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 #include "vpx_config.h" 11 #define RTCD_C 12 #include "vpx_rtcd.h" 13 14 #if CONFIG_MULTITHREAD && defined(_WIN32) 15 #include <windows.h> 16 #include <stdlib.h> 17 static void once(void (*func)(void)) 18 { 19 static CRITICAL_SECTION *lock; 20 static LONG waiters; 21 static int done; 22 void *lock_ptr = &lock; 23 24 /* If the initialization is complete, return early. This isn't just an 25 * optimization, it prevents races on the destruction of the global 26 * lock. 27 */ 28 if(done) 29 return; 30 31 InterlockedIncrement(&waiters); 32 33 /* Get a lock. We create one and try to make it the one-true-lock, 34 * throwing it away if we lost the race. 35 */ 36 37 { 38 /* Scope to protect access to new_lock */ 39 CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION)); 40 InitializeCriticalSection(new_lock); 41 if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL) 42 { 43 DeleteCriticalSection(new_lock); 44 free(new_lock); 45 } 46 } 47 48 /* At this point, we have a lock that can be synchronized on. We don't 49 * care which thread actually performed the allocation. 50 */ 51 52 EnterCriticalSection(lock); 53 54 if (!done) 55 { 56 func(); 57 done = 1; 58 } 59 60 LeaveCriticalSection(lock); 61 62 /* Last one out should free resources. The destructed objects are 63 * protected by checking if(done) above. 64 */ 65 if(!InterlockedDecrement(&waiters)) 66 { 67 DeleteCriticalSection(lock); 68 free(lock); 69 lock = NULL; 70 } 71 } 72 73 74 #elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H 75 #include <pthread.h> 76 static void once(void (*func)(void)) 77 { 78 static pthread_once_t lock = PTHREAD_ONCE_INIT; 79 pthread_once(&lock, func); 80 } 81 82 83 #else 84 /* No-op version that performs no synchronization. vpx_rtcd() is idempotent, 85 * so as long as your platform provides atomic loads/stores of pointers 86 * no synchronization is strictly necessary. 87 */ 88 89 static void once(void (*func)(void)) 90 { 91 static int done; 92 93 if(!done) 94 { 95 func(); 96 done = 1; 97 } 98 } 99 #endif 100 101 102 void vpx_rtcd() 103 { 104 once(setup_rtcd_internal); 105 } 106