1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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 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.
10  */
11 
12 #ifndef AOM_AOM_PORTS_AOM_ONCE_H_
13 #define AOM_AOM_PORTS_AOM_ONCE_H_
14 
15 #include "config/aom_config.h"
16 
17 /* Implement a function wrapper to guarantee initialization
18  * thread-safety for library singletons.
19  *
20  * NOTE: This function uses static locks, and can only be
21  * used with one common argument per compilation unit. So
22  *
23  * file1.c:
24  *   aom_once(foo);
25  *   ...
26  *   aom_once(foo);
27  *
28  * file2.c:
29  *   aom_once(bar);
30  *
31  * will ensure foo() and bar() are each called only once, but in
32  *
33  * file1.c:
34  *   aom_once(foo);
35  *   aom_once(bar):
36  *
37  * bar() will never be called because the lock is used up
38  * by the call to foo().
39  */
40 
41 #if CONFIG_MULTITHREAD && defined(_WIN32)
42 #include <windows.h>
43 /* Declare a per-compilation-unit state variable to track the progress
44  * of calling func() only once. This must be at global scope because
45  * local initializers are not thread-safe in MSVC prior to Visual
46  * Studio 2015.
47  */
48 static INIT_ONCE aom_init_once = INIT_ONCE_STATIC_INIT;
49 
aom_once(void (* func)(void))50 static void aom_once(void (*func)(void)) {
51   BOOL pending;
52   InitOnceBeginInitialize(&aom_init_once, 0, &pending, NULL);
53   if (!pending) {
54     // Initialization has already completed.
55     return;
56   }
57   func();
58   InitOnceComplete(&aom_init_once, 0, NULL);
59 }
60 
61 #elif CONFIG_MULTITHREAD && defined(__OS2__)
62 #define INCL_DOS
63 #include <os2.h>
aom_once(void (* func)(void))64 static void aom_once(void (*func)(void)) {
65   static int done;
66 
67   /* If the initialization is complete, return early. */
68   if (done) return;
69 
70   /* Causes all other threads in the process to block themselves
71    * and give up their time slice.
72    */
73   DosEnterCritSec();
74 
75   if (!done) {
76     func();
77     done = 1;
78   }
79 
80   /* Restores normal thread dispatching for the current process. */
81   DosExitCritSec();
82 }
83 
84 #elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H
85 #include <pthread.h>
aom_once(void (* func)(void))86 static void aom_once(void (*func)(void)) {
87   static pthread_once_t lock = PTHREAD_ONCE_INIT;
88   pthread_once(&lock, func);
89 }
90 
91 #else
92 /* Default version that performs no synchronization. */
93 
aom_once(void (* func)(void))94 static void aom_once(void (*func)(void)) {
95   static int done;
96 
97   if (!done) {
98     func();
99     done = 1;
100   }
101 }
102 #endif
103 
104 #endif  // AOM_AOM_PORTS_AOM_ONCE_H_
105