]> granicus.if.org Git - libvpx/commitdiff
rtcd: merge rtcd.c from master
authorJohn Koleszar <jkoleszar@google.com>
Wed, 10 Oct 2012 19:30:16 +0000 (12:30 -0700)
committerJohn Koleszar <jkoleszar@google.com>
Wed, 10 Oct 2012 19:30:16 +0000 (12:30 -0700)
Pick up changes to multithreading and once() implementations.

Change-Id: I4a98df6b714f3208643798e0e7f74e373a7931e3

vp8/common/rtcd.c

index a7bb92ce4bbfce8d314b27c859cb757121e68f40..01dad4691b1f7bf6360704c547440926cbb6b90d 100644 (file)
 #define RTCD_C
 #include "vpx_rtcd.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. vpx_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;
+static void once(void (*func)(void))
+{
+    static int done;
 
-  if(!done) {
-    func();
-    done = 1;
-  }
+    if(!done)
+    {
+        func();
+        done = 1;
+    }
 }
+#endif
+
 
-void vpx_rtcd() {
-  once(setup_rtcd_internal);
+void vpx_rtcd()
+{
+    once(setup_rtcd_internal);
 }