]> pd.if.org Git - pdclib/commitdiff
win32: mutex rewrite. new form is much simpler
authorOwen Shepherd <owen.shepherd@e43.eu>
Sat, 25 Aug 2012 19:04:11 +0000 (20:04 +0100)
committerOwen Shepherd <owen.shepherd@e43.eu>
Sat, 25 Aug 2012 19:04:11 +0000 (20:04 +0100)
platform/win32/functions/threads/mtx_init.c
platform/win32/functions/threads/mtx_lock.c
platform/win32/functions/threads/mtx_timedlock.c [new file with mode: 0644]
platform/win32/functions/threads/mtx_trylock.c [new file with mode: 0644]
platform/win32/functions/threads/mtx_unlock.c
platform/win32/internals/_PDCLIB_threadconfig.h

index 19db3908dc0430cfa6b08be47877014999782565..b1da7a85a48135f4cc241fd998a0d36a13bcaf0b 100644 (file)
@@ -11,7 +11,6 @@ int mtx_init(mtx_t *mtx, int type)
     if(mtx->_WaitEvHandle == NULL)\r
         return thrd_error;\r
     \r
-    mtx->_State        = -1;\r
     mtx->_ThreadId     = 0;\r
     mtx->_NestCount    = 0;;\r
 \r
index 70af8ae35bd7cd65c7785527544d7cf7778e2776..59e716dc0232c0f56e3584b1d867705e1dcbbf64 100644 (file)
@@ -11,21 +11,15 @@ int mtx_lock(mtx_t *mtx)
         return thrd_success;\r
     }\r
 \r
-    DWORD res = InterlockedIncrement(&mtx->_State);\r
-    if(res == 0) {\r
-        mtx->_ThreadId = myId;\r
-        return thrd_success;\r
+    for(;;) {\r
+        LONG prev = InterlockedCompareExchange(&mtx->_ThreadId, myId, 0);\r
+        if(prev == 0)\r
+            return thrd_success;\r
+\r
+        DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, INFINITE);\r
+        if(rv != WAIT_OBJECT_0)\r
+            return thrd_error;\r
     }\r
-\r
-    // If that increment didn't leave the state == 0, then we have contention\r
-    //  -> block on the wait event handle\r
-    DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, INFINITE);\r
-    if(rv != WAIT_OBJECT_0) \r
-        return thrd_error;\r
-\r
-    // We now own the mutex - so set it up for our use\r
-    mtx->_ThreadId = myId;\r
-    return thrd_success;\r
 }\r
 #endif\r
 \r
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
diff --git a/platform/win32/functions/threads/mtx_trylock.c b/platform/win32/functions/threads/mtx_trylock.c
new file mode 100644 (file)
index 0000000..ebc5e85
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+int mtx_trylock(mtx_t *mtx)\r
+{\r
+    DWORD myId = GetCurrentThreadId();\r
+\r
+    if(mtx->_ThreadId == myId) {\r
+        mtx->_NestCount++;\r
+        return thrd_success;\r
+    }\r
+\r
+    if(mtx->_ThreadId != 0)\r
+        return thrd_busy;\r
+\r
+    LONG prev = InterlockedCompareExchange(&mtx->_ThreadId, myId, 0);\r
+    if(prev == 0)\r
+        return thrd_success;\r
+    else\r
+        return thrd_busy;\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
index 27b7aefadb7d6ff4a277c1e6fedadb27bca74e9d..1222c292ea42ffa47b934fb154ad3df68ef58a69 100644 (file)
@@ -11,19 +11,11 @@ int mtx_unlock(mtx_t *mtx)
     }\r
 \r
     mtx->_ThreadId = 0;\r
-\r
-    DWORD res = InterlockedDecrement(&mtx->_State);\r
-    if(res == (DWORD) -1) {\r
-        // We reset the state to -1; success!\r
-        return thrd_success;\r
-    }\r
-\r
     DWORD rv = SetEvent(mtx->_WaitEvHandle);\r
     if(rv == 0) {\r
         _PDCLIB_w32errno();\r
         return thrd_error;\r
     }\r
-\r
     return thrd_success;\r
 }\r
 #endif\r
index d914ae04d646564db18632f49c62f6b201610a63..c311867e871297fac957528bc1d664090ba86a80 100644 (file)
@@ -19,10 +19,9 @@ void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void));
 #define _PDCLIB_MTX_T struct _PDCLIB_mtx \r
 \r
 struct _PDCLIB_mtx {\r
-    void         * _WaitEvHandle;\r
-    volatile   signed long  _State;\r
-    volatile unsigned  int  _ThreadId;\r
-    volatile unsigned  int  _NestCount;\r
+    void                   * _WaitEvHandle;\r
+    volatile unsigned long   _ThreadId; \r
+    volatile unsigned  int   _NestCount;\r
 };\r
 \r
 #define _PDCLIB_TSS_T struct _PDCLIB_tss *\r