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 && HAVE_PTHREAD_H 77 #include <pthread.h> once(void (* func)(void))78static void once(void (*func)(void)) 79 { 80 static pthread_once_t lock = PTHREAD_ONCE_INIT; 81 pthread_once(&lock, func); 82 } 83 84 85 #else 86 /* No-op version that performs no synchronization. vp8_rtcd() is idempotent, 87 * so as long as your platform provides atomic loads/stores of pointers 88 * no synchronization is strictly necessary. 89 */ 90 once(void (* func)(void))91static void once(void (*func)(void)) 92 { 93 static int done; 94 95 if(!done) 96 { 97 func(); 98 done = 1; 99 } 100 } 101 #endif 102 103 #endif // VPX_PORTS_VPX_ONCE_H_ 104