From 3b357986c8ac26f3aee1033c49c28f58c3cd2fb4 Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Sat, 25 Aug 2012 20:04:11 +0100 Subject: [PATCH] win32: mutex rewrite. new form is much simpler --- platform/win32/functions/threads/mtx_init.c | 1 - platform/win32/functions/threads/mtx_lock.c | 22 +++---- .../win32/functions/threads/mtx_timedlock.c | 58 +++++++++++++++++++ .../win32/functions/threads/mtx_trylock.c | 33 +++++++++++ platform/win32/functions/threads/mtx_unlock.c | 8 --- .../win32/internals/_PDCLIB_threadconfig.h | 7 +-- 6 files changed, 102 insertions(+), 27 deletions(-) create mode 100644 platform/win32/functions/threads/mtx_timedlock.c create mode 100644 platform/win32/functions/threads/mtx_trylock.c diff --git a/platform/win32/functions/threads/mtx_init.c b/platform/win32/functions/threads/mtx_init.c index 19db390..b1da7a8 100644 --- a/platform/win32/functions/threads/mtx_init.c +++ b/platform/win32/functions/threads/mtx_init.c @@ -11,7 +11,6 @@ int mtx_init(mtx_t *mtx, int type) if(mtx->_WaitEvHandle == NULL) return thrd_error; - mtx->_State = -1; mtx->_ThreadId = 0; mtx->_NestCount = 0;; diff --git a/platform/win32/functions/threads/mtx_lock.c b/platform/win32/functions/threads/mtx_lock.c index 70af8ae..59e716d 100644 --- a/platform/win32/functions/threads/mtx_lock.c +++ b/platform/win32/functions/threads/mtx_lock.c @@ -11,21 +11,15 @@ int mtx_lock(mtx_t *mtx) return thrd_success; } - DWORD res = InterlockedIncrement(&mtx->_State); - if(res == 0) { - mtx->_ThreadId = myId; - return thrd_success; + for(;;) { + LONG prev = InterlockedCompareExchange(&mtx->_ThreadId, myId, 0); + if(prev == 0) + return thrd_success; + + DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, INFINITE); + if(rv != WAIT_OBJECT_0) + return thrd_error; } - - // If that increment didn't leave the state == 0, then we have contention - // -> block on the wait event handle - DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, INFINITE); - if(rv != WAIT_OBJECT_0) - return thrd_error; - - // We now own the mutex - so set it up for our use - mtx->_ThreadId = myId; - return thrd_success; } #endif diff --git a/platform/win32/functions/threads/mtx_timedlock.c b/platform/win32/functions/threads/mtx_timedlock.c new file mode 100644 index 0000000..07edc0c --- /dev/null +++ b/platform/win32/functions/threads/mtx_timedlock.c @@ -0,0 +1,58 @@ +#ifndef REGTEST +#include +#include +#include + +int mtx_timedlock(mtx_t *_PDCLIB_restrict mtx, + const struct timespec *_PDCLIB_restrict until) +{ + DWORD myId = GetCurrentThreadId(); + + if(mtx->_ThreadId == myId) { + mtx->_NestCount++; + return thrd_success; + } + + + for(;;) { + LONG prev = InterlockedCompareExchange(&mtx->_ThreadId, myId, 0); + if(prev == 0) + return thrd_success; + + struct timespec now; + int32_t msToWait = 0; + if(timespec_get(&now, TIME_UTC) != TIME_UTC) { + // timespec_get must work! + return thrd_error; + } else { + int64_t deltaSec = (int64_t)until->tv_sec - now.tv_sec; + long deltaNsec = (long)until->tv_nsec - now.tv_nsec; + + if(INT32_MAX / 2000U < deltaSec) { + // Risk of overflow - do a shorter timeout on this iteration + msToWait = INT32_MAX / 2; + } else { + msToWait = deltaSec * 1000 + deltaNsec / 1000; + } + } + + if(msToWait < 0) { + return thrd_timeout; + } + + DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, msToWait); + if(rv != WAIT_OBJECT_0 && rv != WAIT_TIMEOUT) + return thrd_error; + } +} +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + return TEST_RESULTS; +} + +#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 index 0000000..ebc5e85 --- /dev/null +++ b/platform/win32/functions/threads/mtx_trylock.c @@ -0,0 +1,33 @@ +#ifndef REGTEST +#include +#include + +int mtx_trylock(mtx_t *mtx) +{ + DWORD myId = GetCurrentThreadId(); + + if(mtx->_ThreadId == myId) { + mtx->_NestCount++; + return thrd_success; + } + + if(mtx->_ThreadId != 0) + return thrd_busy; + + LONG prev = InterlockedCompareExchange(&mtx->_ThreadId, myId, 0); + if(prev == 0) + return thrd_success; + else + return thrd_busy; +} +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + return TEST_RESULTS; +} + +#endif \ No newline at end of file diff --git a/platform/win32/functions/threads/mtx_unlock.c b/platform/win32/functions/threads/mtx_unlock.c index 27b7aef..1222c29 100644 --- a/platform/win32/functions/threads/mtx_unlock.c +++ b/platform/win32/functions/threads/mtx_unlock.c @@ -11,19 +11,11 @@ int mtx_unlock(mtx_t *mtx) } mtx->_ThreadId = 0; - - DWORD res = InterlockedDecrement(&mtx->_State); - if(res == (DWORD) -1) { - // We reset the state to -1; success! - return thrd_success; - } - DWORD rv = SetEvent(mtx->_WaitEvHandle); if(rv == 0) { _PDCLIB_w32errno(); return thrd_error; } - return thrd_success; } #endif diff --git a/platform/win32/internals/_PDCLIB_threadconfig.h b/platform/win32/internals/_PDCLIB_threadconfig.h index d914ae0..c311867 100644 --- a/platform/win32/internals/_PDCLIB_threadconfig.h +++ b/platform/win32/internals/_PDCLIB_threadconfig.h @@ -19,10 +19,9 @@ void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void)); #define _PDCLIB_MTX_T struct _PDCLIB_mtx struct _PDCLIB_mtx { - void * _WaitEvHandle; - volatile signed long _State; - volatile unsigned int _ThreadId; - volatile unsigned int _NestCount; + void * _WaitEvHandle; + volatile unsigned long _ThreadId; + volatile unsigned int _NestCount; }; #define _PDCLIB_TSS_T struct _PDCLIB_tss * -- 2.40.0