This comes from behavioral study of Windows, which doesn't seem to check if the lock is actually exclusively held, and just simply decrement the value stored in the lock.
This fixes a dead lock which prevents WeCom from starting up.
From: Yuxuan Shui yshui@codeweavers.com
This comes from behavioral study of Windows, which doesn't seem to check if the lock is actually exclusively held, and just simply decrement the value stored in the lock. --- dlls/kernel32/tests/sync.c | 24 ++++++++++++++++++++++++ dlls/ntdll/sync.c | 8 +++++--- 2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 60180194b7a..aa93c486edf 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -2533,6 +2533,29 @@ static void test_srwlock_example(void) trace("number of total exclusive accesses is %ld\n", srwlock_protected_value); }
+static void test_srwlock_quirk(void) +{ + union { RTL_SRWLOCK *rtl; SRWLOCK *s; LONG *l; } u = { &srwlock_example }; + + if (!pInitializeSRWLock) { + /* function is not yet in XP, only in newer Windows */ + win_skip("no srw lock support.\n"); + return; + } + + *u.l = 0; + pReleaseSRWLockExclusive(&srwlock_example); + ok(*u.l == 0xffffffff, "expected 0xffffffff, got %lx\n", *u.l); + + *u.l = 1; + pReleaseSRWLockExclusive(&srwlock_example); + ok(*u.l == 0, "expected 0x0, got %lx\n", *u.l); + + *u.l = 0x10000; + pReleaseSRWLockExclusive(&srwlock_example); + ok(*u.l == 0xffff, "expected 0xffff, got %lx\n", *u.l); +} + static DWORD WINAPI alertable_wait_thread(void *param) { HANDLE *semaphores = param; @@ -2887,6 +2910,7 @@ START_TEST(sync) test_srwlock_base(&aligned_srwlock); test_srwlock_base(&unaligned_srwlock.lock); test_srwlock_example(); + test_srwlock_quirk(); test_alertable_wait(); test_apc_deadlock(); test_crit_section(); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index fa64917029a..3e71b7b7ee9 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -599,9 +599,11 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock ) old.s = *u.s; new = old;
- if (old.s.owners != -1) ERR("Lock %p is not owned exclusive!\n", lock); - - new.s.owners = 0; + if (old.s.owners != -1) { + ERR("Lock %p is not owned exclusive!\n", lock); + new.l = old.l - 1; /* this is what Windows does */ + } else + new.s.owners = 0; } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l);
if (new.s.exclusive_waiters)