vpx_thread.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright 2013 Google Inc. All Rights Reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the COPYING file in the root of the source
  5. // tree. An additional intellectual property rights grant can be found
  6. // in the file PATENTS. All contributing project authors may
  7. // be found in the AUTHORS file in the root of the source tree.
  8. // -----------------------------------------------------------------------------
  9. //
  10. // Multi-threaded worker
  11. //
  12. // Original source:
  13. // http://git.chromium.org/webm/libwebp.git
  14. // 100644 blob 264210ba2807e4da47eb5d18c04cf869d89b9784 src/utils/thread.c
  15. #include <assert.h>
  16. #include <string.h> // for memset()
  17. #include "./vpx_thread.h"
  18. #include "vpx_mem/vpx_mem.h"
  19. #if CONFIG_MULTITHREAD
  20. struct VPxWorkerImpl {
  21. pthread_mutex_t mutex_;
  22. pthread_cond_t condition_;
  23. pthread_t thread_;
  24. };
  25. //------------------------------------------------------------------------------
  26. static void execute(VPxWorker *const worker); // Forward declaration.
  27. static THREADFN thread_loop(void *ptr) {
  28. VPxWorker *const worker = (VPxWorker*)ptr;
  29. int done = 0;
  30. while (!done) {
  31. pthread_mutex_lock(&worker->impl_->mutex_);
  32. while (worker->status_ == OK) { // wait in idling mode
  33. pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
  34. }
  35. if (worker->status_ == WORK) {
  36. execute(worker);
  37. worker->status_ = OK;
  38. } else if (worker->status_ == NOT_OK) { // finish the worker
  39. done = 1;
  40. }
  41. // signal to the main thread that we're done (for sync())
  42. pthread_cond_signal(&worker->impl_->condition_);
  43. pthread_mutex_unlock(&worker->impl_->mutex_);
  44. }
  45. return THREAD_RETURN(NULL); // Thread is finished
  46. }
  47. // main thread state control
  48. static void change_state(VPxWorker *const worker,
  49. VPxWorkerStatus new_status) {
  50. // No-op when attempting to change state on a thread that didn't come up.
  51. // Checking status_ without acquiring the lock first would result in a data
  52. // race.
  53. if (worker->impl_ == NULL) return;
  54. pthread_mutex_lock(&worker->impl_->mutex_);
  55. if (worker->status_ >= OK) {
  56. // wait for the worker to finish
  57. while (worker->status_ != OK) {
  58. pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
  59. }
  60. // assign new status and release the working thread if needed
  61. if (new_status != OK) {
  62. worker->status_ = new_status;
  63. pthread_cond_signal(&worker->impl_->condition_);
  64. }
  65. }
  66. pthread_mutex_unlock(&worker->impl_->mutex_);
  67. }
  68. #endif // CONFIG_MULTITHREAD
  69. //------------------------------------------------------------------------------
  70. static void init(VPxWorker *const worker) {
  71. memset(worker, 0, sizeof(*worker));
  72. worker->status_ = NOT_OK;
  73. }
  74. static int sync(VPxWorker *const worker) {
  75. #if CONFIG_MULTITHREAD
  76. change_state(worker, OK);
  77. #endif
  78. assert(worker->status_ <= OK);
  79. return !worker->had_error;
  80. }
  81. static int reset(VPxWorker *const worker) {
  82. int ok = 1;
  83. worker->had_error = 0;
  84. if (worker->status_ < OK) {
  85. #if CONFIG_MULTITHREAD
  86. worker->impl_ = (VPxWorkerImpl*)vpx_calloc(1, sizeof(*worker->impl_));
  87. if (worker->impl_ == NULL) {
  88. return 0;
  89. }
  90. if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) {
  91. goto Error;
  92. }
  93. if (pthread_cond_init(&worker->impl_->condition_, NULL)) {
  94. pthread_mutex_destroy(&worker->impl_->mutex_);
  95. goto Error;
  96. }
  97. pthread_mutex_lock(&worker->impl_->mutex_);
  98. ok = !pthread_create(&worker->impl_->thread_, NULL, thread_loop, worker);
  99. if (ok) worker->status_ = OK;
  100. pthread_mutex_unlock(&worker->impl_->mutex_);
  101. if (!ok) {
  102. pthread_mutex_destroy(&worker->impl_->mutex_);
  103. pthread_cond_destroy(&worker->impl_->condition_);
  104. Error:
  105. vpx_free(worker->impl_);
  106. worker->impl_ = NULL;
  107. return 0;
  108. }
  109. #else
  110. worker->status_ = OK;
  111. #endif
  112. } else if (worker->status_ > OK) {
  113. ok = sync(worker);
  114. }
  115. assert(!ok || (worker->status_ == OK));
  116. return ok;
  117. }
  118. static void execute(VPxWorker *const worker) {
  119. if (worker->hook != NULL) {
  120. worker->had_error |= !worker->hook(worker->data1, worker->data2);
  121. }
  122. }
  123. static void launch(VPxWorker *const worker) {
  124. #if CONFIG_MULTITHREAD
  125. change_state(worker, WORK);
  126. #else
  127. execute(worker);
  128. #endif
  129. }
  130. static void end(VPxWorker *const worker) {
  131. #if CONFIG_MULTITHREAD
  132. if (worker->impl_ != NULL) {
  133. change_state(worker, NOT_OK);
  134. pthread_join(worker->impl_->thread_, NULL);
  135. pthread_mutex_destroy(&worker->impl_->mutex_);
  136. pthread_cond_destroy(&worker->impl_->condition_);
  137. vpx_free(worker->impl_);
  138. worker->impl_ = NULL;
  139. }
  140. #else
  141. worker->status_ = NOT_OK;
  142. assert(worker->impl_ == NULL);
  143. #endif
  144. assert(worker->status_ == NOT_OK);
  145. }
  146. //------------------------------------------------------------------------------
  147. static VPxWorkerInterface g_worker_interface = {
  148. init, reset, sync, launch, execute, end
  149. };
  150. int vpx_set_worker_interface(const VPxWorkerInterface* const winterface) {
  151. if (winterface == NULL ||
  152. winterface->init == NULL || winterface->reset == NULL ||
  153. winterface->sync == NULL || winterface->launch == NULL ||
  154. winterface->execute == NULL || winterface->end == NULL) {
  155. return 0;
  156. }
  157. g_worker_interface = *winterface;
  158. return 1;
  159. }
  160. const VPxWorkerInterface *vpx_get_worker_interface(void) {
  161. return &g_worker_interface;
  162. }
  163. //------------------------------------------------------------------------------