Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/unix/sync.c | 75 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 59fe6bea8f5..cdc63c8a6ef 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2341,10 +2341,14 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl
union tid_alert_entry { +#ifdef __APPLE__ + semaphore_t sem; +#else HANDLE event; #ifdef __linux__ int futex; #endif +#endif };
#define TID_ALERT_BLOCK_SIZE (65536 / sizeof(union tid_alert_entry)) @@ -2379,6 +2383,17 @@ static union tid_alert_entry *get_tid_alert_entry( HANDLE tid )
entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE];
+#ifdef __APPLE__ + if (!entry->sem) + { + semaphore_t sem; + + if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) + return NULL; + if (InterlockedCompareExchange( (int *)&entry->sem, sem, NULL )) + semaphore_destroy( mach_task_self(), sem ); + } +#else #ifdef __linux__ if (use_futexes()) return entry; @@ -2393,6 +2408,7 @@ static union tid_alert_entry *get_tid_alert_entry( HANDLE tid ) if (InterlockedCompareExchangePointer( &entry->event, event, NULL )) NtClose( event ); } +#endif
return entry; } @@ -2409,6 +2425,10 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid )
if (!entry) return STATUS_INVALID_CID;
+#ifdef __APPLE__ + semaphore_signal( entry->sem ); + return STATUS_SUCCESS; +#else #ifdef __linux__ if (use_futexes()) { @@ -2420,10 +2440,11 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid ) #endif
return NtSetEvent( entry->event, NULL ); +#endif }
-#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) static LONGLONG get_absolute_timeout( const LARGE_INTEGER *timeout ) { LARGE_INTEGER now; @@ -2446,6 +2467,57 @@ static LONGLONG update_timeout( ULONGLONG end ) #endif
+#ifdef __APPLE__ + +/*********************************************************************** + * NtWaitForAlertByThreadId (NTDLL.@) + */ +NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout ) +{ + union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread ); + semaphore_t sem; + ULONGLONG end; + kern_return_t ret; + + TRACE( "%p %s\n", address, debugstr_timeout( timeout ) ); + + if (!entry) return STATUS_INVALID_CID; + sem = entry->sem; + + if (timeout) + { + if (timeout->QuadPart == TIMEOUT_INFINITE) + timeout = NULL; + else + end = get_absolute_timeout( timeout ); + } + + for (;;) + { + if (timeout) + { + LONGLONG timeleft = update_timeout( end ); + mach_timespec_t timespec; + + timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100; + ret = semaphore_timedwait( sem, timespec ); + } + else + ret = semaphore_wait( sem ); + + switch (ret) + { + case KERN_SUCCESS: return STATUS_ALERTED; + case KERN_ABORTED: continue; + case KERN_OPERATION_TIMED_OUT: return STATUS_TIMEOUT; + default: return STATUS_INVALID_HANDLE; + } + } +} + +#else + /*********************************************************************** * NtWaitForAlertByThreadId (NTDLL.@) */ @@ -2498,6 +2570,7 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG return status; }
+#endif
#ifdef __linux__
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/sync.c | 175 ++++++++++++++++++++++++++++++++++++++- dlls/ntdll/unix/loader.c | 3 - dlls/ntdll/unix/sync.c | 162 ------------------------------------ dlls/ntdll/unixlib.h | 6 +- 4 files changed, 173 insertions(+), 173 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index bfb30661864..78c68ddbe38 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -34,11 +34,18 @@ #include "windef.h" #include "winternl.h" #include "wine/debug.h" +#include "wine/list.h" #include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(sync); WINE_DECLARE_DEBUG_CHANNEL(relay);
+static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) +{ + if (!timeout) return "(infinite)"; + return wine_dbgstr_longlong( timeout->QuadPart ); +} + /****************************************************************** * RtlRunOnceInitialize (NTDLL.@) */ @@ -863,13 +870,113 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, return status; }
+/* RtlWaitOnAddress() and RtlWakeAddress*(), hereafter referred to as "Win32 + * futexes", offer futex-like semantics with a variable set of address sizes, + * but are limited to a single process. They are also fair—the documentation + * specifies this, and tests bear it out. + * + * On Windows they are implemented using NtAlertThreadByThreadId and + * NtWaitForAlertByThreadId, which manipulate a single flag (similar to an + * auto-reset event) per thread. This can be tested by attempting to wake a + * thread waiting in RtlWaitOnAddress() via NtAlertThreadByThreadId. + */ + +struct futex_entry +{ + struct list entry; + const void *addr; + DWORD tid; +}; + +struct futex_queue +{ + struct list queue; + LONG lock; +}; + +static struct futex_queue futex_queues[256]; + +static struct futex_queue *get_futex_queue( const void *addr ) +{ + ULONG_PTR val = (ULONG_PTR)addr; + + return &futex_queues[(val >> 4) % ARRAY_SIZE(futex_queues)]; +} + +static void spin_lock( LONG *lock ) +{ + while (InterlockedCompareExchange( lock, -1, 0 )) + YieldProcessor(); +} + +static void spin_unlock( LONG *lock ) +{ + InterlockedExchange( lock, 0 ); +} + +static BOOL compare_addr( const void *addr, const void *cmp, SIZE_T size ) +{ + switch (size) + { + case 1: + return (*(const UCHAR *)addr == *(const UCHAR *)cmp); + case 2: + return (*(const USHORT *)addr == *(const USHORT *)cmp); + case 4: + return (*(const ULONG *)addr == *(const ULONG *)cmp); + case 8: + return (*(const ULONG64 *)addr == *(const ULONG64 *)cmp); + } + + return FALSE; +} + /*********************************************************************** * RtlWaitOnAddress (NTDLL.@) */ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size, const LARGE_INTEGER *timeout ) { - return unix_funcs->RtlWaitOnAddress( addr, cmp, size, timeout ); + struct futex_queue *queue = get_futex_queue( addr ); + struct futex_entry entry; + NTSTATUS ret; + + TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout )); + + if (size != 1 && size != 2 && size != 4 && size != 8) + return STATUS_INVALID_PARAMETER; + + entry.addr = addr; + entry.tid = GetCurrentThreadId(); + + spin_lock( &queue->lock ); + + /* Do the comparison inside of the spinlock, to reduce spurious wakeups. */ + + if (!compare_addr( addr, cmp, size )) + { + spin_unlock( &queue->lock ); + return STATUS_SUCCESS; + } + + if (!queue->queue.next) + list_init( &queue->queue ); + list_add_tail( &queue->queue, &entry.entry ); + + spin_unlock( &queue->lock ); + + ret = NtWaitForAlertByThreadId( NULL, timeout ); + + spin_lock( &queue->lock ); + /* We may have already been removed by a call to RtlWakeAddressSingle(). */ + if (entry.addr) + list_remove( &entry.entry ); + spin_unlock( &queue->lock ); + + TRACE("returning %#x\n", ret); + + if (ret == STATUS_ALERTED) ret = STATUS_SUCCESS; + return ret; }
/*********************************************************************** @@ -877,7 +984,37 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size */ void WINAPI RtlWakeAddressAll( const void *addr ) { - return unix_funcs->RtlWakeAddressAll( addr ); + struct futex_queue *queue = get_futex_queue( addr ); + unsigned int count = 0, i; + struct futex_entry *entry; + DWORD tids[256]; + + TRACE("%p\n", addr); + + if (!addr) return; + + spin_lock( &queue->lock ); + + if (!queue->queue.next) + list_init(&queue->queue); + + LIST_FOR_EACH_ENTRY( entry, &queue->queue, struct futex_entry, entry ) + { + if (entry->addr == addr) + { + /* Try to buffer wakes, so that we don't make a system call while + * holding a spinlock. */ + if (count < ARRAY_SIZE(tids)) + tids[count++] = entry->tid; + else + NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)entry->tid ); + } + } + + spin_unlock( &queue->lock ); + + for (i = 0; i < count; ++i) + NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)tids[i] ); }
/*********************************************************************** @@ -885,5 +1022,37 @@ void WINAPI RtlWakeAddressAll( const void *addr ) */ void WINAPI RtlWakeAddressSingle( const void *addr ) { - return unix_funcs->RtlWakeAddressSingle( addr ); + struct futex_queue *queue = get_futex_queue( addr ); + struct futex_entry *entry; + DWORD tid = 0; + + TRACE("%p\n", addr); + + if (!addr) return; + + spin_lock( &queue->lock ); + + if (!queue->queue.next) + list_init(&queue->queue); + + LIST_FOR_EACH_ENTRY( entry, &queue->queue, struct futex_entry, entry ) + { + if (entry->addr == addr) + { + /* Try to buffer wakes, so that we don't make a system call while + * holding a spinlock. */ + tid = entry->tid; + + /* Remove this entry from the queue, so that a simultaneous call to + * RtlWakeAddressSingle() will not also wake it—two simultaneous + * calls must wake at least two waiters if they exist. */ + entry->addr = NULL; + list_remove( &entry->entry ); + break; + } + } + + spin_unlock( &queue->lock ); + + if (tid) NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)tid ); } diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 7f36dc42579..05ae264297a 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2145,9 +2145,6 @@ static struct unix_funcs unix_funcs = NtCurrentTeb, #endif RtlGetSystemTimePrecise, - RtlWaitOnAddress, - RtlWakeAddressAll, - RtlWakeAddressSingle, fast_RtlpWaitForCriticalSection, fast_RtlpUnWaitCriticalSection, fast_RtlDeleteCriticalSection, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index cdc63c8a6ef..47a0a03b45f 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -73,10 +73,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync);
HANDLE keyed_event = 0;
-static const LARGE_INTEGER zero_timeout; - -static pthread_mutex_t addr_mutex = PTHREAD_MUTEX_INITIALIZER; - static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) { if (!timeout) return "(infinite)"; @@ -186,24 +182,6 @@ static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGE #endif
-static BOOL compare_addr( const void *addr, const void *cmp, SIZE_T size ) -{ - switch (size) - { - case 1: - return (*(const UCHAR *)addr == *(const UCHAR *)cmp); - case 2: - return (*(const USHORT *)addr == *(const USHORT *)cmp); - case 4: - return (*(const ULONG *)addr == *(const ULONG *)cmp); - case 8: - return (*(const ULONG64 *)addr == *(const ULONG64 *)cmp); - } - - return FALSE; -} - - /* 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, data_size_t *ret_len ) @@ -2977,71 +2955,6 @@ NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, return STATUS_SUCCESS; }
- -/* We can't map addresses to futex directly, because an application can wait on - * 8 bytes, and we can't pass all 8 as the compare value to futex(). Instead we - * map all addresses to a small fixed table of futexes. This may result in - * spurious wakes, but the application is already expected to handle those. */ - -static int addr_futex_table[256]; - -static inline int *hash_addr( const void *addr ) -{ - ULONG_PTR val = (ULONG_PTR)addr; - - return &addr_futex_table[(val >> 2) & 255]; -} - -static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T size, - const LARGE_INTEGER *timeout ) -{ - int *futex; - int val; - struct timespec timespec; - int ret; - - if (!use_futexes()) - return STATUS_NOT_IMPLEMENTED; - - futex = hash_addr( addr ); - - /* We must read the previous value of the futex before checking the value - * of the address being waited on. That way, if we receive a wake between - * now and waiting on the futex, we know that val will have changed. - * Use an atomic load so that memory accesses are ordered between this read - * and the increment below. */ - val = InterlockedCompareExchange( futex, 0, 0 ); - if (!compare_addr( addr, cmp, size )) - return STATUS_SUCCESS; - - if (timeout) - { - timespec_from_timeout( ×pec, timeout ); - ret = futex_wait( futex, val, ×pec ); - } - else - ret = futex_wait( futex, val, NULL ); - - if (ret == -1 && errno == ETIMEDOUT) - return STATUS_TIMEOUT; - return STATUS_SUCCESS; -} - -static inline NTSTATUS fast_wake_addr( const void *addr ) -{ - int *futex; - - if (!use_futexes()) - return STATUS_NOT_IMPLEMENTED; - - futex = hash_addr( addr ); - - InterlockedIncrement( futex ); - - futex_wake( futex, INT_MAX ); - return STATUS_SUCCESS; -} - #else
NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) @@ -3084,79 +2997,4 @@ NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value return STATUS_NOT_IMPLEMENTED; }
-static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T size, - const LARGE_INTEGER *timeout ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -static inline NTSTATUS fast_wake_addr( const void *addr ) -{ - return STATUS_NOT_IMPLEMENTED; -} - #endif - - -/*********************************************************************** - * RtlWaitOnAddress (NTDLL.@) - */ -NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size, - const LARGE_INTEGER *timeout ) -{ - select_op_t select_op; - NTSTATUS ret; - timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; - - if (size != 1 && size != 2 && size != 4 && size != 8) - return STATUS_INVALID_PARAMETER; - - if ((ret = fast_wait_addr( addr, cmp, size, timeout )) != STATUS_NOT_IMPLEMENTED) - return ret; - - mutex_lock( &addr_mutex ); - if (!compare_addr( addr, cmp, size )) - { - mutex_unlock( &addr_mutex ); - return STATUS_SUCCESS; - } - - if (abs_timeout < 0) - { - LARGE_INTEGER now; - - NtQueryPerformanceCounter( &now, NULL ); - abs_timeout -= now.QuadPart; - } - - select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT; - select_op.keyed_event.handle = wine_server_obj_handle( keyed_event ); - select_op.keyed_event.key = wine_server_client_ptr( addr ); - - return server_select( &select_op, sizeof(select_op.keyed_event), SELECT_INTERRUPTIBLE, - abs_timeout, NULL, &addr_mutex, NULL ); -} - -/*********************************************************************** - * RtlWakeAddressAll (NTDLL.@) - */ -void WINAPI RtlWakeAddressAll( const void *addr ) -{ - if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED) return; - - mutex_lock( &addr_mutex ); - while (NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout ) == STATUS_SUCCESS) {} - mutex_unlock( &addr_mutex ); -} - -/*********************************************************************** - * RtlWakeAddressSingle (NTDLL.@) - */ -void WINAPI RtlWakeAddressSingle( const void *addr ) -{ - if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED) return; - - mutex_lock( &addr_mutex ); - NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout ); - mutex_unlock( &addr_mutex ); -} diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 62030d91cdb..ded05c40e17 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -26,7 +26,7 @@ struct _DISPATCHER_CONTEXT;
/* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 128 +#define NTDLL_UNIXLIB_VERSION 129
struct unix_funcs { @@ -37,10 +37,6 @@ struct unix_funcs
/* other Win32 API functions */ LONGLONG (WINAPI *RtlGetSystemTimePrecise)(void); - NTSTATUS (WINAPI *RtlWaitOnAddress)( const void *addr, const void *cmp, SIZE_T size, - const LARGE_INTEGER *timeout ); - void (WINAPI *RtlWakeAddressAll)( const void *addr ); - void (WINAPI *RtlWakeAddressSingle)( const void *addr );
/* fast locks */ NTSTATUS (CDECL *fast_RtlpWaitForCriticalSection)( RTL_CRITICAL_SECTION *crit, int timeout );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/sync.c | 35 +++++++---- dlls/ntdll/unix/loader.c | 3 - dlls/ntdll/unix/sync.c | 109 --------------------------------- dlls/ntdll/unix/unix_private.h | 4 -- dlls/ntdll/unixlib.h | 5 +- 5 files changed, 24 insertions(+), 132 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 78c68ddbe38..34b804b1463 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -172,19 +172,26 @@ static inline HANDLE get_semaphore( RTL_CRITICAL_SECTION *crit )
static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout ) { - NTSTATUS ret; + LARGE_INTEGER time = {.QuadPart = timeout * (LONGLONG)-10000000};
/* debug info is cleared by MakeCriticalSectionGlobal */ - if (!crit_section_has_debuginfo( crit ) || - ((ret = unix_funcs->fast_RtlpWaitForCriticalSection( crit, timeout )) == STATUS_NOT_IMPLEMENTED)) + if (!crit_section_has_debuginfo( crit )) { HANDLE sem = get_semaphore( crit ); - LARGE_INTEGER time; - - time.QuadPart = timeout * (LONGLONG)-10000000; - ret = NtWaitForSingleObject( sem, FALSE, &time ); + return NtWaitForSingleObject( sem, FALSE, &time ); + } + else + { + int *lock = (int *)&crit->LockSemaphore; + while (!InterlockedCompareExchange( lock, 0, 1 )) + { + static const int zero; + /* this may wait longer than specified in case of multiple wake-ups */ + if (RtlWaitOnAddress( lock, &zero, sizeof(int), &time ) == STATUS_TIMEOUT) + return STATUS_TIMEOUT; + } + return STATUS_WAIT_0; } - return ret; }
/****************************************************************************** @@ -274,8 +281,6 @@ NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo ); crit->DebugInfo = NULL; } - if (unix_funcs->fast_RtlDeleteCriticalSection( crit ) == STATUS_NOT_IMPLEMENTED) - NtClose( crit->LockSemaphore ); } else NtClose( crit->LockSemaphore ); crit->LockSemaphore = 0; @@ -351,12 +356,18 @@ NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) NTSTATUS ret;
/* debug info is cleared by MakeCriticalSectionGlobal */ - if (!crit_section_has_debuginfo( crit ) || - ((ret = unix_funcs->fast_RtlpUnWaitCriticalSection( crit )) == STATUS_NOT_IMPLEMENTED)) + if (!crit_section_has_debuginfo( crit )) { HANDLE sem = get_semaphore( crit ); ret = NtReleaseSemaphore( sem, 1, NULL ); } + else + { + int *lock = (int *)&crit->LockSemaphore; + InterlockedExchange( lock, 1 ); + RtlWakeAddressSingle( lock ); + ret = STATUS_SUCCESS; + } if (ret) RtlRaiseStatus( ret ); return ret; } diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 05ae264297a..1dbcc0d7a7b 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2145,9 +2145,6 @@ static struct unix_funcs unix_funcs = NtCurrentTeb, #endif RtlGetSystemTimePrecise, - fast_RtlpWaitForCriticalSection, - fast_RtlpUnWaitCriticalSection, - fast_RtlDeleteCriticalSection, fast_RtlTryAcquireSRWLockExclusive, fast_RtlAcquireSRWLockExclusive, fast_RtlTryAcquireSRWLockShared, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 47a0a03b45f..12df0c90d73 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2550,115 +2550,6 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
#endif
-#ifdef __linux__ - -NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - int val; - struct timespec timespec; - - if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; - - timespec.tv_sec = timeout; - timespec.tv_nsec = 0; - while ((val = InterlockedCompareExchange( (int *)&crit->LockSemaphore, 0, 1 )) != 1) - { - /* note: this may wait longer than specified in case of signals or */ - /* multiple wake-ups, but that shouldn't be a problem */ - if (futex_wait( (int *)&crit->LockSemaphore, val, ×pec ) == -1 && errno == ETIMEDOUT) - return STATUS_TIMEOUT; - } - return STATUS_WAIT_0; -} - -NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; - - *(int *)&crit->LockSemaphore = 1; - futex_wake( (int *)&crit->LockSemaphore, 1 ); - return STATUS_SUCCESS; -} - -NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; - return STATUS_SUCCESS; -} - -#elif defined(__APPLE__) - -static inline semaphore_t get_mach_semaphore( RTL_CRITICAL_SECTION *crit ) -{ - semaphore_t ret = *(int *)&crit->LockSemaphore; - if (!ret) - { - semaphore_t sem; - if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) return 0; - if (!(ret = InterlockedCompareExchange( (int *)&crit->LockSemaphore, sem, 0 ))) - ret = sem; - else - semaphore_destroy( mach_task_self(), sem ); /* somebody beat us to it */ - } - return ret; -} - -NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - mach_timespec_t timespec; - semaphore_t sem = get_mach_semaphore( crit ); - - timespec.tv_sec = timeout; - timespec.tv_nsec = 0; - for (;;) - { - switch( semaphore_timedwait( sem, timespec )) - { - case KERN_SUCCESS: - return STATUS_WAIT_0; - case KERN_ABORTED: - continue; /* got a signal, restart */ - case KERN_OPERATION_TIMED_OUT: - return STATUS_TIMEOUT; - default: - return STATUS_INVALID_HANDLE; - } - } -} - -NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - semaphore_t sem = get_mach_semaphore( crit ); - semaphore_signal( sem ); - return STATUS_SUCCESS; -} - -NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - semaphore_destroy( mach_task_self(), *(int *)&crit->LockSemaphore ); - return STATUS_SUCCESS; -} - -#else /* __APPLE__ */ - -NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -#endif - - #ifdef __linux__
/* Futex-based SRW lock implementation: diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 641de0c465f..d44a9e128ff 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -100,10 +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_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) DECLSPEC_HIDDEN; -extern NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit ) DECLSPEC_HIDDEN; -extern NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit ) 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; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index ded05c40e17..535f76a647e 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -26,7 +26,7 @@ struct _DISPATCHER_CONTEXT;
/* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 129 +#define NTDLL_UNIXLIB_VERSION 130
struct unix_funcs { @@ -39,9 +39,6 @@ struct unix_funcs LONGLONG (WINAPI *RtlGetSystemTimePrecise)(void);
/* fast locks */ - NTSTATUS (CDECL *fast_RtlpWaitForCriticalSection)( RTL_CRITICAL_SECTION *crit, int timeout ); - NTSTATUS (CDECL *fast_RtlpUnWaitCriticalSection)( RTL_CRITICAL_SECTION *crit ); - NTSTATUS (CDECL *fast_RtlDeleteCriticalSection)( RTL_CRITICAL_SECTION *crit ); NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockExclusive)( RTL_SRWLOCK *lock ); NTSTATUS (CDECL *fast_RtlAcquireSRWLockExclusive)( RTL_SRWLOCK *lock ); NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockShared)( RTL_SRWLOCK *lock );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/sync.c | 24 ++++-------- dlls/ntdll/unix/loader.c | 2 - dlls/ntdll/unix/sync.c | 71 ---------------------------------- dlls/ntdll/unix/unix_private.h | 3 -- dlls/ntdll/unixlib.h | 5 +-- 5 files changed, 9 insertions(+), 96 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 34b804b1463..4ceadebf0e7 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -792,11 +792,8 @@ void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable ) */ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) { - if (unix_funcs->fast_RtlWakeConditionVariable( variable, 1 ) == STATUS_NOT_IMPLEMENTED) - { - InterlockedIncrement( (int *)&variable->Ptr ); - RtlWakeAddressSingle( variable ); - } + InterlockedIncrement( (int *)&variable->Ptr ); + RtlWakeAddressSingle( variable ); }
/*********************************************************************** @@ -806,11 +803,8 @@ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) */ void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable ) { - if (unix_funcs->fast_RtlWakeConditionVariable( variable, INT_MAX ) == STATUS_NOT_IMPLEMENTED) - { - InterlockedIncrement( (int *)&variable->Ptr ); - RtlWakeAddressAll( variable ); - } + InterlockedIncrement( (int *)&variable->Ptr ); + RtlWakeAddressAll( variable ); }
/*********************************************************************** @@ -831,12 +825,11 @@ void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable ) NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit, const LARGE_INTEGER *timeout ) { - const void *value = variable->Ptr; + int value = *(int *)&variable->Ptr; NTSTATUS status;
RtlLeaveCriticalSection( crit ); - if ((status = unix_funcs->fast_wait_cv( variable, value, timeout )) == STATUS_NOT_IMPLEMENTED) - status = RtlWaitOnAddress( &variable->Ptr, &value, sizeof(value), timeout ); + status = RtlWaitOnAddress( &variable->Ptr, &value, sizeof(value), timeout ); RtlEnterCriticalSection( crit ); return status; } @@ -863,7 +856,7 @@ NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, R NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock, const LARGE_INTEGER *timeout, ULONG flags ) { - const void *value = variable->Ptr; + int value = *(int *)&variable->Ptr; NTSTATUS status;
if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) @@ -871,8 +864,7 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, else RtlReleaseSRWLockExclusive( lock );
- if ((status = unix_funcs->fast_wait_cv( variable, value, timeout )) == STATUS_NOT_IMPLEMENTED) - status = RtlWaitOnAddress( variable, &value, sizeof(value), timeout ); + status = RtlWaitOnAddress( &variable->Ptr, &value, sizeof(value), timeout );
if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) RtlAcquireSRWLockShared( lock ); diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 1dbcc0d7a7b..32aa7267423 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2151,8 +2151,6 @@ static struct unix_funcs unix_funcs = fast_RtlAcquireSRWLockShared, fast_RtlReleaseSRWLockExclusive, fast_RtlReleaseSRWLockShared, - fast_RtlWakeConditionVariable, - fast_wait_cv, load_so_dll, init_builtin_dll, init_unix_lib, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 12df0c90d73..7a2466f5fa3 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -162,23 +162,6 @@ static int *get_futex(void **ptr) return NULL; }
-static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGER *timeout ) -{ - LARGE_INTEGER now; - timeout_t diff; - - if (timeout->QuadPart > 0) - { - NtQuerySystemTime( &now ); - diff = timeout->QuadPart - now.QuadPart; - } - else - diff = -timeout->QuadPart; - - timespec->tv_sec = diff / TICKSPERSEC; - timespec->tv_nsec = (diff % TICKSPERSEC) * 100; -} - #endif
@@ -2802,50 +2785,6 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) return STATUS_SUCCESS; }
-NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value, const LARGE_INTEGER *timeout ) -{ - const char *value_ptr; - int aligned_value, *futex; - struct timespec timespec; - int ret; - - if (!use_futexes()) - return STATUS_NOT_IMPLEMENTED; - - if (!(futex = get_futex( &variable->Ptr ))) - return STATUS_NOT_IMPLEMENTED; - - value_ptr = (const char *)&value; - value_ptr += ((ULONG_PTR)futex) - ((ULONG_PTR)&variable->Ptr); - aligned_value = *(int *)value_ptr; - - if (timeout && timeout->QuadPart != TIMEOUT_INFINITE) - { - timespec_from_timeout( ×pec, timeout ); - ret = futex_wait( futex, aligned_value, ×pec ); - } - else - ret = futex_wait( futex, aligned_value, NULL ); - - if (ret == -1 && errno == ETIMEDOUT) - return STATUS_TIMEOUT; - return STATUS_WAIT_0; -} - -NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count ) -{ - int *futex; - - if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; - - if (!(futex = get_futex( &variable->Ptr ))) - return STATUS_NOT_IMPLEMENTED; - - InterlockedIncrement( futex ); - futex_wake( futex, count ); - return STATUS_SUCCESS; -} - #else
NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) @@ -2878,14 +2817,4 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) return STATUS_NOT_IMPLEMENTED; }
-NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value, const LARGE_INTEGER *timeout ) -{ - return STATUS_NOT_IMPLEMENTED; -} - #endif diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index d44a9e128ff..61f37d4b22f 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -106,10 +106,7 @@ extern NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock ) DECLS 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 NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count ) DECLSPEC_HIDDEN; extern LONGLONG CDECL fast_RtlGetSystemTimePrecise(void) DECLSPEC_HIDDEN; -extern NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value, - const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL unwind_builtin_dll( ULONG type, struct _DISPATCHER_CONTEXT *dispatch, CONTEXT *context ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 535f76a647e..a271bb05da9 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -26,7 +26,7 @@ struct _DISPATCHER_CONTEXT;
/* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 130 +#define NTDLL_UNIXLIB_VERSION 131
struct unix_funcs { @@ -45,9 +45,6 @@ struct unix_funcs NTSTATUS (CDECL *fast_RtlAcquireSRWLockShared)( RTL_SRWLOCK *lock ); NTSTATUS (CDECL *fast_RtlReleaseSRWLockExclusive)( RTL_SRWLOCK *lock ); NTSTATUS (CDECL *fast_RtlReleaseSRWLockShared)( RTL_SRWLOCK *lock ); - NTSTATUS (CDECL *fast_RtlWakeConditionVariable)( RTL_CONDITION_VARIABLE *variable, int count ); - NTSTATUS (CDECL *fast_wait_cv)( RTL_CONDITION_VARIABLE *variable, const void *value, - const LARGE_INTEGER *timeout );
/* loader functions */ NTSTATUS (CDECL *load_so_dll)( UNICODE_STRING *nt_name, void **module );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/sync.c | 313 +++++++++++++++------------------ dlls/ntdll/unix/loader.c | 6 - dlls/ntdll/unix/sync.c | 308 -------------------------------- dlls/ntdll/unix/unix_private.h | 6 - dlls/ntdll/unixlib.h | 10 +- 5 files changed, 142 insertions(+), 501 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 4ceadebf0e7..bdb39e59d6d 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -503,127 +503,24 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu return RtlRunOnceComplete( once, 0, context ? *context : NULL ); }
- -/* SRW locks implementation - * - * The memory layout used by the lock is: - * - * 32 31 16 0 - * ________________ ________________ - * | X| #exclusive | #shared | - * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ - * Since there is no space left for a separate counter of shared access - * threads inside the locked section the #shared field is used for multiple - * purposes. The following table lists all possible states the lock can be - * in, notation: [X, #exclusive, #shared]: - * - * [0, 0, N] -> locked by N shared access threads, if N=0 it's unlocked - * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are - * still shared access threads inside. #shared should not be incremented - * anymore! - * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared - * counter can be used again to count the number of threads waiting in the - * queue for shared access. - * - * the following states are invalid and will never occur: - * [0, >=1, 0], [1, 0, >=0] - * - * The main problem arising from the fact that we have no separate counter - * of shared access threads inside the locked section is that in the state - * [0, >=1, >=1] above we cannot add additional waiting threads to the - * shared access queue - it wouldn't be possible to distinguish waiting - * threads and those that are still inside. To solve this problem the lock - * uses the following approach: a thread that isn't able to allocate a - * shared lock just uses the exclusive queue instead. As soon as the thread - * is woken up it is in the state [1, >=1, >=0]. In this state it's again - * possible to use the shared access queue. The thread atomically moves - * itself to the shared access queue and releases the exclusive lock, so - * that the "real" exclusive access threads have a chance. As soon as they - * are all ready the shared access threads are processed. - */ - -#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) ((void *)(((ULONG_PTR)&lock->Ptr + 1) & ~1)) -#define srwlock_key_shared(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 3) & ~1)) -#else -#define srwlock_key_exclusive(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 3) & ~1)) -#define srwlock_key_shared(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 1) & ~1)) -#endif - -static inline void srwlock_check_invalid( unsigned int val ) +struct srw_lock { - /* Throw exception if it's impossible to acquire/release this lock. */ - if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE || - (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE) - RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); -} + short exclusive_waiters;
-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 again to use the shared queue counter. */ - for (val = *dest;; val = tmp) - { - tmp = val + incr; - srwlock_check_invalid( tmp ); - if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE)) - tmp |= SRWLOCK_MASK_IN_EXCLUSIVE; - if ((tmp = InterlockedCompareExchange( (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; - srwlock_check_invalid( tmp ); - if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE)) - tmp &= SRWLOCK_MASK_SHARED_QUEUE; - if ((tmp = InterlockedCompareExchange( (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, followed by - * the shared waiters. */ - if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) - NtReleaseKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL ); - else - { - val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */ - while (val--) - NtReleaseKeyedEvent( 0, 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( 0, srwlock_key_exclusive(lock), FALSE, NULL ); -} + /* Number of shared owners, or -1 if owned exclusive. + * + * Sadly Windows has no equivalent to FUTEX_WAIT_BITSET, so in order to wake + * up *only* exclusive or *only* shared waiters (and thus avoid spurious + * wakeups), we need to wait on two different addresses. + * RtlAcquireSRWLockShared() needs to know the values of "exclusive_waiters" + * and "owners", but RtlAcquireSRWLockExclusive() only needs to know the + * value of "owners", so the former can wait on the entire structure, and + * the latter waits only on the "owners" member. Note then that "owners" + * must not be the first element in the structure. + */ + short owners; +}; +C_ASSERT( sizeof(struct srw_lock) == 4 );
/*********************************************************************** * RtlInitializeSRWLock (NTDLL.@) @@ -650,11 +547,36 @@ void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock ) */ void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) { - if (unix_funcs->fast_RtlAcquireSRWLockExclusive( lock ) != STATUS_NOT_IMPLEMENTED) - return; + union { RTL_SRWLOCK *rtl; struct srw_lock *s; LONG *l; } u = { lock };
- if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE )) - NtWaitForKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL ); + InterlockedIncrement16( &u.s->exclusive_waiters ); + + for (;;) + { + union { struct srw_lock s; LONG l; } old, new; + BOOL wait; + + do + { + old.s = *u.s; + new.s = old.s; + + if (!old.s.owners) + { + /* Not locked exclusive or shared. We can try to grab it. */ + new.s.owners = -1; + --new.s.exclusive_waiters; + wait = FALSE; + } + else + { + wait = TRUE; + } + } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l); + + if (!wait) return; + RtlWaitOnAddress( &u.s->owners, &new.s.owners, sizeof(short), NULL ); + } }
/*********************************************************************** @@ -666,34 +588,34 @@ void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) */ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock ) { - unsigned int val, tmp; + union { RTL_SRWLOCK *rtl; struct srw_lock *s; LONG *l; } u = { lock };
- if (unix_funcs->fast_RtlAcquireSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED) - return; - - /* Acquires a shared lock. If it's currently not possible to add elements to - * the shared queue, then request exclusive access instead. */ - for (val = *(unsigned int *)&lock->Ptr;; val = tmp) + for (;;) { - if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE)) - tmp = val + SRWLOCK_RES_EXCLUSIVE; - else - tmp = val + SRWLOCK_RES_SHARED; - if ((tmp = InterlockedCompareExchange( (int *)&lock->Ptr, tmp, val )) == val) - break; - } + union { struct srw_lock s; LONG l; } old, new; + BOOL wait;
- /* Drop exclusive access again and instead requeue for shared access. */ - if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE)) - { - NtWaitForKeyedEvent( 0, 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 ); - } + do + { + old.s = *u.s; + new = old;
- if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) - NtWaitForKeyedEvent( 0, srwlock_key_shared(lock), FALSE, NULL ); + if (old.s.owners != -1 && !old.s.exclusive_waiters) + { + /* Not locked exclusive, and no exclusive waiters. + * We can try to grab it. */ + ++new.s.owners; + wait = FALSE; + } + else + { + wait = TRUE; + } + } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l); + + if (!wait) return; + RtlWaitOnAddress( u.s, &new.s, sizeof(struct srw_lock), NULL ); + } }
/*********************************************************************** @@ -701,11 +623,23 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock ) */ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock ) { - if (unix_funcs->fast_RtlReleaseSRWLockExclusive( lock ) != STATUS_NOT_IMPLEMENTED) - return; + union { RTL_SRWLOCK *rtl; struct srw_lock *s; LONG *l; } u = { lock }; + union { struct srw_lock s; LONG l; } old, new;
- srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, - - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE ); + do + { + old.s = *u.s; + new = old; + + if (old.s.owners != -1) ERR("Lock %p is not owned exclusive!\n", lock); + + new.s.owners = 0; + } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l); + + if (new.s.exclusive_waiters) + RtlWakeAddressSingle( &u.s->owners ); + else + RtlWakeAddressAll( u.s ); }
/*********************************************************************** @@ -713,11 +647,22 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock ) */ void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) { - if (unix_funcs->fast_RtlReleaseSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED) - return; + union { RTL_SRWLOCK *rtl; struct srw_lock *s; LONG *l; } u = { lock }; + union { struct srw_lock s; LONG l; } old, new;
- srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, - - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED ); + do + { + old.s = *u.s; + new = old; + + if (old.s.owners == -1) ERR("Lock %p is owned exclusive!\n", lock); + else if (!old.s.owners) ERR("Lock %p is not owned shared!\n", lock); + + --new.s.owners; + } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l); + + if (!new.s.owners) + RtlWakeAddressSingle( &u.s->owners ); }
/*********************************************************************** @@ -729,13 +674,28 @@ void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) */ BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) { - NTSTATUS ret; + union { RTL_SRWLOCK *rtl; struct srw_lock *s; LONG *l; } u = { lock }; + union { struct srw_lock s; LONG l; } old, new; + BOOLEAN ret;
- if ((ret = unix_funcs->fast_RtlTryAcquireSRWLockExclusive( lock )) != STATUS_NOT_IMPLEMENTED) - return (ret == STATUS_SUCCESS); + do + { + old.s = *u.s; + new.s = old.s;
- return InterlockedCompareExchange( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE | - SRWLOCK_RES_EXCLUSIVE, 0 ) == 0; + if (!old.s.owners) + { + /* Not locked exclusive or shared. We can try to grab it. */ + new.s.owners = -1; + ret = TRUE; + } + else + { + ret = FALSE; + } + } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l); + + return ret; }
/*********************************************************************** @@ -743,20 +703,29 @@ BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock ) */ BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock ) { - unsigned int val, tmp; - NTSTATUS ret; + union { RTL_SRWLOCK *rtl; struct srw_lock *s; LONG *l; } u = { lock }; + union { struct srw_lock s; LONG l; } old, new; + BOOLEAN ret;
- if ((ret = unix_funcs->fast_RtlTryAcquireSRWLockShared( lock )) != STATUS_NOT_IMPLEMENTED) - return (ret == STATUS_SUCCESS); - - for (val = *(unsigned int *)&lock->Ptr;; val = tmp) + do { - if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) - return FALSE; - if ((tmp = InterlockedCompareExchange( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val) - break; - } - return TRUE; + old.s = *u.s; + new.s = old.s; + + if (old.s.owners != -1 && !old.s.exclusive_waiters) + { + /* Not locked exclusive, and no exclusive waiters. + * We can try to grab it. */ + ++new.s.owners; + ret = TRUE; + } + else + { + ret = FALSE; + } + } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l); + + return ret; }
/*********************************************************************** diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 32aa7267423..3d26da194e4 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -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, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 7a2466f5fa3..0065f265e42 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -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 diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 61f37d4b22f..b499978b2fe 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -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, diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index a271bb05da9..803b6a082bb 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -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 );