/work/svt-av1/Source/Lib/Codec/svt_threads.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright(c) 2019 Intel Corporation |
3 | | * |
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 https://www.aomedia.org/license/software-license. 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 https://www.aomedia.org/license/patent-license. |
10 | | */ |
11 | | |
12 | | // Summary: |
13 | | // EbThreads contains wrappers functions that hide |
14 | | // platform specific objects such as threads, semaphores, |
15 | | // and mutexs. The goal is to eliminiate platform #define |
16 | | // in the code. |
17 | | |
18 | | #include "EbSvtAv1.h" |
19 | | #if defined(__has_feature) |
20 | | #if __has_feature(thread_sanitizer) |
21 | | #define EB_THREAD_SANITIZER_ENABLED 1 |
22 | | #endif |
23 | | #endif |
24 | | |
25 | | #ifndef EB_THREAD_SANITIZER_ENABLED |
26 | 2 | #define EB_THREAD_SANITIZER_ENABLED 0 |
27 | | #endif |
28 | | |
29 | | /**************************************** |
30 | | * Universal Includes |
31 | | ****************************************/ |
32 | | #include <stdbool.h> |
33 | | #include <stdlib.h> |
34 | | #include <string.h> |
35 | | #include "svt_threads.h" |
36 | | #include "svt_log.h" |
37 | | #if SVT_AV1_NVTX |
38 | | #include "svt_nvtx.h" |
39 | | #include <sys/syscall.h> |
40 | | #endif |
41 | | /**************************************** |
42 | | * Win32 Includes |
43 | | ****************************************/ |
44 | | #ifdef _WIN32 |
45 | | #include <windows.h> |
46 | | #else |
47 | | #include <stdio.h> |
48 | | #include <errno.h> |
49 | | #include <fcntl.h> |
50 | | #include <pthread.h> |
51 | | #include <semaphore.h> |
52 | | #include <unistd.h> |
53 | | #endif // _WIN32 |
54 | | #ifdef __APPLE__ |
55 | | #include <dispatch/dispatch.h> |
56 | | #endif |
57 | | #if PRINTF_TIME |
58 | | #include <time.h> |
59 | | #ifdef _WIN32 |
60 | | void printfTime(const char* fmt, ...) { |
61 | | va_list args; |
62 | | va_start(args, fmt); |
63 | | SVT_LOG(" [%i ms]\t", ((int32_t)clock())); |
64 | | vprintf(fmt, args); |
65 | | va_end(args); |
66 | | } |
67 | | #endif |
68 | | #endif |
69 | | |
70 | | #ifndef _WIN32 |
71 | 0 | static void* dummy_func(void* arg) { |
72 | 0 | (void)arg; |
73 | 0 | return NULL; |
74 | 0 | } |
75 | | |
76 | | /* |
77 | | * pthread_setname_np has different signatures across platforms; the trampoline |
78 | | * always invokes this from inside the new thread, so Apple's self-only form is |
79 | | * naturally compatible. |
80 | | */ |
81 | 12.7k | static inline void svt_thread_self_setname(const char* name) { |
82 | | #if defined(__APPLE__) |
83 | | (void)pthread_setname_np(name); |
84 | | #elif defined(__linux__) || defined(__GLIBC__) || defined(__ANDROID__) |
85 | | (void)pthread_setname_np(pthread_self(), name); |
86 | | #else |
87 | | (void)name; |
88 | | #endif |
89 | 12.7k | } |
90 | | |
91 | | /* |
92 | | * Self-naming trampoline. nsys snapshots the thread name early (often before a |
93 | | * spawner-side pthread_setname_np lands), so we let the new thread rename |
94 | | * itself before it enters user_fn. This makes svt-* names visible in Nsight |
95 | | * timelines, /proc/<tid>/comm, and ps/top. |
96 | | */ |
97 | | typedef struct SvtThreadStart { |
98 | | void* (*fn)(void*); |
99 | | void* arg; |
100 | | char name[16]; |
101 | | } SvtThreadStart; |
102 | | |
103 | 12.7k | static void* svt_thread_trampoline(void* p) { |
104 | 12.7k | SvtThreadStart* payload = (SvtThreadStart*)p; |
105 | 12.7k | void* (*fn)(void*) = payload->fn; |
106 | 12.7k | void* arg = payload->arg; |
107 | 12.7k | char name[16]; |
108 | 12.7k | strncpy(name, payload->name, sizeof(name) - 1); |
109 | 12.7k | name[sizeof(name) - 1] = '\0'; |
110 | 12.7k | free(payload); |
111 | | |
112 | 12.7k | if (name[0]) { |
113 | 12.7k | svt_thread_self_setname(name); |
114 | | #if SVT_AV1_NVTX |
115 | | // syscall(SYS_gettid) instead of gettid(): gettid() needs glibc 2.30+ |
116 | | // (Aug 2019); the raw syscall works on older glibc and musl too. |
117 | | SVT_NVTX_NAME_OS_THREAD((unsigned long)syscall(SYS_gettid), name); |
118 | | #endif |
119 | 12.7k | } |
120 | | |
121 | 12.7k | return fn(arg); |
122 | 12.7k | } |
123 | | |
124 | | // These can stay with pthread_once_t since this is specific to pthreads implementation |
125 | | static pthread_once_t checked_once = PTHREAD_ONCE_INIT; |
126 | | static bool can_use_prio = false; |
127 | | |
128 | 1 | static void check_set_prio(void) { |
129 | | /* We can only use realtime priority if we are running as root, so |
130 | | * check if geteuid() == 0 (meaning either root or sudo). |
131 | | * If we don't do this check, we will eventually run into memory |
132 | | * issues if the encoder is uninitialized and re-initialized multiple |
133 | | * times in one executable due to a bug in glibc. |
134 | | * https://sourceware.org/bugzilla/show_bug.cgi?id=19511 |
135 | | * |
136 | | * We still need to exclude the case of thread sanitizer because we |
137 | | * run the test as root inside the container and trying to change |
138 | | * the thread priority will __always__ fail the thread sanitizer. |
139 | | * https://github.com/google/sanitizers/issues/1088 |
140 | | */ |
141 | 1 | if (EB_THREAD_SANITIZER_ENABLED || geteuid() != 0) { |
142 | 0 | return; |
143 | 0 | } |
144 | 1 | pthread_attr_t attr; |
145 | 1 | int ret; |
146 | 1 | if ((ret = pthread_attr_init(&attr))) { |
147 | 0 | SVT_WARN("Failed to initialize thread attributes: %s\n", strerror(ret)); |
148 | 0 | return; |
149 | 0 | } |
150 | 1 | struct sched_param param; |
151 | 1 | if ((ret = pthread_attr_getschedparam(&attr, ¶m))) { |
152 | 0 | SVT_WARN("Failed to get thread priority: %s\n", strerror(ret)); |
153 | 0 | goto end; |
154 | 0 | } |
155 | 1 | param.sched_priority = 99; |
156 | 1 | if ((ret = pthread_attr_setschedparam(&attr, ¶m))) { |
157 | 1 | SVT_WARN("Failed to set thread priority: %s\n", strerror(ret)); |
158 | 1 | goto end; |
159 | 1 | } |
160 | 0 | pthread_t th; |
161 | 0 | if ((ret = pthread_create(&th, &attr, dummy_func, NULL))) { |
162 | 0 | SVT_WARN("Failed to create thread: %s\n", strerror(ret)); |
163 | 0 | goto end; |
164 | 0 | } |
165 | 0 | can_use_prio = true; |
166 | 0 | pthread_join(th, NULL); |
167 | 1 | end: |
168 | 1 | if ((ret = pthread_attr_destroy(&attr))) { |
169 | 0 | SVT_WARN("Failed to destroy thread attributes: %s\n", strerror(ret)); |
170 | 0 | } |
171 | 1 | } |
172 | | #endif |
173 | | |
174 | 9.80k | void svt_format_thread_name(char* buf, size_t size, const char* prefix, uint32_t index) { |
175 | 9.80k | snprintf(buf, size, "%s%u", prefix, index); |
176 | 9.80k | } |
177 | | |
178 | | /**************************************** |
179 | | * svt_create_thread |
180 | | ****************************************/ |
181 | 12.7k | EbHandle svt_create_thread(void* thread_function(void*), void* thread_context, const char* name) { |
182 | 12.7k | EbHandle thread_handle = NULL; |
183 | | |
184 | | // Drop the `svt_aom_` prefix that EB_CREATE_THREAD pulls in via |
185 | | // `#thread_function`. Linux's TASK_COMM_LEN is 15 chars; without the strip |
186 | | // `svt_aom_picture_decision_kernel` and `svt_aom_picture_manager_kernel` |
187 | | // collapse to the same `svt_aom_picture` label in /proc/.../comm and the |
188 | | // Nsight ThreadNames table. |
189 | 12.7k | if (name && !strncmp(name, "svt_aom_", 8)) { |
190 | 2.91k | name += 8; |
191 | 2.91k | } |
192 | | |
193 | | #ifdef _WIN32 |
194 | | thread_handle = (EbHandle)CreateThread( |
195 | | NULL, // default security attributes |
196 | | 0, // default stack size |
197 | | (LPTHREAD_START_ROUTINE)thread_function, // function to be tied to the new thread |
198 | | thread_context, // context to be tied to the new thread |
199 | | 0, // thread active when created |
200 | | NULL); // new thread ID |
201 | | |
202 | | // SetThreadDescription (Windows 10 1607+) — best effort. Older Windows |
203 | | // returns E_NOTIMPL; nothing else we can do here. |
204 | | if (thread_handle && name && *name) { |
205 | | // Mirror Linux's TASK_COMM_LEN (15 + NUL); MultiByteToWideChar fails if |
206 | | // the source doesn't fit, so truncate first. |
207 | | char truncated[16]; |
208 | | wchar_t wname[16]; |
209 | | strncpy_s(truncated, sizeof(truncated), name, sizeof(truncated) - 1); |
210 | | truncated[sizeof(truncated) - 1] = '\0'; |
211 | | if (MultiByteToWideChar(CP_UTF8, 0, truncated, -1, wname, (int)(sizeof(wname) / sizeof(wname[0]))) > 0) { |
212 | | // On Windows Server 2016, Windows 10 LTSB 2016 and Windows 10 |
213 | | // version 1607, SetThreadDescription is only available via Run Time |
214 | | // Dynamic Linking in KernelBase.dll. |
215 | | HMODULE kernel_base_handle = GetModuleHandle("KernelBase.dll"); |
216 | | if (kernel_base_handle != NULL) { |
217 | | typedef HRESULT (*set_thread_description_t)(HANDLE hThread, PCWSTR lpThreadDescription); |
218 | | set_thread_description_t set_thread_description = (set_thread_description_t)GetProcAddress( |
219 | | kernel_base_handle, "SetThreadDescription"); |
220 | | if (set_thread_description != NULL) { |
221 | | set_thread_description((HANDLE)thread_handle, wname); |
222 | | } |
223 | | } |
224 | | } |
225 | | } |
226 | | |
227 | | #else |
228 | 12.7k | if (pthread_once(&checked_once, check_set_prio)) { |
229 | 0 | SVT_ERROR("Failed to run pthread_once to check if we can set priority\n"); |
230 | 0 | return NULL; |
231 | 0 | } |
232 | | |
233 | 12.7k | pthread_attr_t attr; |
234 | 12.7k | if (pthread_attr_init(&attr)) { |
235 | 0 | SVT_ERROR("Failed to initialize thread attributes\n"); |
236 | 0 | return NULL; |
237 | 0 | } |
238 | | |
239 | 12.7k | if (can_use_prio) { |
240 | | // As described in https://docs.oracle.com/cd/E19455-01/806-5257/attrib-16/index.html |
241 | 0 | struct sched_param param; |
242 | 0 | pthread_attr_getschedparam(&attr, ¶m); |
243 | 0 | param.sched_priority = 99; |
244 | 0 | pthread_attr_setschedparam(&attr, ¶m); |
245 | 0 | } |
246 | | |
247 | | // 1 MiB in bytes for now since we can't easily change the stack size after creation |
248 | 12.7k | const size_t min_stack_size = 1024 * 1024; |
249 | | // We don't care if this fails, it's just a hint for the min size we are expecting. |
250 | 12.7k | (void)pthread_attr_setstacksize(&attr, min_stack_size); |
251 | | |
252 | 12.7k | pthread_t* th = malloc(sizeof(*th)); |
253 | 12.7k | if (th == NULL) { |
254 | 0 | SVT_ERROR("Failed to allocate thread handle\n"); |
255 | 0 | pthread_attr_destroy(&attr); |
256 | 0 | return NULL; |
257 | 0 | } |
258 | | |
259 | 12.7k | SvtThreadStart* payload = malloc(sizeof(*payload)); |
260 | 12.7k | if (payload == NULL) { |
261 | 0 | SVT_ERROR("Failed to allocate thread start payload\n"); |
262 | 0 | free(th); |
263 | 0 | pthread_attr_destroy(&attr); |
264 | 0 | return NULL; |
265 | 0 | } |
266 | 12.7k | payload->fn = thread_function; |
267 | 12.7k | payload->arg = thread_context; |
268 | 12.7k | if (name && *name) { |
269 | 12.7k | strncpy(payload->name, name, sizeof(payload->name) - 1); |
270 | 12.7k | payload->name[sizeof(payload->name) - 1] = '\0'; |
271 | 12.7k | } else { |
272 | 0 | payload->name[0] = '\0'; |
273 | 0 | } |
274 | | |
275 | 12.7k | int ret; |
276 | 12.7k | if ((ret = pthread_create(th, &attr, svt_thread_trampoline, payload))) { |
277 | 0 | SVT_ERROR("Failed to create thread: %s\n", strerror(ret)); |
278 | 0 | free(payload); |
279 | 0 | free(th); |
280 | 0 | pthread_attr_destroy(&attr); |
281 | 0 | return NULL; |
282 | 0 | } |
283 | | |
284 | 12.7k | pthread_attr_destroy(&attr); |
285 | | |
286 | 12.7k | thread_handle = th; |
287 | 12.7k | #endif // _WIN32 |
288 | | |
289 | 12.7k | return thread_handle; |
290 | 12.7k | } |
291 | | |
292 | | /**************************************** |
293 | | * svt_destroy_thread |
294 | | ****************************************/ |
295 | 12.7k | EbErrorType svt_destroy_thread(EbHandle thread_handle) { |
296 | 12.7k | EbErrorType error_return; |
297 | | |
298 | | #ifdef _WIN32 |
299 | | WaitForSingleObject(thread_handle, INFINITE); |
300 | | error_return = CloseHandle(thread_handle) ? EB_ErrorNone : EB_ErrorDestroyThreadFailed; |
301 | | #else |
302 | 12.7k | error_return = pthread_join(*((pthread_t*)thread_handle), NULL) ? EB_ErrorDestroyThreadFailed : EB_ErrorNone; |
303 | 12.7k | free(thread_handle); |
304 | 12.7k | #endif // _WIN32 |
305 | | |
306 | 12.7k | return error_return; |
307 | 12.7k | } |
308 | | |
309 | | /*************************************** |
310 | | * svt_create_semaphore |
311 | | ***************************************/ |
312 | 53.7k | EbHandle svt_create_semaphore(uint32_t initial_count, uint32_t max_count) { |
313 | 53.7k | EbHandle semaphore_handle; |
314 | | |
315 | | #if defined(_WIN32) |
316 | | semaphore_handle = (EbHandle)CreateSemaphore(NULL, // default security attributes |
317 | | initial_count, // initial semaphore count |
318 | | max_count, // maximum semaphore count |
319 | | NULL); // semaphore is not named |
320 | | #elif defined(__APPLE__) |
321 | | UNUSED(max_count); |
322 | | semaphore_handle = (EbHandle)dispatch_semaphore_create(initial_count); |
323 | | #else |
324 | 53.7k | UNUSED(max_count); |
325 | | |
326 | 53.7k | semaphore_handle = (sem_t*)malloc(sizeof(sem_t)); |
327 | 53.7k | if (semaphore_handle != NULL) { |
328 | 53.7k | sem_init((sem_t*)semaphore_handle, // semaphore handle |
329 | 53.7k | 0, // shared semaphore (not local) |
330 | 53.7k | initial_count); // initial count |
331 | 53.7k | } |
332 | 53.7k | #endif |
333 | | |
334 | 53.7k | return semaphore_handle; |
335 | 53.7k | } |
336 | | |
337 | | /*************************************** |
338 | | * svt_post_semaphore |
339 | | ***************************************/ |
340 | 49.0k | EbErrorType svt_post_semaphore(EbHandle semaphore_handle) { |
341 | 49.0k | EbErrorType return_error; |
342 | | |
343 | | #ifdef _WIN32 |
344 | | return_error = !ReleaseSemaphore(semaphore_handle, // semaphore handle |
345 | | 1, // amount to increment the semaphore |
346 | | NULL) // pointer to previous count (optional) |
347 | | ? EB_ErrorSemaphoreUnresponsive |
348 | | : EB_ErrorNone; |
349 | | #elif defined(__APPLE__) |
350 | | dispatch_semaphore_signal((dispatch_semaphore_t)semaphore_handle); |
351 | | return_error = EB_ErrorNone; |
352 | | #else |
353 | 49.0k | return_error = sem_post((sem_t*)semaphore_handle) ? EB_ErrorSemaphoreUnresponsive : EB_ErrorNone; |
354 | 49.0k | #endif |
355 | | |
356 | 49.0k | return return_error; |
357 | 49.0k | } |
358 | | |
359 | | /*************************************** |
360 | | * svt_block_on_semaphore |
361 | | ***************************************/ |
362 | 49.0k | EbErrorType svt_block_on_semaphore(EbHandle semaphore_handle) { |
363 | 49.0k | EbErrorType return_error; |
364 | | |
365 | | #ifdef _WIN32 |
366 | | return_error = WaitForSingleObject((HANDLE)semaphore_handle, INFINITE) ? EB_ErrorSemaphoreUnresponsive |
367 | | : EB_ErrorNone; |
368 | | #elif defined(__APPLE__) |
369 | | return_error = dispatch_semaphore_wait((dispatch_semaphore_t)semaphore_handle, DISPATCH_TIME_FOREVER) |
370 | | ? EB_ErrorSemaphoreUnresponsive |
371 | | : EB_ErrorNone; |
372 | | #else |
373 | 49.0k | int ret; |
374 | 49.0k | do { |
375 | 49.0k | ret = sem_wait((sem_t*)semaphore_handle); |
376 | 49.0k | } while (ret == -1 && errno == EINTR); |
377 | 49.0k | return_error = ret ? EB_ErrorSemaphoreUnresponsive : EB_ErrorNone; |
378 | 49.0k | #endif |
379 | | |
380 | 49.0k | return return_error; |
381 | 49.0k | } |
382 | | |
383 | | /*************************************** |
384 | | * svt_destroy_semaphore |
385 | | ***************************************/ |
386 | 53.7k | EbErrorType svt_destroy_semaphore(EbHandle semaphore_handle) { |
387 | 53.7k | EbErrorType return_error; |
388 | | |
389 | | #ifdef _WIN32 |
390 | | return_error = !CloseHandle((HANDLE)semaphore_handle) ? EB_ErrorDestroySemaphoreFailed : EB_ErrorNone; |
391 | | #elif defined(__APPLE__) |
392 | | dispatch_release((dispatch_semaphore_t)semaphore_handle); |
393 | | return_error = EB_ErrorNone; |
394 | | #else |
395 | 53.7k | return_error = sem_destroy((sem_t*)semaphore_handle) ? EB_ErrorDestroySemaphoreFailed : EB_ErrorNone; |
396 | 53.7k | free(semaphore_handle); |
397 | 53.7k | #endif |
398 | | |
399 | 53.7k | return return_error; |
400 | 53.7k | } |
401 | | |
402 | | /*************************************** |
403 | | * svt_create_mutex |
404 | | ***************************************/ |
405 | 116k | EbHandle svt_create_mutex(void) { |
406 | 116k | EbHandle mutex_handle; |
407 | | |
408 | | #ifdef _WIN32 |
409 | | mutex_handle = (EbHandle)CreateMutex(NULL, // default security attributes |
410 | | false, // false := not initially owned |
411 | | NULL); // mutex is not named |
412 | | |
413 | | #else |
414 | | |
415 | 116k | mutex_handle = (EbHandle)malloc(sizeof(pthread_mutex_t)); |
416 | | |
417 | 116k | if (mutex_handle != NULL) { |
418 | 116k | pthread_mutex_init((pthread_mutex_t*)mutex_handle, |
419 | 116k | NULL); // default attributes |
420 | 116k | } |
421 | 116k | #endif |
422 | | |
423 | 116k | return mutex_handle; |
424 | 116k | } |
425 | | |
426 | | /*************************************** |
427 | | * svt_release_mutex |
428 | | ***************************************/ |
429 | 236k | EbErrorType svt_release_mutex(EbHandle mutex_handle) { |
430 | 236k | EbErrorType return_error; |
431 | | |
432 | | #ifdef _WIN32 |
433 | | return_error = !ReleaseMutex((HANDLE)mutex_handle) ? EB_ErrorMutexUnresponsive : EB_ErrorNone; |
434 | | #else |
435 | 236k | return_error = pthread_mutex_unlock((pthread_mutex_t*)mutex_handle) ? EB_ErrorMutexUnresponsive : EB_ErrorNone; |
436 | 236k | #endif |
437 | | |
438 | 236k | return return_error; |
439 | 236k | } |
440 | | |
441 | | /*************************************** |
442 | | * svt_block_on_mutex |
443 | | ***************************************/ |
444 | 236k | EbErrorType svt_block_on_mutex(EbHandle mutex_handle) { |
445 | 236k | EbErrorType return_error; |
446 | | |
447 | | #ifdef _WIN32 |
448 | | return_error = WaitForSingleObject((HANDLE)mutex_handle, INFINITE) ? EB_ErrorMutexUnresponsive : EB_ErrorNone; |
449 | | #else |
450 | 236k | return_error = pthread_mutex_lock((pthread_mutex_t*)mutex_handle) ? EB_ErrorMutexUnresponsive : EB_ErrorNone; |
451 | 236k | #endif |
452 | | |
453 | 236k | return return_error; |
454 | 236k | } |
455 | | |
456 | | /*************************************** |
457 | | * svt_destroy_mutex |
458 | | ***************************************/ |
459 | 116k | EbErrorType svt_destroy_mutex(EbHandle mutex_handle) { |
460 | 116k | EbErrorType return_error; |
461 | | |
462 | | #ifdef _WIN32 |
463 | | return_error = CloseHandle((HANDLE)mutex_handle) ? EB_ErrorDestroyMutexFailed : EB_ErrorNone; |
464 | | #else |
465 | 116k | return_error = pthread_mutex_destroy((pthread_mutex_t*)mutex_handle) ? EB_ErrorDestroyMutexFailed : EB_ErrorNone; |
466 | 116k | free(mutex_handle); |
467 | 116k | #endif |
468 | | |
469 | 116k | return return_error; |
470 | 116k | } |
471 | | |
472 | | /* |
473 | | set an atomic variable to an input value |
474 | | */ |
475 | 970 | void svt_aom_atomic_set_u32(AtomicVarU32* var, uint32_t in) { |
476 | 970 | svt_block_on_mutex(var->mutex); |
477 | 970 | var->obj = in; |
478 | 970 | svt_release_mutex(var->mutex); |
479 | 970 | } |
480 | | |
481 | | /* |
482 | | create condition variable |
483 | | |
484 | | Condition variables are synchronization primitives that enable |
485 | | threads to wait until a particular condition occurs. |
486 | | Condition variables enable threads to atomically release |
487 | | a lock(mutex) and enter the sleeping state. |
488 | | it could be seen as a combined: wait and release mutex |
489 | | */ |
490 | 970 | EbErrorType svt_create_cond_var(CondVar* cond_var) { |
491 | 970 | EbErrorType return_error; |
492 | 970 | cond_var->val = 0; |
493 | | #ifdef _WIN32 |
494 | | InitializeCriticalSection(&cond_var->cs); |
495 | | InitializeConditionVariable(&cond_var->cv); |
496 | | return_error = EB_ErrorNone; |
497 | | #else |
498 | 970 | pthread_mutex_init(&cond_var->m_mutex, NULL); |
499 | 970 | return_error = pthread_cond_init(&cond_var->m_cond, NULL); |
500 | | |
501 | 970 | #endif |
502 | 970 | return return_error; |
503 | 970 | } |
504 | | |
505 | | /* |
506 | | set a condition variable to the new value |
507 | | */ |
508 | 0 | EbErrorType svt_set_cond_var(CondVar* cond_var, int32_t newval) { |
509 | 0 | EbErrorType return_error; |
510 | | #ifdef _WIN32 |
511 | | EnterCriticalSection(&cond_var->cs); |
512 | | cond_var->val = newval; |
513 | | WakeAllConditionVariable(&cond_var->cv); |
514 | | LeaveCriticalSection(&cond_var->cs); |
515 | | return_error = EB_ErrorNone; |
516 | | #else |
517 | 0 | return_error = pthread_mutex_lock(&cond_var->m_mutex); |
518 | 0 | cond_var->val = newval; |
519 | 0 | return_error |= pthread_cond_broadcast(&cond_var->m_cond); |
520 | 0 | return_error |= pthread_mutex_unlock(&cond_var->m_mutex); |
521 | 0 | #endif |
522 | 0 | return return_error; |
523 | 0 | } |
524 | | |
525 | | /* |
526 | | wait until the cond variable changes to a value |
527 | | different than input |
528 | | */ |
529 | | |
530 | 0 | EbErrorType svt_wait_cond_var(CondVar* cond_var, int32_t input) { |
531 | | #ifdef _WIN32 |
532 | | |
533 | | EnterCriticalSection(&cond_var->cs); |
534 | | while (cond_var->val == input) { |
535 | | SleepConditionVariableCS(&cond_var->cv, &cond_var->cs, INFINITE); |
536 | | } |
537 | | LeaveCriticalSection(&cond_var->cs); |
538 | | #else |
539 | 0 | if (pthread_mutex_lock(&cond_var->m_mutex)) { |
540 | 0 | return EB_ErrorMutexUnresponsive; |
541 | 0 | } |
542 | 0 | while (cond_var->val == input) { |
543 | 0 | if (pthread_cond_wait(&cond_var->m_cond, &cond_var->m_mutex)) { |
544 | 0 | (void)pthread_mutex_unlock(&cond_var->m_mutex); |
545 | 0 | return EB_ErrorMutexUnresponsive; |
546 | 0 | } |
547 | 0 | } |
548 | 0 | if (pthread_mutex_unlock(&cond_var->m_mutex)) { |
549 | 0 | return EB_ErrorMutexUnresponsive; |
550 | 0 | } |
551 | 0 | #endif |
552 | 0 | return EB_ErrorNone; |
553 | 0 | } |
554 | | |
555 | 13.0k | void svt_run_once(OnceType* once_control, OnceFn init_routine) { |
556 | | #ifdef _WIN32 |
557 | | InitOnceExecuteOnce(once_control, init_routine, NULL, NULL); |
558 | | #else |
559 | 13.0k | pthread_once(once_control, init_routine); |
560 | 13.0k | #endif |
561 | 13.0k | } |