diff --git a/patches/ntdll-futex-condition-var/0001-ntdll-Add-a-futex-based-condition-variable-implement.patch b/patches/ntdll-futex-condition-var/0001-ntdll-Add-a-futex-based-condition-variable-implement.patch new file mode 100644 index 00000000..71967ac5 --- /dev/null +++ b/patches/ntdll-futex-condition-var/0001-ntdll-Add-a-futex-based-condition-variable-implement.patch @@ -0,0 +1,213 @@ +From e50ac69d04c81813a52ac8959db34c4c40f047cb Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Tue, 24 Jul 2018 11:26:39 -0600 +Subject: [PATCH] ntdll: Add a futex-based condition variable implementation. + +Signed-off-by: Zebediah Figura +--- + dlls/ntdll/sync.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 132 insertions(+), 11 deletions(-) + +diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c +index 8e406ce..4752543 100644 +--- a/dlls/ntdll/sync.c ++++ b/dlls/ntdll/sync.c +@@ -26,6 +26,7 @@ + + #include + #include ++#include + #include + #ifdef HAVE_SYS_TIME_H + # include +@@ -36,6 +37,9 @@ + #ifdef HAVE_SYS_POLL_H + # include + #endif ++#ifdef HAVE_SYS_SYSCALL_H ++# include ++#endif + #ifdef HAVE_UNISTD_H + # include + #endif +@@ -61,6 +65,102 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntdll); + + HANDLE keyed_event = NULL; + ++#define TICKSPERSEC 10000000 ++ ++#ifdef __linux__ ++ ++static int wait_op = 128; /*FUTEX_WAIT|FUTEX_PRIVATE_FLAG*/ ++static int wake_op = 129; /*FUTEX_WAKE|FUTEX_PRIVATE_FLAG*/ ++ ++static inline int futex_wait( int *addr, int val, struct timespec *timeout ) ++{ ++ return syscall( __NR_futex, addr, wait_op, val, timeout, 0, 0 ); ++} ++ ++static inline int futex_wake( int *addr, int val ) ++{ ++ return syscall( __NR_futex, addr, wake_op, val, NULL, 0, 0 ); ++} ++ ++static inline int use_futexes(void) ++{ ++ static int supported = -1; ++ ++ if (supported == -1) ++ { ++ futex_wait( &supported, 10, NULL ); ++ if (errno == ENOSYS) ++ { ++ wait_op = 0; /*FUTEX_WAIT*/ ++ wake_op = 1; /*FUTEX_WAKE*/ ++ futex_wait( &supported, 10, NULL ); ++ } ++ supported = (errno != ENOSYS); ++ } ++ return supported; ++} ++ ++static inline NTSTATUS fast_wait( RTL_CONDITION_VARIABLE *variable, const LARGE_INTEGER *timeout) ++{ ++ int val, ret; ++ ++ if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; ++ ++ if (timeout && timeout->QuadPart != TIMEOUT_INFINITE) ++ { ++ struct timespec timespec; ++ LONGLONG duration; ++ ++ if (timeout->QuadPart > 0) ++ { ++ LARGE_INTEGER now; ++ NtQuerySystemTime( &now ); ++ duration = timeout->QuadPart - now.QuadPart; ++ } ++ else ++ duration = -timeout->QuadPart; ++ ++ timespec.tv_sec = duration / TICKSPERSEC; ++ timespec.tv_nsec = (duration % TICKSPERSEC) * 100; ++ do ++ val = *((int *)&variable->Ptr); ++ while (val && (ret = futex_wait( (int *)&variable->Ptr, val, ×pec )) == -1 ++ && errno == EAGAIN); ++ } ++ else ++ { ++ do ++ val = *((int *)&variable->Ptr); ++ while (val && (ret = futex_wait( (int *)&variable->Ptr, val, NULL )) == -1 ++ && errno == EAGAIN); ++ } ++ ++ if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT; ++ else if (ret == -1) FIXME("got errno %d %s\n", errno, strerror(errno)); ++ ++ return STATUS_WAIT_0; ++} ++ ++static inline NTSTATUS fast_wake( RTL_CONDITION_VARIABLE *variable, int val ) ++{ ++ if (!use_futexes()) return STATUS_NOT_IMPLEMENTED; ++ ++ futex_wake( (int *)&variable->Ptr, val ); ++ return STATUS_SUCCESS; ++} ++ ++#else ++static inline NTSTATUS fast_wait( RTL_CRITICAL_SECTION *crit, int timeout ) ++{ ++ return STATUS_NOT_IMPLEMENTED; ++} ++ ++static inline NTSTATUS fast_wake( RTL_CRITICAL_SECTION *crit ) ++{ ++ return STATUS_NOT_IMPLEMENTED; ++} ++#endif ++ + static inline int interlocked_dec_if_nonzero( int *dest ) + { + int val, tmp; +@@ -1814,7 +1914,11 @@ void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable ) + void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) + { + if (interlocked_dec_if_nonzero( (int *)&variable->Ptr )) +- NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ { ++ NTSTATUS ret; ++ if ((ret = fast_wake( variable, 1 )) == STATUS_NOT_IMPLEMENTED) ++ NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ } + } + + /*********************************************************************** +@@ -1825,8 +1929,15 @@ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) + void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable ) + { + int val = interlocked_xchg( (int *)&variable->Ptr, 0 ); +- while (val-- > 0) +- NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ if (val) ++ { ++ NTSTATUS ret; ++ if ((ret = fast_wake( variable, INT_MAX )) == STATUS_NOT_IMPLEMENTED) ++ { ++ while (val-- > 0) ++ NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ } ++ } + } + + /*********************************************************************** +@@ -1851,12 +1962,17 @@ NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, R + interlocked_xchg_add( (int *)&variable->Ptr, 1 ); + RtlLeaveCriticalSection( crit ); + +- status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout ); +- if (status != STATUS_SUCCESS) ++ if ((status = fast_wait( variable, timeout )) == STATUS_NOT_IMPLEMENTED) + { +- if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr )) +- status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout ); ++ if (status != STATUS_SUCCESS) ++ { ++ if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr )) ++ status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ } + } ++ else if (status != STATUS_SUCCESS) ++ interlocked_dec_if_nonzero( (int *)&variable->Ptr ); + + RtlEnterCriticalSection( crit ); + return status; +@@ -1892,12 +2008,17 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, + else + RtlReleaseSRWLockExclusive( lock ); + +- status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout ); +- if (status != STATUS_SUCCESS) ++ if ((status = fast_wait( variable, timeout )) == STATUS_NOT_IMPLEMENTED) + { +- if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr )) +- status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout ); ++ if (status != STATUS_SUCCESS) ++ { ++ if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr )) ++ status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL ); ++ } + } ++ else if (status != STATUS_SUCCESS) ++ interlocked_dec_if_nonzero( (int *)&variable->Ptr ); + + if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED) + RtlAcquireSRWLockShared( lock ); +-- +2.7.4 + diff --git a/patches/ntdll-futex-condition-var/definition b/patches/ntdll-futex-condition-var/definition new file mode 100644 index 00000000..4b092557 --- /dev/null +++ b/patches/ntdll-futex-condition-var/definition @@ -0,0 +1 @@ +Fixes: [45524] Add a futex-based implementation of condition variables diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index fab9afbb..f62833cf 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -247,6 +247,7 @@ patch_enable_all () enable_ntdll_WRITECOPY="$1" enable_ntdll_Wait_User_APC="$1" enable_ntdll_Zero_mod_name="$1" + enable_ntdll_futex_condition_var="$1" enable_ntdll_set_full_cpu_context="$1" enable_ntoskrnl_Stubs="$1" enable_nvapi_Stub_DLL="$1" @@ -914,6 +915,9 @@ patch_enable () ntdll-Zero_mod_name) enable_ntdll_Zero_mod_name="$2" ;; + ntdll-futex-condition-var) + enable_ntdll_futex_condition_var="$2" + ;; ntdll-set_full_cpu_context) enable_ntdll_set_full_cpu_context="$2" ;; @@ -5388,6 +5392,21 @@ if test "$enable_ntdll_Zero_mod_name" -eq 1; then ) >> "$patchlist" fi +# Patchset ntdll-futex-condition-var +# | +# | This patchset fixes the following Wine bugs: +# | * [#45524] Add a futex-based implementation of condition variables +# | +# | Modified files: +# | * dlls/ntdll/sync.c +# | +if test "$enable_ntdll_futex_condition_var" -eq 1; then + patch_apply ntdll-futex-condition-var/0001-ntdll-Add-a-futex-based-condition-variable-implement.patch + ( + printf '%s\n' '+ { "Zebediah Figura", "ntdll: Add a futex-based condition variable implementation.", 1 },'; + ) >> "$patchlist" +fi + # Patchset ntdll-set_full_cpu_context # | # | Modified files: