ntdll-NtAlertThreadByThreadId: Make Win32 futexes fair.

Resident Evil 8 depends on this.
This commit is contained in:
Zebediah Figura 2021-10-20 22:25:01 -05:00
parent feb91195ff
commit 4eaa5b69b8
5 changed files with 260 additions and 166 deletions

View File

@ -1,22 +1,26 @@
From 9e5d23232d1e857e1b57292f0f56487943fb0ba4 Mon Sep 17 00:00:00 2001
From 683cdfce393f1a4fca23d1520866d3e663a8c60f Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Mon, 2 Nov 2020 20:24:07 -0600
Date: Mon, 7 Jun 2021 16:26:18 -0500
Subject: [PATCH] ntdll: Reimplement Win32 futexes on top of thread-ID alerts.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
---
dlls/ntdll/sync.c | 158 +++++++++++++++++++++++++++++++++++++-
dlls/ntdll/sync.c | 215 ++++++++++++++++++++++++++++++++++++++-
dlls/ntdll/unix/loader.c | 3 -
dlls/ntdll/unix/sync.c | 162 ---------------------------------------
dlls/ntdll/unixlib.h | 4 -
4 files changed, 155 insertions(+), 172 deletions(-)
dlls/ntdll/unix/sync.c | 162 -----------------------------
dlls/ntdll/unixlib.h | 6 +-
4 files changed, 213 insertions(+), 173 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index f1263ae33fd..348f260c3b0 100644
index f1263ae33fd..c0a6e3a729e 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -36,6 +36,13 @@
@@ -34,8 +34,16 @@
#include "windef.h"
#include "winternl.h"
#include "wine/debug.h"
+#include "wine/list.h"
#include "ntdll_misc.h"
+WINE_DEFAULT_DEBUG_CHANNEL(sync);
@ -29,48 +33,68 @@ index f1263ae33fd..348f260c3b0 100644
/******************************************************************
* RtlRunOnceInitialize (NTDLL.@)
@@ -530,13 +537,111 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable,
@@ -530,13 +538,142 @@ 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 a
+ * manual-reset event) per thread. This can be tested by attempting to wake a
+ * thread waiting in RtlWaitOnAddress() via NtAlertThreadByThreadId.
+ */
+
+#define FUTEX_ADDR_BLOCK_SIZE (65536 / sizeof(void *))
+static void **futex_addr_blocks[4096];
+
+static unsigned int tid_to_index( DWORD tid, unsigned int *block_idx )
+struct futex_entry
+{
+ unsigned int idx = (tid >> 2) - 1;
+ *block_idx = idx / FUTEX_ADDR_BLOCK_SIZE;
+ return idx % FUTEX_ADDR_BLOCK_SIZE;
+ 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 HANDLE index_to_tid( unsigned int block_idx, unsigned int idx )
+static void spin_rdlock( LONG *lock )
+{
+ return (HANDLE)((((block_idx * FUTEX_ADDR_BLOCK_SIZE) + idx) + 1) << 2);
+ for (;;)
+ {
+ LONG old = *lock;
+ if (old != -1 && InterlockedCompareExchange( lock, old + 1, old ) == old)
+ return;
+ YieldProcessor();
+ }
+}
+
+static void **get_futex_entry( DWORD tid )
+static void spin_rdunlock( LONG *lock )
+{
+ unsigned int block_idx, idx = tid_to_index( tid, &block_idx );
+ InterlockedDecrement( lock );
+}
+
+ if (block_idx > ARRAY_SIZE(futex_addr_blocks))
+ {
+ FIXME( "tid %#x is too high\n", tid );
+ return NULL;
+ }
+static void spin_wrlock( LONG *lock )
+{
+ while (InterlockedCompareExchange( lock, -1, 0 ))
+ YieldProcessor();
+}
+
+ if (!futex_addr_blocks[block_idx])
+ {
+ SIZE_T size = FUTEX_ADDR_BLOCK_SIZE * sizeof(void *);
+ void *ptr = NULL;
+
+ if (NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &size, MEM_COMMIT, PAGE_READWRITE ))
+ return NULL;
+ if (InterlockedCompareExchangePointer( (void **)&futex_addr_blocks[block_idx], ptr, NULL ))
+ NtFreeVirtualMemory( NtCurrentProcess(), &ptr, &size, MEM_RELEASE ); /* someone beat us to it */
+ }
+
+ return &futex_addr_blocks[block_idx][idx % FUTEX_ADDR_BLOCK_SIZE];
+static void spin_wrunlock( LONG *lock )
+{
+ InterlockedExchange( lock, 0 );
+}
+
+static BOOL compare_addr( const void *addr, const void *cmp, SIZE_T size )
@ -97,7 +121,8 @@ index f1263ae33fd..348f260c3b0 100644
const LARGE_INTEGER *timeout )
{
- return unix_funcs->RtlWaitOnAddress( addr, cmp, size, timeout );
+ void **entry = get_futex_entry( GetCurrentThreadId() );
+ 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 ));
@ -105,12 +130,17 @@ index f1263ae33fd..348f260c3b0 100644
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!entry) return STATUS_NO_MEMORY;
+ entry.addr = addr;
+ entry.tid = GetCurrentThreadId();
+
+ InterlockedExchangePointer( entry, (void *)addr );
+ spin_wrlock( &queue->lock );
+ if (!queue->queue.next)
+ list_init(&queue->queue);
+ list_add_tail( &queue->queue, &entry.entry );
+ spin_wrunlock( &queue->lock );
+
+ /* Ensure that the compare-and-swap above is ordered before the comparison
+ * below. This barrier is paired with another in RtlWakeByAddress*().
+ /* Ensure that the store above is ordered before the comparison below.
+ * This barrier is paired with another in RtlWakeByAddress*().
+ *
+ * In more detail, given the following sequence:
+ *
@ -129,26 +159,33 @@ index f1263ae33fd..348f260c3b0 100644
+ */
+ MemoryBarrier();
+
+ if (!compare_addr( addr, cmp, size ))
+ {
+ InterlockedExchangePointer( entry, NULL );
+ return STATUS_SUCCESS;
+ }
+ if (compare_addr( addr, cmp, size ))
+ ret = NtWaitForAlertByThreadId( NULL, timeout );
+ else
+ ret = STATUS_SUCCESS;
+
+ spin_wrlock( &queue->lock );
+ /* We may have already been removed by a call to RtlWakeAddressSingle(). */
+ if (entry.addr)
+ list_remove( &entry.entry );
+ spin_wrunlock( &queue->lock );
+
+ TRACE("returning %#x\n", ret);
+
+ ret = NtWaitForAlertByThreadId( NULL, timeout );
+ InterlockedExchangePointer( entry, NULL );
+ if (ret == STATUS_ALERTED) ret = STATUS_SUCCESS;
+ return ret;
}
/***********************************************************************
@@ -544,7 +649,29 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
@@ -544,7 +681,42 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
*/
void WINAPI RtlWakeAddressAll( const void *addr )
{
- return unix_funcs->RtlWakeAddressAll( addr );
+ unsigned int i, j;
+ void **block;
+ struct futex_queue *queue = get_futex_queue( addr );
+ unsigned int count = 0, i;
+ struct futex_entry *entry;
+ DWORD tids[256];
+
+ TRACE("%p\n", addr);
+
@ -159,27 +196,39 @@ index f1263ae33fd..348f260c3b0 100644
+ */
+ MemoryBarrier();
+
+ for (i = 0; i < ARRAY_SIZE(futex_addr_blocks); ++i)
+ {
+ block = futex_addr_blocks[i];
+ if (!block) continue;
+ spin_wrlock( &queue->lock );
+
+ for (j = 0; j < FUTEX_ADDR_BLOCK_SIZE; ++j)
+ if (!queue->queue.next)
+ list_init(&queue->queue);
+
+ LIST_FOR_EACH_ENTRY( entry, &queue->queue, struct futex_entry, entry )
+ {
+ if (entry->addr == addr)
+ {
+ if (block[j] == addr)
+ NtAlertThreadByThreadId( index_to_tid( i, j ) );
+ /* 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_wrunlock( &queue->lock );
+
+ for (i = 0; i < count; ++i)
+ NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)tids[i] );
}
/***********************************************************************
@@ -552,5 +679,30 @@ void WINAPI RtlWakeAddressAll( const void *addr )
@@ -552,5 +724,42 @@ void WINAPI RtlWakeAddressAll( const void *addr )
*/
void WINAPI RtlWakeAddressSingle( const void *addr )
{
- return unix_funcs->RtlWakeAddressSingle( addr );
+ unsigned int i, j;
+ void **block;
+ struct futex_queue *queue = get_futex_queue( addr );
+ struct futex_entry *entry;
+ DWORD tid = 0;
+
+ TRACE("%p\n", addr);
+
@ -190,26 +239,37 @@ index f1263ae33fd..348f260c3b0 100644
+ */
+ MemoryBarrier();
+
+ for (i = 0; i < ARRAY_SIZE(futex_addr_blocks); ++i)
+ {
+ block = futex_addr_blocks[i];
+ if (!block) continue;
+ spin_wrlock( &queue->lock );
+
+ for (j = 0; j < FUTEX_ADDR_BLOCK_SIZE; ++j)
+ if (!queue->queue.next)
+ list_init(&queue->queue);
+
+ LIST_FOR_EACH_ENTRY( entry, &queue->queue, struct futex_entry, entry )
+ {
+ if (entry->addr == addr)
+ {
+ if (block[j] == addr && InterlockedCompareExchangePointer( &block[j], NULL, (void *)addr ) == addr)
+ {
+ NtAlertThreadByThreadId( index_to_tid( i, j ) );
+ return;
+ }
+ /* 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_wrunlock( &queue->lock );
+
+ if (tid) NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)tid );
}
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index c26028d756e..f046d2db878 100644
index 8720660eb6b..269788bcf91 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -1822,9 +1822,6 @@ static struct unix_funcs unix_funcs =
@@ -2151,9 +2151,6 @@ static struct unix_funcs unix_funcs =
#endif
DbgUiIssueRemoteBreakin,
RtlGetSystemTimePrecise,
@ -220,10 +280,10 @@ index c26028d756e..f046d2db878 100644
fast_RtlpUnWaitCriticalSection,
fast_RtlDeleteCriticalSection,
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 9ebcf60c820..5e49593fa4a 100644
index 7f5d9a49ef5..43838e593dc 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -81,10 +81,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync);
@@ -78,10 +78,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync);
HANDLE keyed_event = 0;
@ -234,7 +294,7 @@ index 9ebcf60c820..5e49593fa4a 100644
static const char *debugstr_timeout( const LARGE_INTEGER *timeout )
{
if (!timeout) return "(infinite)";
@@ -194,24 +190,6 @@ static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGE
@@ -191,24 +187,6 @@ static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGE
#endif
@ -259,7 +319,7 @@ index 9ebcf60c820..5e49593fa4a 100644
/* 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 )
@@ -2980,71 +2958,6 @@ NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable,
@@ -2982,71 +2960,6 @@ NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable,
return STATUS_SUCCESS;
}
@ -331,7 +391,7 @@ index 9ebcf60c820..5e49593fa4a 100644
#else
NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
@@ -3087,79 +3000,4 @@ NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value
@@ -3089,79 +3002,4 @@ NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value
return STATUS_NOT_IMPLEMENTED;
}
@ -412,9 +472,18 @@ index 9ebcf60c820..5e49593fa4a 100644
- mutex_unlock( &addr_mutex );
-}
diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h
index cbe5c9d3ccd..914a2f3b7b7 100644
index 4b7c8b45be7..921ceedbdb2 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 126
+#define NTDLL_UNIXLIB_VERSION 127
struct unix_funcs
{
@@ -38,10 +38,6 @@ struct unix_funcs
/* other Win32 API functions */
NTSTATUS (WINAPI *DbgUiIssueRemoteBreakin)( HANDLE process );
@ -427,5 +496,5 @@ index cbe5c9d3ccd..914a2f3b7b7 100644
/* fast locks */
NTSTATUS (CDECL *fast_RtlpWaitForCriticalSection)( RTL_CRITICAL_SECTION *crit, int timeout );
--
2.30.2
2.33.0

View File

@ -1,9 +1,10 @@
From 601db6caf92a018e469a714085c7a573c7cd8fa1 Mon Sep 17 00:00:00 2001
From daa52c29f5fe2ba16338672bc545259d3314295c Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Mon, 31 Aug 2020 23:30:52 -0500
Subject: [PATCH] ntdll: Merge critsection.c into sync.c.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
---
dlls/ntdll/Makefile.in | 1 -
dlls/ntdll/critsection.c | 543 ---------------------------------------
@ -12,10 +13,10 @@ Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
delete mode 100644 dlls/ntdll/critsection.c
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 881a3b28ff1..841e1a4a943 100644
index aac7f8eead7..29b772c7c56 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -9,7 +9,6 @@ EXTRADLLFLAGS = -mno-cygwin -nodefaultlibs -Wl,--image-base,0x7bc00000
@@ -11,7 +11,6 @@ EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x7bc00000
C_SRCS = \
actctx.c \
atom.c \
@ -573,7 +574,7 @@ index fe7d933c0fa..00000000000
- return STATUS_SUCCESS;
-}
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 348f260c3b0..c73fb09da47 100644
index c0a6e3a729e..db68a466d8a 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -2,7 +2,7 @@
@ -585,7 +586,7 @@ index 348f260c3b0..c73fb09da47 100644
* Copyright 1999, 2000 Juergen Schmied
* Copyright 2003 Eric Pouech
*
@@ -37,6 +37,7 @@
@@ -38,6 +38,7 @@
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(sync);
@ -593,11 +594,10 @@ index 348f260c3b0..c73fb09da47 100644
static const char *debugstr_timeout( const LARGE_INTEGER *timeout )
{
@@ -706,3 +707,334 @@ void WINAPI RtlWakeAddressSingle( const void *addr )
}
@@ -141,6 +142,337 @@ DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context
}
}
+
+
+/***********************************************************************
+ * Critical sections
@ -928,6 +928,10 @@ index 348f260c3b0..c73fb09da47 100644
+ }
+ return STATUS_SUCCESS;
+}
+
/******************************************************************
* RtlRunOnceExecuteOnce (NTDLL.@)
*/
--
2.30.2
2.33.0

View File

@ -1,23 +1,24 @@
From aaa6e2824cd84e2317017c5436c03621a890cc0c Mon Sep 17 00:00:00 2001
From d43977918339fdda79e06331502254eaf456adab Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Mon, 31 Aug 2020 23:38:09 -0500
Subject: [PATCH] ntdll: Reimplement the critical section fast path on top of
Win32 futexes.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
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 | 3 -
5 files changed, 23 insertions(+), 131 deletions(-)
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 c73fb09da47..6edf104c5e9 100644
index db68a466d8a..3a47679bb60 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -738,19 +738,26 @@ static inline HANDLE get_semaphore( RTL_CRITICAL_SECTION *crit )
@@ -172,19 +172,26 @@ static inline HANDLE get_semaphore( RTL_CRITICAL_SECTION *crit )
static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout )
{
@ -52,7 +53,7 @@ index c73fb09da47..6edf104c5e9 100644
}
/******************************************************************************
@@ -840,8 +847,6 @@ NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
@@ -274,8 +281,6 @@ NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
crit->DebugInfo = NULL;
}
@ -61,7 +62,7 @@ index c73fb09da47..6edf104c5e9 100644
}
else NtClose( crit->LockSemaphore );
crit->LockSemaphore = 0;
@@ -917,12 +922,18 @@ NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
@@ -351,12 +356,18 @@ NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
NTSTATUS ret;
/* debug info is cleared by MakeCriticalSectionGlobal */
@ -83,10 +84,10 @@ index c73fb09da47..6edf104c5e9 100644
return ret;
}
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index e21cf8631d7..97bb9e510b2 100644
index 269788bcf91..5302b7f1638 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -1872,9 +1872,6 @@ static struct unix_funcs unix_funcs =
@@ -2151,9 +2151,6 @@ static struct unix_funcs unix_funcs =
#endif
DbgUiIssueRemoteBreakin,
RtlGetSystemTimePrecise,
@ -97,10 +98,10 @@ index e21cf8631d7..97bb9e510b2 100644
fast_RtlAcquireSRWLockExclusive,
fast_RtlTryAcquireSRWLockShared,
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 5e49593fa4a..84f7c937be3 100644
index 43838e593dc..6a636d30f21 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -2553,115 +2553,6 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
@@ -2555,115 +2555,6 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
#endif
@ -217,10 +218,10 @@ index 5e49593fa4a..84f7c937be3 100644
/* Futex-based SRW lock implementation:
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 090f6afdf29..5e3dbebee4c 100644
index 6b8835bcba0..d142fa894b1 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -96,10 +96,6 @@ extern void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PT
@@ -101,10 +101,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;
@ -232,9 +233,18 @@ index 090f6afdf29..5e3dbebee4c 100644
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 10b0f57fbed..37a0e2da83c 100644
index 921ceedbdb2..d86501dfb5e 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 127
+#define NTDLL_UNIXLIB_VERSION 128
struct unix_funcs
{
@@ -40,9 +40,6 @@ struct unix_funcs
LONGLONG (WINAPI *RtlGetSystemTimePrecise)(void);
@ -246,5 +256,5 @@ index 10b0f57fbed..37a0e2da83c 100644
NTSTATUS (CDECL *fast_RtlAcquireSRWLockExclusive)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlTryAcquireSRWLockShared)( RTL_SRWLOCK *lock );
--
2.30.2
2.33.0

View File

@ -1,23 +1,24 @@
From 16e1eb20e23a8bd8129cf59efef1db06848752ed Mon Sep 17 00:00:00 2001
From a90c16005d368581ea802f9fb2780fcb10d23566 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Mon, 31 Aug 2020 23:55:29 -0500
Subject: [PATCH] ntdll: Get rid of the direct futex path for condition
variables.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
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 | 3 --
5 files changed, 8 insertions(+), 95 deletions(-)
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 6edf104c5e9..4b92379a0ff 100644
index 3a47679bb60..6e68d07b81b 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -449,11 +449,8 @@ void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
@@ -792,11 +792,8 @@ void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
*/
void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
{
@ -31,7 +32,7 @@ index 6edf104c5e9..4b92379a0ff 100644
}
/***********************************************************************
@@ -463,11 +460,8 @@ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
@@ -806,11 +803,8 @@ void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
*/
void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
{
@ -45,7 +46,7 @@ index 6edf104c5e9..4b92379a0ff 100644
}
/***********************************************************************
@@ -488,12 +482,11 @@ void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *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 )
{
@ -60,7 +61,7 @@ index 6edf104c5e9..4b92379a0ff 100644
RtlEnterCriticalSection( crit );
return status;
}
@@ -520,7 +513,7 @@ NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, R
@@ -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 )
{
@ -69,7 +70,7 @@ index 6edf104c5e9..4b92379a0ff 100644
NTSTATUS status;
if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
@@ -528,8 +521,7 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable,
@@ -871,8 +864,7 @@ NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable,
else
RtlReleaseSRWLockExclusive( lock );
@ -80,10 +81,10 @@ index 6edf104c5e9..4b92379a0ff 100644
if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
RtlAcquireSRWLockShared( lock );
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 9633aaf3966..c2b713597d7 100644
index 5302b7f1638..bb25f50581c 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -2156,8 +2156,6 @@ static struct unix_funcs unix_funcs =
@@ -2157,8 +2157,6 @@ static struct unix_funcs unix_funcs =
fast_RtlAcquireSRWLockShared,
fast_RtlReleaseSRWLockExclusive,
fast_RtlReleaseSRWLockShared,
@ -93,10 +94,10 @@ index 9633aaf3966..c2b713597d7 100644
ntdll_ceil,
ntdll_cos,
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 42ac52c9704..99be558da12 100644
index 6a636d30f21..f0267c2df1c 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -170,23 +170,6 @@ static int *get_futex(void **ptr)
@@ -167,23 +167,6 @@ static int *get_futex(void **ptr)
return NULL;
}
@ -120,7 +121,7 @@ index 42ac52c9704..99be558da12 100644
#endif
@@ -2842,50 +2825,6 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
@@ -2807,50 +2790,6 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
return STATUS_SUCCESS;
}
@ -171,7 +172,7 @@ index 42ac52c9704..99be558da12 100644
#else
NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
@@ -2918,14 +2857,4 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
@@ -2883,14 +2822,4 @@ NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
return STATUS_NOT_IMPLEMENTED;
}
@ -187,10 +188,10 @@ index 42ac52c9704..99be558da12 100644
-
#endif
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index b5a0b4121bc..dd13a976a7f 100644
index d142fa894b1..f192215f32a 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -108,10 +108,7 @@ extern NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock ) DECLS
@@ -107,10 +107,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;
@ -202,9 +203,18 @@ index b5a0b4121bc..dd13a976a7f 100644
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 3834dc78728..f7e9dc0a214 100644
index d86501dfb5e..5b56f1f2cf1 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
{
@@ -46,9 +46,6 @@ struct unix_funcs
NTSTATUS (CDECL *fast_RtlAcquireSRWLockShared)( RTL_SRWLOCK *lock );
NTSTATUS (CDECL *fast_RtlReleaseSRWLockExclusive)( RTL_SRWLOCK *lock );

View File

@ -1,9 +1,10 @@
From 8071d356061b69182746fda71ec9f1b0e9a40e3d Mon Sep 17 00:00:00 2001
From f032b2f1811e4a13a817b69b1f81fa9171e70502 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Sun, 22 Nov 2020 20:51:10 -0600
Subject: [PATCH] ntdll: Reimplement SRW locks on top of Win32 futexes.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
---
dlls/ntdll/sync.c | 313 +++++++++++++++------------------
dlls/ntdll/unix/loader.c | 6 -
@ -13,10 +14,10 @@ Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
5 files changed, 142 insertions(+), 501 deletions(-)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 4b92379a0ff..2edc9f8d558 100644
index 6e68d07b81b..e380f3e4e93 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -160,127 +160,24 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu
@@ -503,127 +503,24 @@ DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN fu
return RtlRunOnceComplete( once, 0, context ? *context : NULL );
}
@ -74,13 +75,15 @@ index 4b92379a0ff..2edc9f8d558 100644
-#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;
@ -120,8 +123,7 @@ index 4b92379a0ff..2edc9f8d558 100644
-}
-
-static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
+struct srw_lock
{
-{
- /* Used when a thread leaves an exclusive section. If there are other
- * exclusive access threads they are processed first, followed by
- * the shared waiters. */
@ -134,8 +136,7 @@ index 4b92379a0ff..2edc9f8d558 100644
- NtReleaseKeyedEvent( 0, srwlock_key_shared(lock), FALSE, NULL );
- }
-}
+ short exclusive_waiters;
-
-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
@ -160,14 +161,16 @@ index 4b92379a0ff..2edc9f8d558 100644
/***********************************************************************
* RtlInitializeSRWLock (NTDLL.@)
@@ -307,11 +204,36 @@ void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
@@ -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 (;;)
@ -192,25 +195,23 @@ index 4b92379a0ff..2edc9f8d558 100644
+ wait = TRUE;
+ }
+ } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l);
- if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
- NtWaitForKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
+
+ if (!wait) return;
+ RtlWaitOnAddress( &u.s->owners, &new.s.owners, sizeof(short), NULL );
+ }
}
/***********************************************************************
@@ -323,34 +245,34 @@ void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
@@ -666,34 +588,34 @@ void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
*/
void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
{
- unsigned int val, tmp;
-
- if (unix_funcs->fast_RtlAcquireSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED)
- return;
+ 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)
@ -260,7 +261,7 @@ index 4b92379a0ff..2edc9f8d558 100644
}
/***********************************************************************
@@ -358,11 +280,23 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
@@ -701,11 +623,23 @@ void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
*/
void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
{
@ -268,16 +269,16 @@ index 4b92379a0ff..2edc9f8d558 100644
- 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);
- srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
- - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
+
+ new.s.owners = 0;
+ } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l);
+
@ -288,7 +289,7 @@ index 4b92379a0ff..2edc9f8d558 100644
}
/***********************************************************************
@@ -370,11 +304,22 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
@@ -713,11 +647,22 @@ void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
*/
void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
{
@ -296,7 +297,9 @@ index 4b92379a0ff..2edc9f8d558 100644
- 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;
@ -304,9 +307,7 @@ index 4b92379a0ff..2edc9f8d558 100644
+
+ 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);
- srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
- - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
+
+ --new.s.owners;
+ } while (InterlockedCompareExchange( u.l, new.l, old.l ) != old.l);
+
@ -315,7 +316,7 @@ index 4b92379a0ff..2edc9f8d558 100644
}
/***********************************************************************
@@ -386,13 +331,28 @@ void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
@@ -729,13 +674,28 @@ void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
*/
BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
{
@ -349,7 +350,7 @@ index 4b92379a0ff..2edc9f8d558 100644
}
/***********************************************************************
@@ -400,20 +360,29 @@ BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
@@ -743,20 +703,29 @@ BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
*/
BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
{
@ -392,10 +393,10 @@ index 4b92379a0ff..2edc9f8d558 100644
/***********************************************************************
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index f1767f2b568..99268914734 100644
index bb25f50581c..a8dc128adcf 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -1870,12 +1870,6 @@ static struct unix_funcs unix_funcs =
@@ -2151,12 +2151,6 @@ static struct unix_funcs unix_funcs =
#endif
DbgUiIssueRemoteBreakin,
RtlGetSystemTimePrecise,
@ -409,10 +410,10 @@ index f1767f2b568..99268914734 100644
ntdll_ceil,
ntdll_cos,
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 99be558da12..5a82cf7e539 100644
index f0267c2df1c..19a499ff2c9 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -118,8 +118,6 @@ static inline ULONGLONG monotonic_counter(void)
@@ -115,8 +115,6 @@ static inline ULONGLONG monotonic_counter(void)
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
@ -421,7 +422,7 @@ index 99be558da12..5a82cf7e539 100644
static int futex_private = 128;
@@ -133,16 +131,6 @@ static inline int futex_wake( const int *addr, int val )
@@ -130,16 +128,6 @@ static inline int futex_wake( const int *addr, int val )
return syscall( __NR_futex, addr, FUTEX_WAKE | futex_private, val, NULL, 0, 0 );
}
@ -438,7 +439,7 @@ index 99be558da12..5a82cf7e539 100644
static inline int use_futexes(void)
{
static int supported = -1;
@@ -160,16 +148,6 @@ static inline int use_futexes(void)
@@ -157,16 +145,6 @@ static inline int use_futexes(void)
return supported;
}
@ -455,7 +456,7 @@ index 99be558da12..5a82cf7e539 100644
#endif
@@ -2572,289 +2550,3 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
@@ -2537,289 +2515,3 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
}
#endif
@ -746,10 +747,10 @@ index 99be558da12..5a82cf7e539 100644
-
-#endif
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 452eb2790ab..8f85eb5ebc6 100644
index f192215f32a..fc52b7d210e 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -96,12 +96,6 @@ extern void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PT
@@ -101,12 +101,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;
@ -763,15 +764,15 @@ index 452eb2790ab..8f85eb5ebc6 100644
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 9d9842b4072..4aaa20d1795 100644
index 5b56f1f2cf1..a3eaf9a59d0 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 126
+#define NTDLL_UNIXLIB_VERSION 127
-#define NTDLL_UNIXLIB_VERSION 129
+#define NTDLL_UNIXLIB_VERSION 130
struct unix_funcs
{
@ -791,5 +792,5 @@ index 9d9842b4072..4aaa20d1795 100644
double (CDECL *atan)( double d );
double (CDECL *ceil)( double d );
--
2.30.2
2.33.0