ref: 2808dd12c29b83226563fcf443b72f4be3dcb73d
dir: /vpx_ports/vpx_once.h/
/* * 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 && defined(__OS2__) #define INCL_DOS #include <os2.h> static void once(void (*func)(void)) { static int done; /* If the initialization is complete, return early. */ if(done) return; /* Causes all other threads in the process to block themselves * and give up their time slice. */ DosEnterCritSec(); if (!done) { func(); done = 1; } /* Restores normal thread dispatching for the current process. */ DosExitCritSec(); } #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. *_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_