[Bug 46252] StarCitizen has bad performance
wine-bugs at winehq.org
wine-bugs at winehq.org
Wed Jan 23 13:21:49 CST 2019
https://bugs.winehq.org/show_bug.cgi?id=46252
--- Comment #10 from rawfox <rawfox at freenet.de> ---
Comment on attachment 63216
--> https://bugs.winehq.org/attachment.cgi?id=63216
merged futex conditions patch for wine vanilla
>--- a/dlls/ntdll/sync.c 2019-01-07 22:06:29.876808084 +0100
>+++ b/dlls/ntdll/sync.c 2019-01-07 23:51:22.897154211 +0100
>@@ -26,6 +26,7 @@
>
> #include <assert.h>
> #include <errno.h>
>+#include <limits.h>
> #include <signal.h>
> #ifdef HAVE_SYS_TIME_H
> # include <sys/time.h>
>@@ -36,6 +37,9 @@
> #ifdef HAVE_SYS_POLL_H
> # include <sys/poll.h>
> #endif
>+#ifdef HAVE_SYS_SYSCALL_H
>+# include <sys/syscall.h>
>+#endif
> #ifdef HAVE_UNISTD_H
> # include <unistd.h>
> #endif
>@@ -61,7 +65,140 @@
>
> HANDLE keyed_event = NULL;
>
>+
> static const LARGE_INTEGER zero_timeout;
>+#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, int val,
>+ const LARGE_INTEGER *timeout)
>+{
>+ struct timespec timespec;
>+ LONGLONG timeleft;
>+ LARGE_INTEGER now;
>+ int ret;
>+
>+ if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
>+
>+ if (timeout && timeout->QuadPart != TIMEOUT_INFINITE)
>+ {
>+ if (timeout->QuadPart >= 0)
>+ {
>+ NtQuerySystemTime( &now );
>+ timeleft = timeout->QuadPart - now.QuadPart;
>+ if (timeleft < 0) timeleft = 0;
>+ }
>+ else
>+ timeleft = -timeout->QuadPart;
>+
>+ timespec.tv_sec = timeleft / TICKSPERSEC;
>+ timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100;
>+
>+ ret = futex_wait( (int *)&variable->Ptr, val, ×pec );
>+ }
>+ else
>+ ret = futex_wait( (int *)&variable->Ptr, val, NULL );
>+
>+ if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT;
>+ return STATUS_WAIT_0;
>+}
>+
>+static inline NTSTATUS fast_sleep_cs( RTL_CONDITION_VARIABLE *variable,
>+ RTL_CRITICAL_SECTION *crit, const LARGE_INTEGER *timeout )
>+{
>+ int val = *(int *)&variable->Ptr;
>+ NTSTATUS ret;
>+
>+ RtlLeaveCriticalSection( crit );
>+
>+ ret = fast_wait( variable, val, timeout );
>+
>+ RtlEnterCriticalSection( crit );
>+
>+ return ret;
>+}
>+
>+static inline NTSTATUS fast_sleep_srw( RTL_CONDITION_VARIABLE *variable,
>+ RTL_SRWLOCK *lock, const LARGE_INTEGER *timeout, ULONG flags )
>+{
>+ int val = *(int *)&variable->Ptr;
>+ NTSTATUS ret;
>+
>+ if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
>+ RtlReleaseSRWLockShared( lock );
>+ else
>+ RtlReleaseSRWLockExclusive( lock );
>+
>+ ret = fast_wait( variable, val, timeout );
>+
>+ if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
>+ RtlAcquireSRWLockShared( lock );
>+ else
>+ RtlAcquireSRWLockExclusive( lock );
>+
>+ return ret;
>+}
>+
>+static inline NTSTATUS fast_wake( RTL_CONDITION_VARIABLE *variable, int val )
>+{
>+ if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
>+
>+ interlocked_xchg_add( (int *)&variable->Ptr, 1 );
>+ futex_wake( (int *)&variable->Ptr, val );
>+ return STATUS_SUCCESS;
>+}
>+
>+#else
>+static inline NTSTATUS fast_sleep_cs( RTL_CONDITION_VARIABLE *variable,
>+ RTL_CRITICAL_SECTION *crit, const LARGE_INTEGER *timeout )
>+{
>+ return STATUS_NOT_IMPLEMENTED;
>+}
>+
>+static inline NTSTATUS fast_sleep_srw( RTL_CONDITION_VARIABLE *variable,
>+ RTL_SRWLOCK *lock, const LARGE_INTEGER *timeout, ULONG flags )
>+{
>+ return STATUS_NOT_IMPLEMENTED;
>+}
>+
>+static inline NTSTATUS fast_wake( RTL_CONDITION_VARIABLE *variable, int val )
>+{
>+ return STATUS_NOT_IMPLEMENTED;
>+}
>+#endif
>+
>
> static inline int interlocked_dec_if_nonzero( int *dest )
> {
>@@ -1868,8 +2005,11 @@
> */
> void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
> {
>- if (interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
>- NtReleaseKeyedEvent( 0, &variable->Ptr, FALSE, NULL );
>+ if (fast_wake( variable, 1 ) == STATUS_NOT_IMPLEMENTED)
>+ {
>+ if (interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
>+ NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
>+ }
> }
>
> /***********************************************************************
>@@ -1879,9 +2019,12 @@
> */
> void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
> {
>- int val = interlocked_xchg( (int *)&variable->Ptr, 0 );
>- while (val-- > 0)
>- NtReleaseKeyedEvent( 0, &variable->Ptr, FALSE, NULL );
>+ if (fast_wake( variable, INT_MAX ) == STATUS_NOT_IMPLEMENTED)
>+ {
>+ int val = interlocked_xchg( (int *)&variable->Ptr, 0 );
>+ while (val-- > 0)
>+ NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
>+ }
> }
>
> /***********************************************************************
>@@ -1903,17 +2046,24 @@
> const LARGE_INTEGER *timeout )
> {
> NTSTATUS status;
>- interlocked_xchg_add( (int *)&variable->Ptr, 1 );
>- RtlLeaveCriticalSection( crit );
>
>- status = NtWaitForKeyedEvent( 0, &variable->Ptr, FALSE, timeout );
>- if (status != STATUS_SUCCESS)
>+ if ((status = fast_sleep_cs( variable, crit, timeout )) == STATUS_NOT_IMPLEMENTED)
> {
>- if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
>- status = NtWaitForKeyedEvent( 0, &variable->Ptr, FALSE, NULL );
>- }
>+ interlocked_xchg_add( (int *)&variable->Ptr, 1 );
>+ RtlLeaveCriticalSection( crit );
>
>- RtlEnterCriticalSection( crit );
>+ 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;
> }
>
>@@ -1940,24 +2090,31 @@
> const LARGE_INTEGER *timeout, ULONG flags )
> {
> NTSTATUS status;
>- interlocked_xchg_add( (int *)&variable->Ptr, 1 );
>-
>- if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
>- RtlReleaseSRWLockShared( lock );
>- else
>- RtlReleaseSRWLockExclusive( lock );
>
>- status = NtWaitForKeyedEvent( 0, &variable->Ptr, FALSE, timeout );
>- if (status != STATUS_SUCCESS)
>+ if ((status = fast_sleep_srw( variable, lock, timeout, flags )) == STATUS_NOT_IMPLEMENTED)
> {
>- if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
>- status = NtWaitForKeyedEvent( 0, &variable->Ptr, FALSE, NULL );
>- }
>+ interlocked_xchg_add( (int *)&variable->Ptr, 1 );
>
>- if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
>- RtlAcquireSRWLockShared( lock );
>- else
>- RtlAcquireSRWLockExclusive( lock );
>+ if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
>+ RtlReleaseSRWLockShared( lock );
>+ else
>+ RtlReleaseSRWLockExclusive( lock );
>+
>+ 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 );
>+ else
>+ RtlAcquireSRWLockExclusive( lock );
>+ }
> return status;
> }
>
>@@ -1987,6 +2144,89 @@
> return FALSE;
> }
>
>+#ifdef __linux__
>+
>+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;
>+ LARGE_INTEGER now;
>+ timeout_t diff;
>+ 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. */
>+ val = interlocked_cmpxchg( futex, 0, 0 );
>+ if (!compare_addr( addr, cmp, size ))
>+ return STATUS_SUCCESS;
>+
>+ if (timeout)
>+ {
>+ if (timeout->QuadPart > 0)
>+ {
>+ NtQuerySystemTime( &now );
>+ diff = timeout->QuadPart - now.QuadPart;
>+ }
>+ else
>+ diff = -timeout->QuadPart;
>+
>+ timespec.tv_sec = diff / 1000000;
>+ timespec.tv_nsec = diff % 1000000;
>+
>+ 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 );
>+
>+ interlocked_xchg_add( futex, 1 );
>+
>+ futex_wake( futex, INT_MAX );
>+ return STATUS_SUCCESS;
>+}
>+#else
>+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.@)
> */
>@@ -2005,6 +2245,9 @@
> 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;
>+
> 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 );
>@@ -2059,6 +2302,9 @@
> */
> void WINAPI RtlWakeAddressAll( const void *addr )
> {
>+ if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED)
>+ return;
>+
> RtlEnterCriticalSection( &addr_section );
> while (NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout ) == STATUS_SUCCESS) {}
> RtlLeaveCriticalSection( &addr_section );
>@@ -2069,6 +2315,9 @@
> */
> void WINAPI RtlWakeAddressSingle( const void *addr )
> {
>+ if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED)
>+ return;
>+
> RtlEnterCriticalSection( &addr_section );
> NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout );
> RtlLeaveCriticalSection( &addr_section );
--
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.
More information about the wine-bugs
mailing list