Home | History | Annotate | Download | only in common
      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