1 /* 2 * Copyright (c) 2011 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef VPX_PORTS_VPX_ONCE_H_ 12 #define VPX_PORTS_VPX_ONCE_H_ 13 14 #include "vpx_config.h" 15 16 #if CONFIG_MULTITHREAD && defined(_WIN32) 17 #include <windows.h> 18 #include <stdlib.h> once(void (* func)(void))19static void once(void (*func)(void)) 20 { 21 static CRITICAL_SECTION *lock; 22 static LONG waiters; 23 static int done; 24 void *lock_ptr = &lock; 25 26 /* If the initialization is complete, return early. This isn't just an 27 * optimization, it prevents races on the destruction of the global 28 * lock. 29 */ 30 if(done) 31 return; 32 33 InterlockedIncrement(&waiters); 34 35 /* Get a lock. We create one and try to make it the one-true-lock, 36 * throwing it away if we lost the race. 37 */ 38 39 { 40 /* Scope to protect access to new_lock */ 41 CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION)); 42 InitializeCriticalSection(new_lock); 43 if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL) 44 { 45 DeleteCriticalSection(new_lock); 46 free(new_lock); 47 } 48 } 49 50 /* At this point, we have a lock that can be synchronized on. We don't 51 * care which thread actually performed the allocation. 52 */ 53 54 EnterCriticalSection(lock); 55 56 if (!done) 57 { 58 func(); 59 done = 1; 60 } 61 62 LeaveCriticalSection(lock); 63 64 /* Last one out should free resources. The destructed objects are 65 * protected by checking if(done) above. 66 */ 67 if(!InterlockedDecrement(&waiters)) 68 { 69 DeleteCriticalSection(lock); 70 free(lock); 71 lock = NULL; 72 } 73 } 74 75 76 #elif CONFIG_MULTITHREAD && defined(__OS2__) 77 #define INCL_DOS 78 #include <os2.h> once(void (* func)(void))79static void once(void (*func)(void)) 80 { 81 static int done; 82 83 /* If the initialization is complete, return early. */ 84 if(done) 85 return; 86 87 /* Causes all other threads in the process to block themselves 88 * and give up their time slice. 89 */ 90 DosEnterCritSec(); 91 92 if (!done) 93 { 94 func(); 95 done = 1; 96 } 97 98 /* Restores normal thread dispatching for the current process. */ 99 DosExitCritSec(); 100 } 101 102 103 #elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H 104 #include <pthread.h> once(void (* func)(void))105static void once(void (*func)(void)) 106 { 107 static pthread_once_t lock = PTHREAD_ONCE_INIT; 108 pthread_once(&lock, func); 109 } 110 111 112 #else 113 /* No-op version that performs no synchronization. *_rtcd() is idempotent, 114 * so as long as your platform provides atomic loads/stores of pointers 115 * no synchronization is strictly necessary. 116 */ 117 once(void (* func)(void))118static void once(void (*func)(void)) 119 { 120 static int done; 121 122 if(!done) 123 { 124 func(); 125 done = 1; 126 } 127 } 128 #endif 129 130 #endif // VPX_PORTS_VPX_ONCE_H_ 131