]> pd.if.org Git - pdclib/blobdiff - platform/win32/functions/threads/call_once.c
win32: initial pass at thread support
[pdclib] / platform / win32 / functions / threads / call_once.c
diff --git a/platform/win32/functions/threads/call_once.c b/platform/win32/functions/threads/call_once.c
new file mode 100644 (file)
index 0000000..675e000
--- /dev/null
@@ -0,0 +1,79 @@
+#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