summaryrefslogtreecommitdiff
path: root/includes
diff options
context:
space:
mode:
authorTamar Christina <tamar@zhox.com>2019-06-01 10:56:31 +0100
committerBen Gamari <ben@smart-cactus.org>2020-07-15 16:41:01 -0400
commit459e1c5f7c71e37ed8bb239c57bdec441d278fff (patch)
treee049c6429afef505fcd65af9eb0a785be78aa200 /includes
parent00a23bfda4840546075ec2b2e18f61380b360dfc (diff)
downloadhaskell-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.h77
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