blob: 16a735ccdbe4261b42ab2c65e458d23b5844851c [file] [log] [blame]
John Koleszara9c75972012-11-08 17:09:30 -08001/*
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
12#if CONFIG_MULTITHREAD && defined(_WIN32)
13#include <windows.h>
14#include <stdlib.h>
15static void once(void (*func)(void))
16{
17 static CRITICAL_SECTION *lock;
18 static LONG waiters;
19 static int done;
20 void *lock_ptr = &lock;
21
22 /* If the initialization is complete, return early. This isn't just an
23 * optimization, it prevents races on the destruction of the global
24 * lock.
25 */
26 if(done)
27 return;
28
29 InterlockedIncrement(&waiters);
30
31 /* Get a lock. We create one and try to make it the one-true-lock,
32 * throwing it away if we lost the race.
33 */
34
35 {
36 /* Scope to protect access to new_lock */
37 CRITICAL_SECTION *new_lock = malloc(sizeof(CRITICAL_SECTION));
38 InitializeCriticalSection(new_lock);
39 if (InterlockedCompareExchangePointer(lock_ptr, new_lock, NULL) != NULL)
40 {
41 DeleteCriticalSection(new_lock);
42 free(new_lock);
43 }
44 }
45
46 /* At this point, we have a lock that can be synchronized on. We don't
47 * care which thread actually performed the allocation.
48 */
49
50 EnterCriticalSection(lock);
51
52 if (!done)
53 {
54 func();
55 done = 1;
56 }
57
58 LeaveCriticalSection(lock);
59
60 /* Last one out should free resources. The destructed objects are
61 * protected by checking if(done) above.
62 */
63 if(!InterlockedDecrement(&waiters))
64 {
65 DeleteCriticalSection(lock);
66 free(lock);
67 lock = NULL;
68 }
69}
70
71
72#elif CONFIG_MULTITHREAD && HAVE_PTHREAD_H
73#include <pthread.h>
74static void once(void (*func)(void))
75{
76 static pthread_once_t lock = PTHREAD_ONCE_INIT;
77 pthread_once(&lock, func);
78}
79
80
81#else
82/* No-op version that performs no synchronization. vp8_rtcd() is idempotent,
83 * so as long as your platform provides atomic loads/stores of pointers
84 * no synchronization is strictly necessary.
85 */
86
87static void once(void (*func)(void))
88{
89 static int done;
90
91 if(!done)
92 {
93 func();
94 done = 1;
95 }
96}
97#endif