| /* |
| * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 2 Clause License and |
| * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| * was not distributed with this source code in the LICENSE file, you can |
| * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| * Media Patent License 1.0 was not distributed with this source code in the |
| * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
| */ |
| |
| #ifndef AOM_AOM_PORTS_AOM_ONCE_H_ |
| #define AOM_AOM_PORTS_AOM_ONCE_H_ |
| |
| #include "config/aom_config.h" |
| |
| /* Implement a function wrapper to guarantee initialization |
| * thread-safety for library singletons. |
| * |
| * NOTE: This function uses static locks, and can only be |
| * used with one common argument per compilation unit. So |
| * |
| * file1.c: |
| * aom_once(foo); |
| * ... |
| * aom_once(foo); |
| * |
| * file2.c: |
| * aom_once(bar); |
| * |
| * will ensure foo() and bar() are each called only once, but in |
| * |
| * file1.c: |
| * aom_once(foo); |
| * aom_once(bar): |
| * |
| * bar() will never be called because the lock is used up |
| * by the call to foo(). |
| */ |
| |
| #if CONFIG_MULTITHREAD && defined(_WIN32) |
| #include <windows.h> |
| /* Declare a per-compilation-unit state variable to track the progress |
| * of calling func() only once. This must be at global scope because |
| * local initializers are not thread-safe in MSVC prior to Visual |
| * Studio 2015. |
| */ |
| static INIT_ONCE aom_init_once = INIT_ONCE_STATIC_INIT; |
| |
| static void aom_once(void (*func)(void)) { |
| BOOL pending; |
| InitOnceBeginInitialize(&aom_init_once, 0, &pending, NULL); |
| if (!pending) { |
| // Initialization has already completed. |
| return; |
| } |
| func(); |
| InitOnceComplete(&aom_init_once, 0, NULL); |
| } |
| |
| #elif CONFIG_MULTITHREAD && defined(__OS2__) |
| #define INCL_DOS |
| #include <os2.h> |
| static void aom_once(void (*func)(void)) { |
| static volatile int done; |
| |
| /* If the initialization is complete, return early. */ |
| if (done) return; |
| |
| /* Causes all other threads in the process to block themselves |
| * and give up their time slice. |
| */ |
| DosEnterCritSec(); |
| |
| if (!done) { |
| func(); |
| done = 1; |
| } |
| |
| /* Restores normal thread dispatching for the current process. */ |
| DosExitCritSec(); |
| } |
| |
| #elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H |
| #include <pthread.h> |
| static void aom_once(void (*func)(void)) { |
| static pthread_once_t lock = PTHREAD_ONCE_INIT; |
| pthread_once(&lock, func); |
| } |
| |
| #else |
| /* Default version that performs no synchronization. */ |
| |
| static void aom_once(void (*func)(void)) { |
| static volatile int done; |
| |
| if (!done) { |
| func(); |
| done = 1; |
| } |
| } |
| #endif |
| |
| #endif // AOM_AOM_PORTS_AOM_ONCE_H_ |