ntdll: Move the futex-based SRW lock implementation to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4d70266274
commit
246dedaa09
|
@ -88,16 +88,6 @@ static inline int futex_wake( const int *addr, int val )
|
||||||
return syscall( __NR_futex, addr, FUTEX_WAKE | futex_private, val, NULL, 0, 0 );
|
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 inline int use_futexes(void)
|
||||||
{
|
{
|
||||||
static int supported = -1;
|
static int supported = -1;
|
||||||
|
@ -1191,291 +1181,6 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu
|
||||||
return RtlRunOnceComplete( once, 0, context ? *context : NULL );
|
return RtlRunOnceComplete( once, 0, context ? *context : NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
static NTSTATUS fast_try_acquire_srw_exclusive( 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_acquire_srw_exclusive( 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_try_acquire_srw_shared( 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_acquire_srw_shared( 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_release_srw_exclusive( 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_release_srw_shared( 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
|
|
||||||
|
|
||||||
static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock )
|
|
||||||
{
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock )
|
|
||||||
{
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock )
|
|
||||||
{
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock )
|
|
||||||
{
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock )
|
|
||||||
{
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NTSTATUS fast_release_srw_shared( RTL_SRWLOCK *lock )
|
|
||||||
{
|
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* SRW locks implementation
|
/* SRW locks implementation
|
||||||
*
|
*
|
||||||
|
@ -1623,7 +1328,7 @@ void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
|
||||||
*/
|
*/
|
||||||
void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
|
void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
|
||||||
{
|
{
|
||||||
if (fast_acquire_srw_exclusive( lock ) != STATUS_NOT_IMPLEMENTED)
|
if (unix_funcs->fast_RtlAcquireSRWLockExclusive( lock ) != STATUS_NOT_IMPLEMENTED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
|
if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
|
||||||
|
@ -1641,7 +1346,7 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
|
||||||
{
|
{
|
||||||
unsigned int val, tmp;
|
unsigned int val, tmp;
|
||||||
|
|
||||||
if (fast_acquire_srw_shared( lock ) != STATUS_NOT_IMPLEMENTED)
|
if (unix_funcs->fast_RtlAcquireSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Acquires a shared lock. If it's currently not possible to add elements to
|
/* Acquires a shared lock. If it's currently not possible to add elements to
|
||||||
|
@ -1674,7 +1379,7 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
|
||||||
*/
|
*/
|
||||||
void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
|
void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
|
||||||
{
|
{
|
||||||
if (fast_release_srw_exclusive( lock ) != STATUS_NOT_IMPLEMENTED)
|
if (unix_funcs->fast_RtlReleaseSRWLockExclusive( lock ) != STATUS_NOT_IMPLEMENTED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
|
srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
|
||||||
|
@ -1686,7 +1391,7 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
|
||||||
*/
|
*/
|
||||||
void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
|
void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
|
||||||
{
|
{
|
||||||
if (fast_release_srw_shared( lock ) != STATUS_NOT_IMPLEMENTED)
|
if (unix_funcs->fast_RtlReleaseSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
|
srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
|
||||||
|
@ -1704,7 +1409,7 @@ BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
|
||||||
{
|
{
|
||||||
NTSTATUS ret;
|
NTSTATUS ret;
|
||||||
|
|
||||||
if ((ret = fast_try_acquire_srw_exclusive( lock )) != STATUS_NOT_IMPLEMENTED)
|
if ((ret = unix_funcs->fast_RtlTryAcquireSRWLockExclusive( lock )) != STATUS_NOT_IMPLEMENTED)
|
||||||
return (ret == STATUS_SUCCESS);
|
return (ret == STATUS_SUCCESS);
|
||||||
|
|
||||||
return InterlockedCompareExchange( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
|
return InterlockedCompareExchange( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
|
||||||
|
@ -1719,7 +1424,7 @@ BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
|
||||||
unsigned int val, tmp;
|
unsigned int val, tmp;
|
||||||
NTSTATUS ret;
|
NTSTATUS ret;
|
||||||
|
|
||||||
if ((ret = fast_try_acquire_srw_shared( lock )) != STATUS_NOT_IMPLEMENTED)
|
if ((ret = unix_funcs->fast_RtlTryAcquireSRWLockShared( lock )) != STATUS_NOT_IMPLEMENTED)
|
||||||
return (ret == STATUS_SUCCESS);
|
return (ret == STATUS_SUCCESS);
|
||||||
|
|
||||||
for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
|
for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
|
||||||
|
|
|
@ -1046,6 +1046,12 @@ static struct unix_funcs unix_funcs =
|
||||||
NtWriteVirtualMemory,
|
NtWriteVirtualMemory,
|
||||||
NtYieldExecution,
|
NtYieldExecution,
|
||||||
DbgUiIssueRemoteBreakin,
|
DbgUiIssueRemoteBreakin,
|
||||||
|
fast_RtlTryAcquireSRWLockExclusive,
|
||||||
|
fast_RtlAcquireSRWLockExclusive,
|
||||||
|
fast_RtlTryAcquireSRWLockShared,
|
||||||
|
fast_RtlAcquireSRWLockShared,
|
||||||
|
fast_RtlReleaseSRWLockExclusive,
|
||||||
|
fast_RtlReleaseSRWLockShared,
|
||||||
get_main_args,
|
get_main_args,
|
||||||
get_paths,
|
get_paths,
|
||||||
get_dll_path,
|
get_dll_path,
|
||||||
|
|
|
@ -70,6 +70,64 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync);
|
||||||
|
|
||||||
HANDLE keyed_event = 0;
|
HANDLE keyed_event = 0;
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#define FUTEX_WAIT 0
|
||||||
|
#define FUTEX_WAKE 1
|
||||||
|
#define FUTEX_WAIT_BITSET 9
|
||||||
|
#define FUTEX_WAKE_BITSET 10
|
||||||
|
|
||||||
|
static int futex_private = 128;
|
||||||
|
|
||||||
|
static inline int futex_wait( const int *addr, int val, struct timespec *timeout )
|
||||||
|
{
|
||||||
|
return syscall( __NR_futex, addr, FUTEX_WAIT | futex_private, val, timeout, 0, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (supported == -1)
|
||||||
|
{
|
||||||
|
futex_wait( &supported, 10, NULL );
|
||||||
|
if (errno == ENOSYS)
|
||||||
|
{
|
||||||
|
futex_private = 0;
|
||||||
|
futex_wait( &supported, 10, NULL );
|
||||||
|
}
|
||||||
|
supported = (errno != ENOSYS);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
/* create a struct security_descriptor and contained information in one contiguous piece of memory */
|
/* create a struct security_descriptor and contained information in one contiguous piece of memory */
|
||||||
NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
|
NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
|
||||||
|
@ -948,3 +1006,290 @@ NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
|
@ -57,6 +57,13 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
|
||||||
NTSTATUS WINAPI KiUserExceptionDispatcher(EXCEPTION_RECORD*,CONTEXT*);
|
NTSTATUS WINAPI KiUserExceptionDispatcher(EXCEPTION_RECORD*,CONTEXT*);
|
||||||
void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR);
|
void WINAPI LdrInitializeThunk(CONTEXT*,void**,ULONG_PTR,ULONG_PTR);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
void CDECL mmap_add_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
void CDECL mmap_add_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
void CDECL mmap_remove_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
void CDECL mmap_remove_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct ldt_copy;
|
||||||
struct msghdr;
|
struct msghdr;
|
||||||
|
|
||||||
/* increment this when you change the function table */
|
/* increment this when you change the function table */
|
||||||
#define NTDLL_UNIXLIB_VERSION 34
|
#define NTDLL_UNIXLIB_VERSION 35
|
||||||
|
|
||||||
struct unix_funcs
|
struct unix_funcs
|
||||||
{
|
{
|
||||||
|
@ -144,6 +144,14 @@ struct unix_funcs
|
||||||
/* other Win32 API functions */
|
/* other Win32 API functions */
|
||||||
NTSTATUS (WINAPI *DbgUiIssueRemoteBreakin)( HANDLE process );
|
NTSTATUS (WINAPI *DbgUiIssueRemoteBreakin)( HANDLE process );
|
||||||
|
|
||||||
|
/* 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 );
|
||||||
|
|
||||||
/* environment functions */
|
/* environment functions */
|
||||||
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
|
void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );
|
||||||
void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir );
|
void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir );
|
||||||
|
|
Loading…
Reference in New Issue