vpx_thread.c 5.3 KB

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