ntdll: Reimplement the critical section fast path on top of Win32 futexes.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-11-17 20:18:55 -06:00 committed by Alexandre Julliard
parent 6bdb914a25
commit c577ce2671
5 changed files with 24 additions and 132 deletions

View File

@ -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;
}

View File

@ -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,

View File

@ -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, &timespec ) == -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:

View File

@ -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;

View File

@ -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 );