]> pd.if.org Git - pdclib/blobdiff - platform/win32/functions/threads/mtx_timedlock.c
win32: mutex rewrite. new form is much simpler
[pdclib] / platform / win32 / functions / threads / mtx_timedlock.c
diff --git a/platform/win32/functions/threads/mtx_timedlock.c b/platform/win32/functions/threads/mtx_timedlock.c
new file mode 100644 (file)
index 0000000..07edc0c
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+#include <stdint.h>\r
+\r
+int mtx_timedlock(mtx_t *_PDCLIB_restrict mtx, \r
+                  const struct timespec *_PDCLIB_restrict until)\r
+{\r
+    DWORD myId = GetCurrentThreadId();\r
+\r
+    if(mtx->_ThreadId == myId) {\r
+        mtx->_NestCount++;\r
+        return thrd_success;\r
+    }\r
+\r
+\r
+    for(;;) {\r
+        LONG prev = InterlockedCompareExchange(&mtx->_ThreadId, myId, 0);\r
+        if(prev == 0)\r
+            return thrd_success;\r
+\r
+        struct timespec now;\r
+        int32_t msToWait = 0;\r
+        if(timespec_get(&now, TIME_UTC) != TIME_UTC) {\r
+            // timespec_get must work!\r
+            return thrd_error;\r
+        } else {\r
+            int64_t deltaSec  = (int64_t)until->tv_sec  - now.tv_sec;\r
+            long    deltaNsec = (long)until->tv_nsec - now.tv_nsec;\r
+\r
+            if(INT32_MAX / 2000U < deltaSec) {\r
+                // Risk of overflow - do a shorter timeout on this iteration\r
+                msToWait = INT32_MAX / 2;\r
+            } else {\r
+                msToWait = deltaSec * 1000 + deltaNsec / 1000;\r
+            }\r
+        }\r
+\r
+        if(msToWait < 0) {\r
+            return thrd_timeout;\r
+        }\r
+\r
+        DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, msToWait);\r
+        if(rv != WAIT_OBJECT_0 && rv != WAIT_TIMEOUT)\r
+            return thrd_error;\r
+    }\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+int main( void )\r
+{\r
+    return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file