- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / libvpx / vp9 / decoder / vp9_thread.c
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 eff8f2a8c20095aade3c292b0e9292dac6cb3587  src/utils/thread.c
15
16
17 #include <assert.h>
18 #include <string.h>   // for memset()
19 #include "./vp9_thread.h"
20
21 #if defined(__cplusplus) || defined(c_plusplus)
22 extern "C" {
23 #endif
24
25 #if CONFIG_MULTITHREAD
26
27 #if defined(_WIN32)
28
29 //------------------------------------------------------------------------------
30 // simplistic pthread emulation layer
31
32 #include <process.h>  // NOLINT
33
34 // _beginthreadex requires __stdcall
35 #define THREADFN unsigned int __stdcall
36 #define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
37
38 static int pthread_create(pthread_t* const thread, const void* attr,
39                           unsigned int (__stdcall *start)(void*), void* arg) {
40   (void)attr;
41   *thread = (pthread_t)_beginthreadex(NULL,   /* void *security */
42                                       0,      /* unsigned stack_size */
43                                       start,
44                                       arg,
45                                       0,      /* unsigned initflag */
46                                       NULL);  /* unsigned *thrdaddr */
47   if (*thread == NULL) return 1;
48   SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
49   return 0;
50 }
51
52 static int pthread_join(pthread_t thread, void** value_ptr) {
53   (void)value_ptr;
54   return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
55           CloseHandle(thread) == 0);
56 }
57
58 // Mutex
59 static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) {
60   (void)mutexattr;
61   InitializeCriticalSection(mutex);
62   return 0;
63 }
64
65 static int pthread_mutex_lock(pthread_mutex_t* const mutex) {
66   EnterCriticalSection(mutex);
67   return 0;
68 }
69
70 static int pthread_mutex_unlock(pthread_mutex_t* const mutex) {
71   LeaveCriticalSection(mutex);
72   return 0;
73 }
74
75 static int pthread_mutex_destroy(pthread_mutex_t* const mutex) {
76   DeleteCriticalSection(mutex);
77   return 0;
78 }
79
80 // Condition
81 static int pthread_cond_destroy(pthread_cond_t* const condition) {
82   int ok = 1;
83   ok &= (CloseHandle(condition->waiting_sem_) != 0);
84   ok &= (CloseHandle(condition->received_sem_) != 0);
85   ok &= (CloseHandle(condition->signal_event_) != 0);
86   return !ok;
87 }
88
89 static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
90   (void)cond_attr;
91   condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
92   condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
93   condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
94   if (condition->waiting_sem_ == NULL ||
95       condition->received_sem_ == NULL ||
96       condition->signal_event_ == NULL) {
97     pthread_cond_destroy(condition);
98     return 1;
99   }
100   return 0;
101 }
102
103 static int pthread_cond_signal(pthread_cond_t* const condition) {
104   int ok = 1;
105   if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
106     // a thread is waiting in pthread_cond_wait: allow it to be notified
107     ok = SetEvent(condition->signal_event_);
108     // wait until the event is consumed so the signaler cannot consume
109     // the event via its own pthread_cond_wait.
110     ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
111            WAIT_OBJECT_0);
112   }
113   return !ok;
114 }
115
116 static int pthread_cond_wait(pthread_cond_t* const condition,
117                              pthread_mutex_t* const mutex) {
118   int ok;
119   // note that there is a consumer available so the signal isn't dropped in
120   // pthread_cond_signal
121   if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
122     return 1;
123   // now unlock the mutex so pthread_cond_signal may be issued
124   pthread_mutex_unlock(mutex);
125   ok = (WaitForSingleObject(condition->signal_event_, INFINITE) ==
126         WAIT_OBJECT_0);
127   ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
128   pthread_mutex_lock(mutex);
129   return !ok;
130 }
131
132 #else  // _WIN32
133 # define THREADFN void*
134 # define THREAD_RETURN(val) val
135 #endif
136
137 //------------------------------------------------------------------------------
138
139 static THREADFN thread_loop(void *ptr) {    // thread loop
140   VP9Worker* const worker = (VP9Worker*)ptr;
141   int done = 0;
142   while (!done) {
143     pthread_mutex_lock(&worker->mutex_);
144     while (worker->status_ == OK) {   // wait in idling mode
145       pthread_cond_wait(&worker->condition_, &worker->mutex_);
146     }
147     if (worker->status_ == WORK) {
148       vp9_worker_execute(worker);
149       worker->status_ = OK;
150     } else if (worker->status_ == NOT_OK) {   // finish the worker
151       done = 1;
152     }
153     // signal to the main thread that we're done (for Sync())
154     pthread_cond_signal(&worker->condition_);
155     pthread_mutex_unlock(&worker->mutex_);
156   }
157   return THREAD_RETURN(NULL);    // Thread is finished
158 }
159
160 // main thread state control
161 static void change_state(VP9Worker* const worker,
162                          VP9WorkerStatus new_status) {
163   // no-op when attempting to change state on a thread that didn't come up
164   if (worker->status_ < OK) return;
165
166   pthread_mutex_lock(&worker->mutex_);
167   // wait for the worker to finish
168   while (worker->status_ != OK) {
169     pthread_cond_wait(&worker->condition_, &worker->mutex_);
170   }
171   // assign new status and release the working thread if needed
172   if (new_status != OK) {
173     worker->status_ = new_status;
174     pthread_cond_signal(&worker->condition_);
175   }
176   pthread_mutex_unlock(&worker->mutex_);
177 }
178
179 #endif  // CONFIG_MULTITHREAD
180
181 //------------------------------------------------------------------------------
182
183 void vp9_worker_init(VP9Worker* const worker) {
184   memset(worker, 0, sizeof(*worker));
185   worker->status_ = NOT_OK;
186 }
187
188 int vp9_worker_sync(VP9Worker* const worker) {
189 #if CONFIG_MULTITHREAD
190   change_state(worker, OK);
191 #endif
192   assert(worker->status_ <= OK);
193   return !worker->had_error;
194 }
195
196 int vp9_worker_reset(VP9Worker* const worker) {
197   int ok = 1;
198   worker->had_error = 0;
199   if (worker->status_ < OK) {
200 #if CONFIG_MULTITHREAD
201     if (pthread_mutex_init(&worker->mutex_, NULL) ||
202         pthread_cond_init(&worker->condition_, NULL)) {
203       return 0;
204     }
205     pthread_mutex_lock(&worker->mutex_);
206     ok = !pthread_create(&worker->thread_, NULL, thread_loop, worker);
207     if (ok) worker->status_ = OK;
208     pthread_mutex_unlock(&worker->mutex_);
209 #else
210     worker->status_ = OK;
211 #endif
212   } else if (worker->status_ > OK) {
213     ok = vp9_worker_sync(worker);
214   }
215   assert(!ok || (worker->status_ == OK));
216   return ok;
217 }
218
219 void vp9_worker_execute(VP9Worker* const worker) {
220   if (worker->hook != NULL) {
221     worker->had_error |= !worker->hook(worker->data1, worker->data2);
222   }
223 }
224
225 void vp9_worker_launch(VP9Worker* const worker) {
226 #if CONFIG_MULTITHREAD
227   change_state(worker, WORK);
228 #else
229   vp9_worker_execute(worker);
230 #endif
231 }
232
233 void vp9_worker_end(VP9Worker* const worker) {
234   if (worker->status_ >= OK) {
235 #if CONFIG_MULTITHREAD
236     change_state(worker, NOT_OK);
237     pthread_join(worker->thread_, NULL);
238     pthread_mutex_destroy(&worker->mutex_);
239     pthread_cond_destroy(&worker->condition_);
240 #else
241     worker->status_ = NOT_OK;
242 #endif
243   }
244   assert(worker->status_ == NOT_OK);
245 }
246
247 //------------------------------------------------------------------------------
248
249 #if defined(__cplusplus) || defined(c_plusplus)
250 }    // extern "C"
251 #endif