Commit a6e70c60 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

ntdll: Handle unaligned SRW locks when using futexes.

parent 28619e60
...@@ -1705,14 +1705,17 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu ...@@ -1705,14 +1705,17 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu
static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock ) static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock )
{ {
int old, new; int old, new, *futex;
NTSTATUS ret; NTSTATUS ret;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do do
{ {
old = *(int *)lock; old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT) if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK)) && !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
...@@ -1726,31 +1729,34 @@ static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock ) ...@@ -1726,31 +1729,34 @@ static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock )
new = old; new = old;
ret = STATUS_TIMEOUT; ret = STATUS_TIMEOUT;
} }
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
return ret; return ret;
} }
static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock ) static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock )
{ {
int old, new; int old, new, *futex;
BOOLEAN wait; BOOLEAN wait;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
/* Atomically increment the exclusive waiter count. */ /* Atomically increment the exclusive waiter count. */
do do
{ {
old = *(int *)lock; old = *futex;
new = old + SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC; new = old + SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK); assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
for (;;) for (;;)
{ {
do do
{ {
old = *(int *)lock; old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT) if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK)) && !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
...@@ -1766,12 +1772,12 @@ static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock ) ...@@ -1766,12 +1772,12 @@ static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock )
new = old; new = old;
wait = TRUE; wait = TRUE;
} }
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
if (!wait) if (!wait)
return STATUS_SUCCESS; return STATUS_SUCCESS;
futex_wait_bitset( (int *)lock, new, NULL, SRWLOCK_FUTEX_BITSET_EXCLUSIVE ); futex_wait_bitset( futex, new, NULL, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;
...@@ -1779,14 +1785,17 @@ static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock ) ...@@ -1779,14 +1785,17 @@ static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock )
static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock ) static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock )
{ {
int new, old; int new, old, *futex;
NTSTATUS ret; NTSTATUS ret;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do do
{ {
old = *(int *)lock; old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT) if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)) && !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
...@@ -1802,23 +1811,26 @@ static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock ) ...@@ -1802,23 +1811,26 @@ static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock )
new = old; new = old;
ret = STATUS_TIMEOUT; ret = STATUS_TIMEOUT;
} }
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
return ret; return ret;
} }
static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock ) static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock )
{ {
int old, new; int old, new, *futex;
BOOLEAN wait; BOOLEAN wait;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
for (;;) for (;;)
{ {
do do
{ {
old = *(int *)lock; old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT) if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)) && !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
...@@ -1834,12 +1846,12 @@ static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock ) ...@@ -1834,12 +1846,12 @@ static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock )
new = old | SRWLOCK_FUTEX_SHARED_WAITERS_BIT; new = old | SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
wait = TRUE; wait = TRUE;
} }
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
if (!wait) if (!wait)
return STATUS_SUCCESS; return STATUS_SUCCESS;
futex_wait_bitset( (int *)lock, new, NULL, SRWLOCK_FUTEX_BITSET_SHARED ); futex_wait_bitset( futex, new, NULL, SRWLOCK_FUTEX_BITSET_SHARED );
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;
...@@ -1847,17 +1859,20 @@ static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock ) ...@@ -1847,17 +1859,20 @@ static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock )
static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock ) static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock )
{ {
int old, new; int old, new, *futex;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do do
{ {
old = *(int *)lock; old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)) if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT))
{ {
ERR("Lock %p is not owned exclusive! (%#x)\n", lock, *(int *)lock); ERR("Lock %p is not owned exclusive! (%#x)\n", lock, *futex);
return STATUS_RESOURCE_NOT_OWNED; return STATUS_RESOURCE_NOT_OWNED;
} }
...@@ -1865,43 +1880,46 @@ static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock ) ...@@ -1865,43 +1880,46 @@ static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock )
if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)) if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT; new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK) if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)
futex_wake_bitset( (int *)lock, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE ); futex_wake_bitset( futex, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
else if (old & SRWLOCK_FUTEX_SHARED_WAITERS_BIT) else if (old & SRWLOCK_FUTEX_SHARED_WAITERS_BIT)
futex_wake_bitset( (int *)lock, INT_MAX, SRWLOCK_FUTEX_BITSET_SHARED ); futex_wake_bitset( futex, INT_MAX, SRWLOCK_FUTEX_BITSET_SHARED );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS fast_release_srw_shared( RTL_SRWLOCK *lock ) static NTSTATUS fast_release_srw_shared( RTL_SRWLOCK *lock )
{ {
int old, new; int old, new, *futex;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do do
{ {
old = *(int *)lock; old = *futex;
if (old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT) if (old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
{ {
ERR("Lock %p is owned exclusive! (%#x)\n", lock, *(int *)lock); ERR("Lock %p is owned exclusive! (%#x)\n", lock, *futex);
return STATUS_RESOURCE_NOT_OWNED; return STATUS_RESOURCE_NOT_OWNED;
} }
else if (!(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK)) else if (!(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
{ {
ERR("Lock %p is not owned shared! (%#x)\n", lock, *(int *)lock); ERR("Lock %p is not owned shared! (%#x)\n", lock, *futex);
return STATUS_RESOURCE_NOT_OWNED; return STATUS_RESOURCE_NOT_OWNED;
} }
new = old - SRWLOCK_FUTEX_SHARED_OWNERS_INC; new = old - SRWLOCK_FUTEX_SHARED_OWNERS_INC;
} while (interlocked_cmpxchg( (int *)lock, new, old ) != old); } while (interlocked_cmpxchg( futex, new, old ) != old);
/* Optimization: only bother waking if there are actually exclusive waiters. */ /* Optimization: only bother waking if there are actually exclusive waiters. */
if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)) if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
futex_wake_bitset( (int *)lock, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE ); futex_wake_bitset( futex, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment