]> pd.if.org Git - pdclib/blob - platform/win32/functions/threads/call_once.c
Cosmetic comment fixes.
[pdclib] / platform / win32 / functions / threads / call_once.c
1 #ifndef REGTEST
2 #include <threads.h>
3 #include <windows.h>
4
5 static volatile HANDLE onceHandle = NULL;
6
7 static void initOnceHandle( _PDCLIB_once_flag *flag )
8 {
9     HANDLE tOnceHandle = CreateEvent(NULL, TRUE, TRUE, NULL);
10     HANDLE oldVal 
11         = InterlockedCompareExchangePointer(&flag->_Handle, tOnceHandle, NULL);
12     if(oldVal != NULL)
13         CloseHandle(tOnceHandle);
14 }
15
16 void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void))
17 {
18    if(!flag->_Handle) initOnceHandle(flag);
19
20    long oldVal = InterlockedCompareExchange(&flag->_State, 1, -1);
21    for(;;) {
22         if(oldVal == 0) {
23             // Initialized
24             return;
25         } else if(oldVal == -1) {
26             // We are doing the initialization
27             func();
28             if(InterlockedDecrement(&flag->_State) == 0)
29                 CloseHandle(flag->_Handle);
30             SetEvent(flag->_Handle);
31             return;
32         } else {
33             // Somebody else is initializing - we are waiting
34             long newOldVal = InterlockedCompareExchange(&flag->_State, oldVal, 
35                                                         oldVal+1);
36             if(newOldVal == oldVal) {
37                 // We incremented the "waiters" counter
38                 if(WaitForSingleObject(flag->_Handle, INFINITE) != WAIT_OBJECT_0)
39                     abort();
40                 if(InterlockedDecrement(&flag->_State) == 0)
41                     CloseHandle(flag->_Handle);
42                 return;
43             } else {
44                 oldVal = newOldVal;
45                 continue;
46             }
47         }
48     }
49 }
50 #endif
51
52 #ifdef TEST
53 #include "_PDCLIB_test.h"
54
55 #ifndef REGTEST
56 static int count = 0;
57 static once_flag once = ONCE_FLAG_INIT;
58
59 static void do_once(void)
60 {
61     count++;
62 }
63 #endif
64
65 int main( void )
66 {
67 #ifndef REGTEST
68     TESTCASE(count == 0);
69     call_once(&once, do_once);
70     TESTCASE(count == 1);
71     call_once(&once, do_once);
72     TESTCASE(count == 1);
73     do_once();
74     TESTCASE(count == 2);
75 #endif
76     return TEST_RESULTS;
77 }
78
79 #endif