Previously, InitialzeCriticalSectionEx with RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN worked as semi-stub.
This patch implements dynamic spinning. Specifically, 32th bit from the right (starting with zero index) indicates whether it is dynamically spinning critical section.
Signed-off-by: Jangwoong Kim 6812skiii@gmail.com --- dlls/ntdll/critsection.c | 45 +++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c index fe7d933c0fa..8642015e05c 100644 --- a/dlls/ntdll/critsection.c +++ b/dlls/ntdll/critsection.c @@ -20,6 +20,7 @@
#include <assert.h> #include <errno.h> +#include <limits.h> #include <stdarg.h> #include <stdio.h> #include <sys/types.h> @@ -34,6 +35,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntdll); WINE_DECLARE_DEBUG_CHANNEL(relay);
+#define IS_DYNAMIC_SPIN crit->SpinCount >> 31 == 1 ? TRUE : FALSE +#define MAX_ADAPTIVE_SPIN_COUNT 100 +#define MIN(a,b) (((a)<(b))?(a):(b)) + static inline void small_pause(void) { #ifdef __i386__ @@ -159,7 +164,7 @@ NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION * */ NTSTATUS WINAPI RtlInitializeCriticalSectionEx( RTL_CRITICAL_SECTION *crit, ULONG spincount, ULONG flags ) { - if (flags & (RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN|RTL_CRITICAL_SECTION_FLAG_STATIC_INIT)) + if (flags & RTL_CRITICAL_SECTION_FLAG_STATIC_INIT) FIXME("(%p,%u,0x%08x) semi-stub\n", crit, spincount, flags);
/* FIXME: if RTL_CRITICAL_SECTION_FLAG_STATIC_INIT is given, we should use @@ -189,8 +194,15 @@ NTSTATUS WINAPI RtlInitializeCriticalSectionEx( RTL_CRITICAL_SECTION *crit, ULON crit->RecursionCount = 0; crit->OwningThread = 0; crit->LockSemaphore = 0; + spincount = spincount & ~0x80000000; + if (flags & RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN) + { + spincount = MIN(spincount, MAX_ADAPTIVE_SPIN_COUNT); + /* 31th bit (from right starting with 0) indicates whether it is dynamically spinning CS */ + spincount |= ((ULONG)1 << 31); + } if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0; - crit->SpinCount = spincount & ~0x80000000; + crit->SpinCount = spincount; return STATUS_SUCCESS; }
@@ -403,14 +415,33 @@ NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit ) ULONG count;
if (RtlTryEnterCriticalSection( crit )) return STATUS_SUCCESS; - for (count = crit->SpinCount; count > 0; count--) + if (IS_DYNAMIC_SPIN) + { + ULONG max_count = MIN(MAX_ADAPTIVE_SPIN_COUNT, crit->SpinCount & ~0x80000000 * 2); + for (count = 0 ; count < max_count ; count++) { + if (crit->LockCount == -1) + { + if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) + { + crit->SpinCount += ((LONG)count - (LONG)(crit->SpinCount & ~0x80000000)) / 10; + goto done; + } + } + small_pause(); + } + crit->SpinCount += ((LONG)count - (LONG)(crit->SpinCount & ~0x80000000)) / 10; + } + else { - if (crit->LockCount > 0) break; /* more than one waiter, don't bother spinning */ - if (crit->LockCount == -1) /* try again */ + for (count = crit->SpinCount; count > 0; count--) { - if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) goto done; + if (crit->LockCount > 0) break; /* more than one waiter, don't bother spinning */ + if (crit->LockCount == -1) /* try again */ + { + if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) goto done; + } + small_pause(); } - small_pause(); } }