2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
12 // Multi-threaded worker
15 // https://chromium.googlesource.com/webm/libwebp
17 // Enable GNU extensions in glibc so that we can call pthread_setname_np().
18 // This must be before any #include statements.
24 #include <string.h> // for memset()
26 #include "aom_mem/aom_mem.h"
27 #include "aom_util/aom_thread.h"
29 #if CONFIG_MULTITHREAD
31 struct AVxWorkerImpl
{
32 pthread_mutex_t mutex_
;
33 pthread_cond_t condition_
;
37 //------------------------------------------------------------------------------
39 static void execute(AVxWorker
*const worker
); // Forward declaration.
41 static THREADFN
thread_loop(void *ptr
) {
42 AVxWorker
*const worker
= (AVxWorker
*)ptr
;
44 if (worker
->thread_name
!= NULL
) {
45 // Apple's version of pthread_setname_np takes one argument and operates on
46 // the current thread only. The maximum size of the thread_name buffer was
47 // noted in the Chromium source code and was confirmed by experiments. If
48 // thread_name is too long, pthread_setname_np returns -1 with errno
51 strncpy(thread_name
, worker
->thread_name
, sizeof(thread_name
) - 1);
52 thread_name
[sizeof(thread_name
) - 1] = '\0';
53 pthread_setname_np(thread_name
);
55 #elif defined(__GLIBC__) || defined(__BIONIC__)
56 if (worker
->thread_name
!= NULL
) {
57 // Linux and Android require names (with nul) fit in 16 chars, otherwise
58 // pthread_setname_np() returns ERANGE (34).
60 strncpy(thread_name
, worker
->thread_name
, sizeof(thread_name
) - 1);
61 thread_name
[sizeof(thread_name
) - 1] = '\0';
62 pthread_setname_np(pthread_self(), thread_name
);
67 pthread_mutex_lock(&worker
->impl_
->mutex_
);
68 while (worker
->status_
== OK
) { // wait in idling mode
69 pthread_cond_wait(&worker
->impl_
->condition_
, &worker
->impl_
->mutex_
);
71 if (worker
->status_
== WORK
) {
74 } else if (worker
->status_
== NOT_OK
) { // finish the worker
77 // signal to the main thread that we're done (for sync())
78 pthread_cond_signal(&worker
->impl_
->condition_
);
79 pthread_mutex_unlock(&worker
->impl_
->mutex_
);
81 return THREAD_RETURN(NULL
); // Thread is finished
84 // main thread state control
85 static void change_state(AVxWorker
*const worker
, AVxWorkerStatus new_status
) {
86 // No-op when attempting to change state on a thread that didn't come up.
87 // Checking status_ without acquiring the lock first would result in a data
89 if (worker
->impl_
== NULL
) return;
91 pthread_mutex_lock(&worker
->impl_
->mutex_
);
92 if (worker
->status_
>= OK
) {
93 // wait for the worker to finish
94 while (worker
->status_
!= OK
) {
95 pthread_cond_wait(&worker
->impl_
->condition_
, &worker
->impl_
->mutex_
);
97 // assign new status and release the working thread if needed
98 if (new_status
!= OK
) {
99 worker
->status_
= new_status
;
100 pthread_cond_signal(&worker
->impl_
->condition_
);
103 pthread_mutex_unlock(&worker
->impl_
->mutex_
);
106 #endif // CONFIG_MULTITHREAD
108 //------------------------------------------------------------------------------
110 static void init(AVxWorker
*const worker
) {
111 memset(worker
, 0, sizeof(*worker
));
112 worker
->status_
= NOT_OK
;
115 static int sync(AVxWorker
*const worker
) {
116 #if CONFIG_MULTITHREAD
117 change_state(worker
, OK
);
119 assert(worker
->status_
<= OK
);
120 return !worker
->had_error
;
123 static int reset(AVxWorker
*const worker
) {
125 worker
->had_error
= 0;
126 if (worker
->status_
< OK
) {
127 #if CONFIG_MULTITHREAD
128 worker
->impl_
= (AVxWorkerImpl
*)aom_calloc(1, sizeof(*worker
->impl_
));
129 if (worker
->impl_
== NULL
) {
132 if (pthread_mutex_init(&worker
->impl_
->mutex_
, NULL
)) {
135 if (pthread_cond_init(&worker
->impl_
->condition_
, NULL
)) {
136 pthread_mutex_destroy(&worker
->impl_
->mutex_
);
139 pthread_mutex_lock(&worker
->impl_
->mutex_
);
140 ok
= !pthread_create(&worker
->impl_
->thread_
, NULL
, thread_loop
, worker
);
141 if (ok
) worker
->status_
= OK
;
142 pthread_mutex_unlock(&worker
->impl_
->mutex_
);
144 pthread_mutex_destroy(&worker
->impl_
->mutex_
);
145 pthread_cond_destroy(&worker
->impl_
->condition_
);
147 aom_free(worker
->impl_
);
148 worker
->impl_
= NULL
;
152 worker
->status_
= OK
;
154 } else if (worker
->status_
> OK
) {
157 assert(!ok
|| (worker
->status_
== OK
));
161 static void execute(AVxWorker
*const worker
) {
162 if (worker
->hook
!= NULL
) {
163 worker
->had_error
|= !worker
->hook(worker
->data1
, worker
->data2
);
167 static void launch(AVxWorker
*const worker
) {
168 #if CONFIG_MULTITHREAD
169 change_state(worker
, WORK
);
175 static void end(AVxWorker
*const worker
) {
176 #if CONFIG_MULTITHREAD
177 if (worker
->impl_
!= NULL
) {
178 change_state(worker
, NOT_OK
);
179 pthread_join(worker
->impl_
->thread_
, NULL
);
180 pthread_mutex_destroy(&worker
->impl_
->mutex_
);
181 pthread_cond_destroy(&worker
->impl_
->condition_
);
182 aom_free(worker
->impl_
);
183 worker
->impl_
= NULL
;
186 worker
->status_
= NOT_OK
;
187 assert(worker
->impl_
== NULL
);
189 assert(worker
->status_
== NOT_OK
);
192 //------------------------------------------------------------------------------
194 static AVxWorkerInterface g_worker_interface
= { init
, reset
, sync
,
195 launch
, execute
, end
};
197 int aom_set_worker_interface(const AVxWorkerInterface
*const winterface
) {
198 if (winterface
== NULL
|| winterface
->init
== NULL
||
199 winterface
->reset
== NULL
|| winterface
->sync
== NULL
||
200 winterface
->launch
== NULL
|| winterface
->execute
== NULL
||
201 winterface
->end
== NULL
) {
204 g_worker_interface
= *winterface
;
208 const AVxWorkerInterface
*aom_get_worker_interface(void) {
209 return &g_worker_interface
;
212 //------------------------------------------------------------------------------