mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-01-28 22:04:43 -08:00
208 lines
8.3 KiB
Diff
208 lines
8.3 KiB
Diff
From 7324234ddce315b21a31e9e810593ea0c6917384 Mon Sep 17 00:00:00 2001
|
|
From: Sebastian Lackner <sebastian@fds-team.de>
|
|
Date: Sat, 11 Jan 2014 02:18:10 +0100
|
|
Subject: ntdll: Implement SRWLock functions using keyed events
|
|
|
|
---
|
|
dlls/kernel32/tests/sync.c | 6 ---
|
|
dlls/ntdll/sync.c | 119 ++++++++++++++++++++++++++++++++++++++++++--
|
|
2 files changed, 115 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c
|
|
index e5d1353..c7cceaa 100644
|
|
--- a/dlls/kernel32/tests/sync.c
|
|
+++ b/dlls/kernel32/tests/sync.c
|
|
@@ -1890,9 +1890,6 @@ static void test_srwlock_base(void)
|
|
WaitForSingleObject(h2, 100);
|
|
WaitForSingleObject(h3, 100);
|
|
|
|
- /* the current implementation just consists of stubs and all tests fail */
|
|
- todo_wine
|
|
- {
|
|
ok(!srwlock_base_errors.wrong_execution_order,
|
|
"thread commands were executed in the wrong order (occurred %d times).\n",
|
|
srwlock_base_errors.wrong_execution_order);
|
|
@@ -1916,7 +1913,6 @@ static void test_srwlock_base(void)
|
|
ok(!srwlock_base_errors.excl_not_preferred,
|
|
"thread waiting for exclusive access to the SHMLock was not preferred (occurred %d times).\n",
|
|
srwlock_base_errors.excl_not_preferred);
|
|
- }
|
|
}
|
|
|
|
static SRWLOCK srwlock_example;
|
|
@@ -1994,8 +1990,6 @@ static void test_srwlock_example(void)
|
|
WaitForSingleObject(h3, 1000);
|
|
|
|
ok(!srwlock_inside, "threads didn't terminate properly, srwlock_inside is %d.\n", srwlock_inside);
|
|
-
|
|
- todo_wine
|
|
ok(!srwlock_example_errors, "errors occured while running SRWLock example test (number of errors: %d)\n",
|
|
srwlock_example_errors);
|
|
|
|
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
|
|
index c94d9c4..d68be50 100644
|
|
--- a/dlls/ntdll/sync.c
|
|
+++ b/dlls/ntdll/sync.c
|
|
@@ -1382,8 +1382,88 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu
|
|
return RtlRunOnceComplete( once, 0, context ? *context : NULL );
|
|
}
|
|
|
|
+#define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
|
|
+#define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
|
|
+#define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
|
|
+#define SRWLOCK_RES_EXCLUSIVE 0x00010000
|
|
+#define SRWLOCK_RES_SHARED 0x00000001
|
|
+
|
|
+#ifdef WORDS_BIGENDIAN
|
|
+#define srwlock_key_exclusive(lock) (&lock->Ptr)
|
|
+#define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2))
|
|
+#else
|
|
+#define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2))
|
|
+#define srwlock_key_shared(lock) (&lock->Ptr)
|
|
+#endif
|
|
+
|
|
+static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
|
|
+{
|
|
+ unsigned int val, tmp;
|
|
+ /* Atomically modifies the value of *dest by adding incr. If the shared
|
|
+ * queue is empty and there are threads waiting for exclusive access, then
|
|
+ * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
|
|
+ * they are allowed to use again the shared queue counter. */
|
|
+ for (val = *dest;; val = tmp)
|
|
+ {
|
|
+ tmp = val + incr;
|
|
+ if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
|
|
+ tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
|
|
+ if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
|
|
+ break;
|
|
+ }
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
|
|
+{
|
|
+ unsigned int val, tmp;
|
|
+ /* Atomically modifies the value of *dest by adding incr. If the queue of
|
|
+ * threads waiting for exclusive access is empty, then remove the
|
|
+ * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
|
|
+ * remain). */
|
|
+ for (val = *dest;; val = tmp)
|
|
+ {
|
|
+ tmp = val + incr;
|
|
+ if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
|
|
+ tmp &= SRWLOCK_MASK_SHARED_QUEUE;
|
|
+ if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
|
|
+ break;
|
|
+ }
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
|
|
+{
|
|
+ /* Used when a thread leaves an exclusive section. If there are other
|
|
+ * exclusive access threads they are processed first, afterwards process
|
|
+ * the shared waiters. */
|
|
+ if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
|
|
+ NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
|
|
+ else
|
|
+ {
|
|
+ val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
|
|
+ while (val--)
|
|
+ NtReleaseKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
|
|
+{
|
|
+ /* Wake up one exclusive thread as soon as the last shared access thread
|
|
+ * has left. */
|
|
+ if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
|
|
+ NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
|
|
+}
|
|
+
|
|
/***********************************************************************
|
|
* RtlInitializeSRWLock (NTDLL.@)
|
|
+ *
|
|
+ * NOTES
|
|
+ * Please note that SRWLocks do not keep track of the owner of a lock.
|
|
+ * It doesn't make any difference which thread for example unlocks an
|
|
+ * SRWLock (see corresponding tests). This implementation uses two
|
|
+ * keyed events (one for the exclusive waiters and one for the shared
|
|
+ * waiters) and is limited to 2^15-1 waiting threads.
|
|
*/
|
|
void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
|
|
{
|
|
@@ -1392,10 +1472,16 @@ void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
|
|
|
|
/***********************************************************************
|
|
* RtlAcquireSRWLockExclusive (NTDLL.@)
|
|
+ *
|
|
+ * NOTES
|
|
+ * Unlike RtlAcquireResourceExclusive this function doesn't allow
|
|
+ * nested calls from the same thread. "Upgrading" a shared access lock
|
|
+ * to an exclusive access lock also doesn't seem to be supported.
|
|
*/
|
|
void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
|
|
{
|
|
- FIXME( "%p stub\n", lock );
|
|
+ if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
|
|
+ NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
|
|
}
|
|
|
|
/***********************************************************************
|
|
@@ -1403,7 +1489,30 @@ void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
|
|
*/
|
|
void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
|
|
{
|
|
- FIXME( "%p stub\n", lock );
|
|
+ unsigned int val, tmp;
|
|
+ /* Acquires a shared lock. If its currently not possible to add elements to
|
|
+ * the shared queue, then request exclusive access instead. */
|
|
+ for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
|
|
+ {
|
|
+ if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
|
|
+ tmp = val + SRWLOCK_RES_EXCLUSIVE;
|
|
+ else
|
|
+ tmp = val + SRWLOCK_RES_SHARED;
|
|
+ if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Drop exclusive access again and instead requeue for shared access. */
|
|
+ if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
|
|
+ {
|
|
+ NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
|
|
+ val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
|
|
+ - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
|
|
+ srwlock_leave_exclusive( lock, val );
|
|
+ }
|
|
+
|
|
+ if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
|
|
+ NtWaitForKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
|
|
}
|
|
|
|
/***********************************************************************
|
|
@@ -1411,7 +1520,8 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
|
|
*/
|
|
void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
|
|
{
|
|
- FIXME( "%p stub\n", lock );
|
|
+ srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
|
|
+ - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
|
|
}
|
|
|
|
/***********************************************************************
|
|
@@ -1419,7 +1529,8 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
|
|
*/
|
|
void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
|
|
{
|
|
- FIXME( "%p stub\n", lock );
|
|
+ srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
|
|
+ - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
|
|
}
|
|
|
|
/***********************************************************************
|
|
--
|
|
1.7.9.5
|
|
|