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