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