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