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

ntdll: Reimplement SRW locks on top of Win32 futexes.

parent 87164ee3
......@@ -2145,12 +2145,6 @@ static struct unix_funcs unix_funcs =
NtCurrentTeb,
#endif
RtlGetSystemTimePrecise,
fast_RtlTryAcquireSRWLockExclusive,
fast_RtlAcquireSRWLockExclusive,
fast_RtlTryAcquireSRWLockShared,
fast_RtlAcquireSRWLockShared,
fast_RtlReleaseSRWLockExclusive,
fast_RtlReleaseSRWLockShared,
load_so_dll,
init_builtin_dll,
init_unix_lib,
......
......@@ -110,8 +110,6 @@ static inline ULONGLONG monotonic_counter(void)
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_WAIT_BITSET 9
#define FUTEX_WAKE_BITSET 10
static int futex_private = 128;
......@@ -125,16 +123,6 @@ static inline int futex_wake( const int *addr, int val )
return syscall( __NR_futex, addr, FUTEX_WAKE | futex_private, val, NULL, 0, 0 );
}
static inline int futex_wait_bitset( const int *addr, int val, struct timespec *timeout, int mask )
{
return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | futex_private, val, timeout, 0, mask );
}
static inline int futex_wake_bitset( const int *addr, int val, int mask )
{
return syscall( __NR_futex, addr, FUTEX_WAKE_BITSET | futex_private, val, NULL, 0, mask );
}
static inline int use_futexes(void)
{
static int supported = -1;
......@@ -152,16 +140,6 @@ static inline int use_futexes(void)
return supported;
}
static int *get_futex(void **ptr)
{
if (sizeof(void *) == 8)
return (int *)((((ULONG_PTR)ptr) + 3) & ~3);
else if (!(((ULONG_PTR)ptr) & 3))
return (int *)ptr;
else
return NULL;
}
#endif
......@@ -2532,289 +2510,3 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
}
#endif
#ifdef __linux__
/* Futex-based SRW lock implementation:
*
* Since we can rely on the kernel to release all threads and don't need to
* worry about NtReleaseKeyedEvent(), we can simplify the layout a bit. The
* layout looks like this:
*
* 31 - Exclusive lock bit, set if the resource is owned exclusively.
* 30-16 - Number of exclusive waiters. Unlike the fallback implementation,
* this does not include the thread owning the lock, or shared threads
* waiting on the lock.
* 15 - Does this lock have any shared waiters? We use this as an
* optimization to avoid unnecessary FUTEX_WAKE_BITSET calls when
* releasing an exclusive lock.
* 14-0 - Number of shared owners. Unlike the fallback implementation, this
* does not include the number of shared threads waiting on the lock.
* Thus the state [1, x, >=1] will never occur.
*/
#define SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT 0x80000000
#define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK 0x7fff0000
#define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC 0x00010000
#define SRWLOCK_FUTEX_SHARED_WAITERS_BIT 0x00008000
#define SRWLOCK_FUTEX_SHARED_OWNERS_MASK 0x00007fff
#define SRWLOCK_FUTEX_SHARED_OWNERS_INC 0x00000001
/* Futex bitmasks; these are independent from the bits in the lock itself. */
#define SRWLOCK_FUTEX_BITSET_EXCLUSIVE 1
#define SRWLOCK_FUTEX_BITSET_SHARED 2
NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
{
int old, new, *futex;
NTSTATUS ret;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do
{
old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
{
/* Not locked exclusive or shared. We can try to grab it. */
new = old | SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
ret = STATUS_SUCCESS;
}
else
{
new = old;
ret = STATUS_TIMEOUT;
}
} while (InterlockedCompareExchange( futex, new, old ) != old);
return ret;
}
NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
{
int old, new, *futex;
BOOLEAN wait;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
/* Atomically increment the exclusive waiter count. */
do
{
old = *futex;
new = old + SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
} while (InterlockedCompareExchange( futex, new, old ) != old);
for (;;)
{
do
{
old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
{
/* Not locked exclusive or shared. We can try to grab it. */
new = old | SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
assert(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
new -= SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
wait = FALSE;
}
else
{
new = old;
wait = TRUE;
}
} while (InterlockedCompareExchange( futex, new, old ) != old);
if (!wait)
return STATUS_SUCCESS;
futex_wait_bitset( futex, new, NULL, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
}
return STATUS_SUCCESS;
}
NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
{
int new, old, *futex;
NTSTATUS ret;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do
{
old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
{
/* Not locked exclusive, and no exclusive waiters. We can try to
* grab it. */
new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
ret = STATUS_SUCCESS;
}
else
{
new = old;
ret = STATUS_TIMEOUT;
}
} while (InterlockedCompareExchange( futex, new, old ) != old);
return ret;
}
NTSTATUS CDECL fast_RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
{
int old, new, *futex;
BOOLEAN wait;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
for (;;)
{
do
{
old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
&& !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
{
/* Not locked exclusive, and no exclusive waiters. We can try
* to grab it. */
new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
wait = FALSE;
}
else
{
new = old | SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
wait = TRUE;
}
} while (InterlockedCompareExchange( futex, new, old ) != old);
if (!wait)
return STATUS_SUCCESS;
futex_wait_bitset( futex, new, NULL, SRWLOCK_FUTEX_BITSET_SHARED );
}
return STATUS_SUCCESS;
}
NTSTATUS CDECL fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
{
int old, new, *futex;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do
{
old = *futex;
if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT))
{
ERR("Lock %p is not owned exclusive! (%#x)\n", lock, *futex);
return STATUS_RESOURCE_NOT_OWNED;
}
new = old & ~SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
} while (InterlockedCompareExchange( futex, new, old ) != old);
if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)
futex_wake_bitset( futex, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
else if (old & SRWLOCK_FUTEX_SHARED_WAITERS_BIT)
futex_wake_bitset( futex, INT_MAX, SRWLOCK_FUTEX_BITSET_SHARED );
return STATUS_SUCCESS;
}
NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
{
int old, new, *futex;
if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
if (!(futex = get_futex( &lock->Ptr )))
return STATUS_NOT_IMPLEMENTED;
do
{
old = *futex;
if (old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
{
ERR("Lock %p is owned exclusive! (%#x)\n", lock, *futex);
return STATUS_RESOURCE_NOT_OWNED;
}
else if (!(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
{
ERR("Lock %p is not owned shared! (%#x)\n", lock, *futex);
return STATUS_RESOURCE_NOT_OWNED;
}
new = old - SRWLOCK_FUTEX_SHARED_OWNERS_INC;
} while (InterlockedCompareExchange( futex, new, old ) != old);
/* Optimization: only bother waking if there are actually exclusive waiters. */
if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
futex_wake_bitset( futex, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
return STATUS_SUCCESS;
}
#else
NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS CDECL fast_RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS CDECL fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
{
return STATUS_NOT_IMPLEMENTED;
}
#endif
......@@ -100,12 +100,6 @@ extern void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PT
extern void (WINAPI *pRtlUserThreadStart)( PRTL_THREAD_START_ROUTINE entry, void *arg ) DECLSPEC_HIDDEN;
extern void (WINAPI *p__wine_ctrl_routine)(void *) DECLSPEC_HIDDEN;
extern SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_RtlAcquireSRWLockShared( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) DECLSPEC_HIDDEN;
extern LONGLONG CDECL fast_RtlGetSystemTimePrecise(void) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL unwind_builtin_dll( ULONG type, struct _DISPATCHER_CONTEXT *dispatch,
......
......@@ -26,7 +26,7 @@
struct _DISPATCHER_CONTEXT;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 131
#define NTDLL_UNIXLIB_VERSION 132
struct unix_funcs
{
......@@ -38,14 +38,6 @@ struct unix_funcs
/* other Win32 API functions */
LONGLONG (WINAPI *RtlGetSystemTimePrecise)(void);
/* fast locks */
NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockExclusive)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlAcquireSRWLockExclusive)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockShared)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlAcquireSRWLockShared)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlReleaseSRWLockExclusive)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlReleaseSRWLockShared)( RTL_SRWLOCK *lock );
/* loader functions */
NTSTATUS (CDECL *load_so_dll)( UNICODE_STRING *nt_name, void **module );
void (CDECL *init_builtin_dll)( void *module );
......
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