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(a)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();
}
}
--
2.25.1