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