| /* | 
 |  *  Copyright (c) 2011 The WebM project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #ifndef VPX_PORTS_VPX_ONCE_H_ | 
 | #define VPX_PORTS_VPX_ONCE_H_ | 
 |  | 
 | #include "vpx_config.h" | 
 |  | 
 | #if CONFIG_MULTITHREAD && defined(_WIN32) | 
 | #include <windows.h> | 
 | #include <stdlib.h> | 
 | static void once(void (*func)(void)) | 
 | { | 
 |     static CRITICAL_SECTION *lock; | 
 |     static LONG waiters; | 
 |     static int done; | 
 |     void *lock_ptr = &lock; | 
 |  | 
 |     /* If the initialization is complete, return early. This isn't just an | 
 |      * optimization, it prevents races on the destruction of the global | 
 |      * lock. | 
 |      */ | 
 |     if(done) | 
 |         return; | 
 |  | 
 |     InterlockedIncrement(&waiters); | 
 |  | 
 |     /* Get a lock. We create one and try to make it the one-true-lock, | 
 |      * throwing it away if we lost the race. | 
 |      */ | 
 |  | 
 |     { | 
 |         /* Scope to protect access to new_lock */ | 
 |         CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION)); | 
 |         InitializeCriticalSection(new_lock); | 
 |         if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL) | 
 |         { | 
 |             DeleteCriticalSection(new_lock); | 
 |             free(new_lock); | 
 |         } | 
 |     } | 
 |  | 
 |     /* At this point, we have a lock that can be synchronized on. We don't | 
 |      * care which thread actually performed the allocation. | 
 |      */ | 
 |  | 
 |     EnterCriticalSection(lock); | 
 |  | 
 |     if (!done) | 
 |     { | 
 |         func(); | 
 |         done = 1; | 
 |     } | 
 |  | 
 |     LeaveCriticalSection(lock); | 
 |  | 
 |     /* Last one out should free resources. The destructed objects are | 
 |      * protected by checking if(done) above. | 
 |      */ | 
 |     if(!InterlockedDecrement(&waiters)) | 
 |     { | 
 |         DeleteCriticalSection(lock); | 
 |         free(lock); | 
 |         lock = NULL; | 
 |     } | 
 | } | 
 |  | 
 |  | 
 | #elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H | 
 | #include <pthread.h> | 
 | static void once(void (*func)(void)) | 
 | { | 
 |     static pthread_once_t lock = PTHREAD_ONCE_INIT; | 
 |     pthread_once(&lock, func); | 
 | } | 
 |  | 
 |  | 
 | #else | 
 | /* No-op version that performs no synchronization. vp8_rtcd() is idempotent, | 
 |  * so as long as your platform provides atomic loads/stores of pointers | 
 |  * no synchronization is strictly necessary. | 
 |  */ | 
 |  | 
 | static void once(void (*func)(void)) | 
 | { | 
 |     static int done; | 
 |  | 
 |     if(!done) | 
 |     { | 
 |         func(); | 
 |         done = 1; | 
 |     } | 
 | } | 
 | #endif | 
 |  | 
 | #endif  // VPX_PORTS_VPX_ONCE_H_ |