diff options
author | Tamar Christina <tamar@zhox.com> | 2019-06-01 10:56:31 +0100 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2020-07-15 16:41:01 -0400 |
commit | 459e1c5f7c71e37ed8bb239c57bdec441d278fff (patch) | |
tree | e049c6429afef505fcd65af9eb0a785be78aa200 /includes | |
parent | 00a23bfda4840546075ec2b2e18f61380b360dfc (diff) | |
download | haskell-459e1c5f7c71e37ed8bb239c57bdec441d278fff.tar.gz |
winio: Use SlimReaderLocks and ConditonalVariables provided by the OS instead of emulated ones
Diffstat (limited to 'includes')
-rw-r--r-- | includes/rts/OSThreads.h | 77 |
1 files changed, 35 insertions, 42 deletions
diff --git a/includes/rts/OSThreads.h b/includes/rts/OSThreads.h index ada2a9a787..a68f1ea140 100644 --- a/includes/rts/OSThreads.h +++ b/includes/rts/OSThreads.h @@ -77,18 +77,22 @@ EXTERN_INLINE int TRY_ACQUIRE_LOCK(pthread_mutex_t *mutex) #if defined(CMINUSMINUS) -/* We jump through a hoop here to get a CCall EnterCriticalSection - and LeaveCriticalSection, as that's what C-- wants. */ +/* We jump through a hoop here to get a CCall AcquireSRWLockExclusive + and ReleaseSRWLockExclusive, as that's what C-- wants. */ -#define OS_ACQUIRE_LOCK(mutex) foreign "stdcall" EnterCriticalSection(mutex) -#define OS_RELEASE_LOCK(mutex) foreign "stdcall" LeaveCriticalSection(mutex) +#define OS_ACQUIRE_LOCK(mutex) foreign "stdcall" AcquireSRWLockExclusive(mutex) +#define OS_RELEASE_LOCK(mutex) foreign "stdcall" ReleaseSRWLockExclusive(mutex) #define OS_ASSERT_LOCK_HELD(mutex) /* nothing */ -#else +#else // CMINUSMINUS #include <windows.h> +#include <synchapi.h> -typedef HANDLE Condition; +/* Use native conditional variables coupled with SRW locks, these are more + efficient and occur a smaller overhead then emulating them with events. + See Note [SRW locks]. */ +typedef CONDITION_VARIABLE Condition; typedef DWORD OSThreadId; // don't be tempted to use HANDLE as the OSThreadId: there can be // many HANDLES to a given thread, so comparison would not work. @@ -98,58 +102,47 @@ typedef DWORD ThreadLocalKey; #define INIT_COND_VAR 0 -// We have a choice for implementing Mutexes on Windows. Standard -// Mutexes are kernel objects that require kernel calls to -// acquire/release, whereas CriticalSections are spin-locks that block -// in the kernel after spinning for a configurable number of times. -// CriticalSections are *much* faster, so we use those. The Mutex -// implementation is left here for posterity. -#define USE_CRITICAL_SECTIONS 1 - -#if USE_CRITICAL_SECTIONS - -typedef CRITICAL_SECTION Mutex; +/* Note [SRW locks] + We have a choice for implementing Mutexes on Windows. Standard + Mutexes are kernel objects that require kernel calls to + acquire/release, whereas CriticalSections are spin-locks that block + in the kernel after spinning for a configurable number of times. + CriticalSections are *much* faster than Mutexes, however not as fast as + slim reader/writer locks. CriticalSections also require a 48 byte structure + to provide lock re-entrancy. We don't need that because the other primitives + used for other platforms don't have this, as such locks are used defensively + in the RTS in a way that we don't need re-entrancy. This means that SRW's + 8 byte size is much more appropriate. With an 8 byte payload there's a + higher chance of it being in your cache line. They're also a lot faster than + CriticalSections when multiple threads are involved. CS requires setup and + teardown via kernel calls while SRWL is zero-initialized via + SRWLOCK_INIT assignment. */ + +typedef SRWLOCK Mutex; #if defined(LOCK_DEBUG) #define OS_ACQUIRE_LOCK(mutex) \ debugBelch("ACQUIRE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \ - EnterCriticalSection(mutex) + AcquireSRWLockExclusive(mutex) #define OS_RELEASE_LOCK(mutex) \ debugBelch("RELEASE_LOCK(0x%p) %s %d\n", mutex,__FILE__,__LINE__); \ - LeaveCriticalSection(mutex) + ReleaseSRWLockExclusive(mutex) #define OS_ASSERT_LOCK_HELD(mutex) /* nothing */ #else -#define OS_ACQUIRE_LOCK(mutex) EnterCriticalSection(mutex) -#define TRY_ACQUIRE_LOCK(mutex) (TryEnterCriticalSection(mutex) == 0) -#define OS_RELEASE_LOCK(mutex) LeaveCriticalSection(mutex) +#define OS_ACQUIRE_LOCK(mutex) AcquireSRWLockExclusive(mutex) +#define TRY_ACQUIRE_LOCK(mutex) (TryAcquireSRWLockExclusive(mutex) == 0) +#define OS_RELEASE_LOCK(mutex) ReleaseSRWLockExclusive(mutex) +#define OS_INIT_LOCK(mutex) InitializeSRWLock(mutex) +#define OS_CLOSE_LOCK(mutex) // I don't know how to do this. TryEnterCriticalSection() doesn't do // the right thing. #define OS_ASSERT_LOCK_HELD(mutex) /* nothing */ -#endif - -#else - -typedef HANDLE Mutex; - -// casting to (Mutex *) here required due to use in .cmm files where -// the argument has (void *) type. -#define OS_ACQUIRE_LOCK(mutex) \ - if (WaitForSingleObject(*((Mutex *)mutex),INFINITE) == WAIT_FAILED) { \ - barf("WaitForSingleObject: %d", GetLastError()); \ - } - -#define OS_RELEASE_LOCK(mutex) \ - if (ReleaseMutex(*((Mutex *)mutex)) == 0) { \ - barf("ReleaseMutex: %d", GetLastError()); \ - } - -#define OS_ASSERT_LOCK_HELD(mutex) /* nothing */ -#endif +#endif // LOCK_DEBUG #endif // CMINUSMINUS |