--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+static volatile HANDLE onceHandle = NULL;\r
+\r
+static void initOnceHandle( _PDCLIB_once_flag *flag )\r
+{\r
+ HANDLE tOnceHandle = CreateEvent(NULL, TRUE, TRUE, NULL);\r
+ HANDLE oldVal \r
+ = InterlockedCompareExchangePointer(&flag->_Handle, tOnceHandle, NULL);\r
+ if(oldVal != NULL)\r
+ CloseHandle(tOnceHandle);\r
+}\r
+\r
+void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void))\r
+{\r
+ if(!flag->_Handle) initOnceHandle(flag);\r
+\r
+ long oldVal = InterlockedCompareExchange(&flag->_State, 1, -1);\r
+ for(;;) {\r
+ if(oldVal == 0) {\r
+ // Initialized\r
+ return;\r
+ } else if(oldVal == -1) {\r
+ // We are doing the initialization\r
+ func();\r
+ if(InterlockedDecrement(&flag->_State) == 0)\r
+ CloseHandle(flag->_Handle);\r
+ SetEvent(flag->_Handle);\r
+ return;\r
+ } else {\r
+ // Somebody else is initializing - we are waiting\r
+ long newOldVal = InterlockedCompareExchange(&flag->_State, oldVal, \r
+ oldVal+1);\r
+ if(newOldVal == oldVal) {\r
+ // We incremented the "waiters" counter\r
+ if(WaitForSingleObject(flag->_Handle, INFINITE) != WAIT_OBJECT_0)\r
+ abort();\r
+ if(InterlockedDecrement(&flag->_State) == 0)\r
+ CloseHandle(flag->_Handle);\r
+ return;\r
+ } else {\r
+ oldVal = newOldVal;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+#ifndef REGTEST\r
+static int count = 0;\r
+static once_flag once = ONCE_FLAG_INIT;\r
+\r
+static void do_once(void)\r
+{\r
+ count++;\r
+}\r
+#endif\r
+\r
+int main( void )\r
+{\r
+#ifndef REGTEST\r
+ TESTCASE(count == 0);\r
+ call_once(&once, do_once);\r
+ TESTCASE(count == 1);\r
+ call_once(&once, do_once);\r
+ TESTCASE(count == 1);\r
+ do_once();\r
+ TESTCASE(count == 2);\r
+#endif\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif\r