From 509ad75adbca85d606a3bd8bba727abf0751cebc Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 9 Jun 2020 12:38:37 +0200 Subject: [PATCH] ntdll: Move the futex-based condition variable implementation to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/ntdll/sync.c | 119 ++------------------------------- dlls/ntdll/unix/loader.c | 3 + dlls/ntdll/unix/sync.c | 115 +++++++++++++++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 6 ++ dlls/ntdll/unixlib.h | 9 ++- 5 files changed, 138 insertions(+), 114 deletions(-) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index b087b1faeb5..f834b05c421 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -105,16 +105,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; -} - static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGER *timeout ) { LARGE_INTEGER now; @@ -1437,105 +1427,6 @@ BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock ) return TRUE; } -#ifdef __linux__ -static NTSTATUS fast_wait_cv( int *futex, int val, const LARGE_INTEGER *timeout ) -{ - struct timespec timespec; - int ret; - - if (timeout && timeout->QuadPart != TIMEOUT_INFINITE) - { - 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_WAIT_0; -} - -static NTSTATUS fast_sleep_cs_cv( RTL_CONDITION_VARIABLE *variable, - RTL_CRITICAL_SECTION *cs, const LARGE_INTEGER *timeout ) -{ - NTSTATUS status; - int val, *futex; - - if (!use_futexes()) - return STATUS_NOT_IMPLEMENTED; - - if (!(futex = get_futex( &variable->Ptr ))) - return STATUS_NOT_IMPLEMENTED; - - val = *futex; - - RtlLeaveCriticalSection( cs ); - status = fast_wait_cv( futex, val, timeout ); - RtlEnterCriticalSection( cs ); - return status; -} - -static NTSTATUS fast_sleep_srw_cv( RTL_CONDITION_VARIABLE *variable, - RTL_SRWLOCK *lock, const LARGE_INTEGER *timeout, ULONG flags ) -{ - NTSTATUS status; - int val, *futex; - - if (!use_futexes()) - return STATUS_NOT_IMPLEMENTED; - - if (!(futex = get_futex( &variable->Ptr ))) - return STATUS_NOT_IMPLEMENTED; - - val = *futex; - - if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) - RtlReleaseSRWLockShared( lock ); - else - RtlReleaseSRWLockExclusive( lock ); - - status = fast_wait_cv( futex, val, timeout ); - - if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) - RtlAcquireSRWLockShared( lock ); - else - RtlAcquireSRWLockExclusive( lock ); - return status; -} - -static NTSTATUS fast_wake_cv( 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 -static NTSTATUS fast_sleep_srw_cv( RTL_CONDITION_VARIABLE *variable, - RTL_SRWLOCK *lock, const LARGE_INTEGER *timeout, ULONG flags ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS fast_sleep_cs_cv( RTL_CONDITION_VARIABLE *variable, - RTL_CRITICAL_SECTION *cs, const LARGE_INTEGER *timeout ) -{ - return STATUS_NOT_IMPLEMENTED; -} - -static NTSTATUS fast_wake_cv( RTL_CONDITION_VARIABLE *variable, int count ) -{ - return STATUS_NOT_IMPLEMENTED; -} -#endif - /*********************************************************************** * RtlInitializeConditionVariable (NTDLL.@) * @@ -1569,7 +1460,7 @@ void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable ) */ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) { - if (fast_wake_cv( variable, 1 ) == STATUS_NOT_IMPLEMENTED) + if (unix_funcs->fast_RtlWakeConditionVariable( variable, 1 ) == STATUS_NOT_IMPLEMENTED) { InterlockedIncrement( (int *)&variable->Ptr ); RtlWakeAddressSingle( variable ); @@ -1583,7 +1474,7 @@ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) */ void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable ) { - if (fast_wake_cv( variable, INT_MAX ) == STATUS_NOT_IMPLEMENTED) + if (unix_funcs->fast_RtlWakeConditionVariable( variable, INT_MAX ) == STATUS_NOT_IMPLEMENTED) { InterlockedIncrement( (int *)&variable->Ptr ); RtlWakeAddressAll( variable ); @@ -1611,7 +1502,8 @@ NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, R NTSTATUS status; int val; - if ((status = fast_sleep_cs_cv( variable, crit, timeout )) != STATUS_NOT_IMPLEMENTED) + if ((status = unix_funcs->fast_RtlSleepConditionVariableCS( variable, crit, + timeout )) != STATUS_NOT_IMPLEMENTED) return status; val = *(int *)&variable->Ptr; @@ -1646,7 +1538,8 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, NTSTATUS status; int val; - if ((status = fast_sleep_srw_cv( variable, lock, timeout, flags )) != STATUS_NOT_IMPLEMENTED) + if ((status = unix_funcs->fast_RtlSleepConditionVariableSRW( variable, lock, timeout, + flags )) != STATUS_NOT_IMPLEMENTED) return status; val = *(int *)&variable->Ptr; diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 027070cea3d..380ef8e15a4 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1052,6 +1052,9 @@ static struct unix_funcs unix_funcs = fast_RtlAcquireSRWLockShared, fast_RtlReleaseSRWLockExclusive, fast_RtlReleaseSRWLockShared, + fast_RtlSleepConditionVariableSRW, + fast_RtlSleepConditionVariableCS, + fast_RtlWakeConditionVariable, get_main_args, get_paths, get_dll_path, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 7b73c93655e..af81d43335b 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -67,6 +67,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync); +#define TICKSPERSEC 10000000 HANDLE keyed_event = 0; @@ -126,6 +127,23 @@ 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 @@ -1260,6 +1278,86 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) return STATUS_SUCCESS; } +static NTSTATUS wait_cv( int *futex, int val, const LARGE_INTEGER *timeout ) +{ + struct timespec timespec; + int ret; + + if (timeout && timeout->QuadPart != TIMEOUT_INFINITE) + { + 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_WAIT_0; +} + +NTSTATUS CDECL fast_RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, + RTL_CRITICAL_SECTION *cs, const LARGE_INTEGER *timeout ) +{ + NTSTATUS status; + int val, *futex; + + if (!use_futexes()) + return STATUS_NOT_IMPLEMENTED; + + if (!(futex = get_futex( &variable->Ptr ))) + return STATUS_NOT_IMPLEMENTED; + + val = *futex; + + RtlLeaveCriticalSection( cs ); + status = wait_cv( futex, val, timeout ); + RtlEnterCriticalSection( cs ); + return status; +} + +NTSTATUS CDECL fast_RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock, + const LARGE_INTEGER *timeout, ULONG flags ) +{ + NTSTATUS status; + int val, *futex; + + if (!use_futexes()) + return STATUS_NOT_IMPLEMENTED; + + if (!(futex = get_futex( &variable->Ptr )) || !get_futex( &lock->Ptr )) + return STATUS_NOT_IMPLEMENTED; + + val = *futex; + + if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) + fast_RtlReleaseSRWLockShared( lock ); + else + fast_RtlReleaseSRWLockExclusive( lock ); + + status = wait_cv( futex, val, timeout ); + + if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) + fast_RtlAcquireSRWLockShared( lock ); + else + fast_RtlAcquireSRWLockExclusive( lock ); + return status; +} + +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 ) @@ -1292,4 +1390,21 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) return STATUS_NOT_IMPLEMENTED; } +NTSTATUS CDECL fast_RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock, + const LARGE_INTEGER *timeout, ULONG flags ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS CDECL fast_RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, + RTL_CRITICAL_SECTION *cs, const LARGE_INTEGER *timeout ) +{ + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count ) +{ + return STATUS_NOT_IMPLEMENTED; +} + #endif diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 70e4a98fd04..4264e14905a 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -63,6 +63,12 @@ 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_RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock, + const LARGE_INTEGER *timeout, ULONG flags ) DECLSPEC_HIDDEN; +extern NTSTATUS CDECL fast_RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, + RTL_CRITICAL_SECTION *cs, + const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; +extern NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count ) 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; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 922db2db7ba..2598ca20694 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 35 +#define NTDLL_UNIXLIB_VERSION 36 struct unix_funcs { @@ -151,6 +151,13 @@ 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_RtlSleepConditionVariableSRW)( RTL_CONDITION_VARIABLE *variable, + RTL_SRWLOCK *lock, + const LARGE_INTEGER *timeout, ULONG flags ); + NTSTATUS (CDECL *fast_RtlSleepConditionVariableCS)( RTL_CONDITION_VARIABLE *variable, + RTL_CRITICAL_SECTION *cs, + const LARGE_INTEGER *timeout ); + NTSTATUS (CDECL *fast_RtlWakeConditionVariable)( RTL_CONDITION_VARIABLE *variable, int count ); /* environment functions */ void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] );