The following patch implements all the goo related to SpinCount, by doing the following: 1) Implement RtlSetCriticalSectionSpinCount and make SetCriticalSectionSpinCount call down to it. 2) A bit more NtQuerySystemInformation implementation so we can determine if we're running as UP or SMP from within NTDLL. This is important, because SetCriticalSectionSpinCount and RtlInitializeCriticalSectionAndSpinCount have different semantics under the two environments. 3) Make RtlInitializeCriticalSection call RtlInitializeCriticalSectionAndSpinCount. This prevents the former call from creating a critical section with an uninitialized SpinCount value as it was before. 4) Make RtlpWaitForCriticalSection spin SpinCount times before calling WaitForSingleObject -Ryan
? controls/edit.glue.c ? dlls/gdi/printdrv.glue.c ? dlls/gdi/win16drv/prtdrv.glue.c ? dlls/kernel/utthunk.glue.c ? dlls/msvideo/msvideo_main.glue.c ? dlls/setupapi/virtcopy.glue.c ? dlls/user/property.glue.c ? dlls/user/text.glue.c ? dlls/user/wnd16.glue.c ? dlls/user/dde/ddeml16.glue.c ? dlls/winaspi/winaspi16.glue.c ? dlls/winmm/lolvldrv.glue.c ? dlls/winmm/mmsystem.glue.c ? dlls/winmm/time.glue.c ? loader/task.glue.c ? loader/ne/module.glue.c ? loader/ne/segment.glue.c ? memory/local.glue.c ? objects/dc.glue.c ? objects/font.glue.c ? objects/gdiobj.glue.c ? objects/linedda.glue.c ? objects/metafile.glue.c ? windows/driver.glue.c ? windows/hook.glue.c ? windows/painting.glue.c Index: dlls/ntdll/critsection.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/critsection.c,v retrieving revision 1.13 diff -u -r1.13 critsection.c --- dlls/ntdll/critsection.c 12 Sep 2002 22:07:03 -0000 1.13 +++ dlls/ntdll/critsection.c 13 Sep 2002 16:25:38 -0000 @@ -42,6 +42,22 @@ return interlocked_xchg_add( dest, -1 ) - 1; } +static BOOL is_smp() +{ + static BOOL cached = FALSE; + static BOOL value; + + if (!cached) + { + SYSTEM_BASIC_INFORMATION info; + NtQuerySystemInformation(0x0, &info, sizeof(info), 0); + value = (info.bKeNumberProcessors > 1); + cached = TRUE; + } + + return value; +} + /*********************************************************************** * get_semaphore */ @@ -66,12 +82,7 @@ */ NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit ) { - crit->DebugInfo = NULL; - crit->LockCount = -1; - crit->RecursionCount = 0; - crit->OwningThread = 0; - crit->LockSemaphore = 0; - return STATUS_SUCCESS; + return RtlInitializeCriticalSectionAndSpinCount( crit, 0 ); } /*********************************************************************** @@ -83,11 +94,38 @@ */ NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION *crit, DWORD spincount ) { - if(spincount) TRACE("critsection=%p: spincount=%ld not supported\n", crit, spincount); - crit->SpinCount = spincount; - return RtlInitializeCriticalSection( crit ); + crit->DebugInfo = NULL; + crit->LockCount = -1; + crit->RecursionCount = 0; + crit->OwningThread = 0; + crit->LockSemaphore = 0; + + if (spincount && is_smp()) + crit->SpinCount = spincount; + else + crit->SpinCount = 0; + + return STATUS_SUCCESS; } +/*********************************************************************** + * RtlSetCriticalSectionSpinCount (NTDLL.@) + */ +DWORD WINAPI RtlSetCriticalSectionSpinCount( RTL_CRITICAL_SECTION *crit, DWORD dwSpinCount ) +{ + DWORD ret = crit->SpinCount; + + if (dwSpinCount && is_smp()) + { + crit->SpinCount = dwSpinCount; + } + else + { + crit->SpinCount = 0; + } + + return ret; +} /*********************************************************************** * RtlDeleteCriticalSection (NTDLL.@) @@ -112,6 +150,16 @@ { EXCEPTION_RECORD rec; HANDLE sem = get_semaphore( crit ); + ULONG tries; + + /* Try spinning on the lock a bit before going to + WaitForSingleObject. This path should only be + followed on SMP systems. */ + for(tries = crit->SpinCount;tries;tries--) + { + if (RtlTryEnterCriticalSection(crit)) + return STATUS_SUCCESS; + } DWORD res = WaitForSingleObject( sem, 5000L ); if ( res == WAIT_TIMEOUT ) Index: dlls/ntdll/nt.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/nt.c,v retrieving revision 1.44 diff -u -r1.44 nt.c --- dlls/ntdll/nt.c 12 Sep 2002 22:07:03 -0000 1.44 +++ dlls/ntdll/nt.c 13 Sep 2002 16:25:38 -0000 @@ -24,6 +24,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #include <time.h> #include "wine/debug.h" @@ -31,6 +32,10 @@ #include "ntdll_misc.h" #include "wine/server.h" +#ifdef linux +#include <sys/sysinfo.h> +#endif + WINE_DEFAULT_DEBUG_CHANNEL(ntdll); /* @@ -650,8 +655,33 @@ IN ULONG Length, OUT PULONG ResultLength) { + SYSTEM_BASIC_INFORMATION *basic_info = (SYSTEM_BASIC_INFORMATION*)SystemInformation; + switch(SystemInformationClass) { + case 0x0: + ZeroMemory (SystemInformation, Length); + + /* Fill out a few choice fields */ + + if (ResultLength) + *ResultLength = sizeof(SYSTEM_BASIC_INFORMATION); + + basic_info->uPageSize = getpagesize(); + +#ifdef linux + { + struct sysinfo info; + sysinfo(&info); + basic_info->bKeNumberProcessors = info.procs; + } +#else + basic_info->bKeNumberProcessors = 1; +#endif + + FIXME("(0x%08x,%p,0x%08lx,%p) partial stub\n", + SystemInformationClass,SystemInformation,Length,ResultLength); + case 0x25: /* Something to do with the size of the registry * * Since we don't have a size limitation, fake it * Index: dlls/ntdll/ntdll.spec =================================================================== RCS file: /home/wine/wine/dlls/ntdll/ntdll.spec,v retrieving revision 1.76 diff -u -r1.76 ntdll.spec --- dlls/ntdll/ntdll.spec 6 Sep 2002 18:51:32 -0000 1.76 +++ dlls/ntdll/ntdll.spec 13 Sep 2002 16:25:39 -0000 @@ -499,6 +499,7 @@ @ stub RtlSelfRelativeToAbsoluteSD @ stdcall RtlSetAllBits(ptr) RtlSetAllBits @ stdcall RtlSetBits(ptr long long) RtlSetBits +@ stdcall RtlSetCriticalSectionSpinCount(ptr long) RtlSetCriticalSectionSpinCount @ stub RtlSetCurrentDirectory_U @ stub RtlSetCurrentEnvironment @ stdcall RtlSetDaclSecurityDescriptor(ptr long ptr long) RtlSetDaclSecurityDescriptor Index: include/winternl.h =================================================================== RCS file: /home/wine/wine/include/winternl.h,v retrieving revision 1.2 diff -u -r1.2 winternl.h --- include/winternl.h 12 Sep 2002 22:07:05 -0000 1.2 +++ include/winternl.h 13 Sep 2002 16:25:39 -0000 @@ -950,6 +950,7 @@ void WINAPI RtlSecondsSince1980ToTime(DWORD,LARGE_INTEGER *); void WINAPI RtlSetAllBits(PRTL_BITMAP); void WINAPI RtlSetBits(PRTL_BITMAP,ULONG,ULONG); +DWORD WINAPI RtlSetCriticalSectionSpinCount(RTL_CRITICAL_SECTION *,DWORD); NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOLEAN,PACL,BOOLEAN); DWORD WINAPI RtlSetEnvironmentVariable(DWORD,PUNICODE_STRING,PUNICODE_STRING); NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR,PSID,BOOLEAN); Index: scheduler/critsection.c =================================================================== RCS file: /home/wine/wine/scheduler/critsection.c,v retrieving revision 1.35 diff -u -r1.35 critsection.c --- scheduler/critsection.c 12 Sep 2002 22:07:06 -0000 1.35 +++ scheduler/critsection.c 13 Sep 2002 16:25:44 -0000 @@ -61,10 +61,7 @@ */ DWORD WINAPI SetCriticalSectionSpinCount( CRITICAL_SECTION *crit, DWORD spincount ) { - ULONG_PTR oldspincount = crit->SpinCount; - if(spincount) FIXME("critsection=%p: spincount=%ld not supported\n", crit, spincount); - crit->SpinCount = spincount; - return oldspincount; + return RtlSetCriticalSectionSpinCount( crit, spincount ); } /***********************************************************************