OLD | NEW |
| (Empty) |
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 08ad4e1fecba302bf1247645e84a7d2779956bc3 src/utils/thread.c | |
15 | |
16 #include <assert.h> | |
17 #include <string.h> // for memset() | |
18 #include "./vp9_thread.h" | |
19 #include "vpx_mem/vpx_mem.h" | |
20 | |
21 #if CONFIG_MULTITHREAD | |
22 | |
23 struct VP9WorkerImpl { | |
24 pthread_mutex_t mutex_; | |
25 pthread_cond_t condition_; | |
26 pthread_t thread_; | |
27 }; | |
28 | |
29 //------------------------------------------------------------------------------ | |
30 | |
31 static void execute(VP9Worker *const worker); // Forward declaration. | |
32 | |
33 static THREADFN thread_loop(void *ptr) { | |
34 VP9Worker *const worker = (VP9Worker*)ptr; | |
35 int done = 0; | |
36 while (!done) { | |
37 pthread_mutex_lock(&worker->impl_->mutex_); | |
38 while (worker->status_ == OK) { // wait in idling mode | |
39 pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_); | |
40 } | |
41 if (worker->status_ == WORK) { | |
42 execute(worker); | |
43 worker->status_ = OK; | |
44 } else if (worker->status_ == NOT_OK) { // finish the worker | |
45 done = 1; | |
46 } | |
47 // signal to the main thread that we're done (for sync()) | |
48 pthread_cond_signal(&worker->impl_->condition_); | |
49 pthread_mutex_unlock(&worker->impl_->mutex_); | |
50 } | |
51 return THREAD_RETURN(NULL); // Thread is finished | |
52 } | |
53 | |
54 // main thread state control | |
55 static void change_state(VP9Worker *const worker, | |
56 VP9WorkerStatus new_status) { | |
57 // No-op when attempting to change state on a thread that didn't come up. | |
58 // Checking status_ without acquiring the lock first would result in a data | |
59 // race. | |
60 if (worker->impl_ == NULL) return; | |
61 | |
62 pthread_mutex_lock(&worker->impl_->mutex_); | |
63 if (worker->status_ >= OK) { | |
64 // wait for the worker to finish | |
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 } | |
73 } | |
74 pthread_mutex_unlock(&worker->impl_->mutex_); | |
75 } | |
76 | |
77 #endif // CONFIG_MULTITHREAD | |
78 | |
79 //------------------------------------------------------------------------------ | |
80 | |
81 static void init(VP9Worker *const worker) { | |
82 memset(worker, 0, sizeof(*worker)); | |
83 worker->status_ = NOT_OK; | |
84 } | |
85 | |
86 static int sync(VP9Worker *const worker) { | |
87 #if CONFIG_MULTITHREAD | |
88 change_state(worker, OK); | |
89 #endif | |
90 assert(worker->status_ <= OK); | |
91 return !worker->had_error; | |
92 } | |
93 | |
94 static int reset(VP9Worker *const worker) { | |
95 int ok = 1; | |
96 worker->had_error = 0; | |
97 if (worker->status_ < OK) { | |
98 #if CONFIG_MULTITHREAD | |
99 worker->impl_ = (VP9WorkerImpl*)vpx_calloc(1, sizeof(*worker->impl_)); | |
100 if (worker->impl_ == NULL) { | |
101 return 0; | |
102 } | |
103 if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) { | |
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); | |
112 if (ok) worker->status_ = OK; | |
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 } | |
122 #else | |
123 worker->status_ = OK; | |
124 #endif | |
125 } else if (worker->status_ > OK) { | |
126 ok = sync(worker); | |
127 } | |
128 assert(!ok || (worker->status_ == OK)); | |
129 return ok; | |
130 } | |
131 | |
132 static void execute(VP9Worker *const worker) { | |
133 if (worker->hook != NULL) { | |
134 worker->had_error |= !worker->hook(worker->data1, worker->data2); | |
135 } | |
136 } | |
137 | |
138 static void launch(VP9Worker *const worker) { | |
139 #if CONFIG_MULTITHREAD | |
140 change_state(worker, WORK); | |
141 #else | |
142 execute(worker); | |
143 #endif | |
144 } | |
145 | |
146 static void end(VP9Worker *const worker) { | |
147 if (worker->status_ >= OK) { | |
148 #if CONFIG_MULTITHREAD | |
149 change_state(worker, NOT_OK); | |
150 pthread_join(worker->impl_->thread_, NULL); | |
151 pthread_mutex_destroy(&worker->impl_->mutex_); | |
152 pthread_cond_destroy(&worker->impl_->condition_); | |
153 #else | |
154 worker->status_ = NOT_OK; | |
155 #endif | |
156 } | |
157 vpx_free(worker->impl_); | |
158 worker->impl_ = NULL; | |
159 assert(worker->status_ == NOT_OK); | |
160 } | |
161 | |
162 //------------------------------------------------------------------------------ | |
163 | |
164 static VP9WorkerInterface g_worker_interface = { | |
165 init, reset, sync, launch, execute, end | |
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 |