Rewrite ROS Critical Section implementation, which was slow and broken
(because it always created an event, which is the slow path). Note that
coincidentally, Gunnar also fixed this code and committed a patch this
morning, taken from WINE. This code is also based on WINE, but adds more
features which WINE does not support/need yet (regarding Debug CS).
Hence, this code was a re-write of the original ROS code, not of
Gunnar's, and we've both discussed the accidental conflict.
Modified: trunk/reactos/include/funcs.h
Modified: trunk/reactos/include/ntdll/rtl.h
Modified: trunk/reactos/lib/advapi32/reg/reg.c
Modified: trunk/reactos/lib/kernel32/include/kernel32.h
Modified: trunk/reactos/lib/kernel32/misc/console.c
Modified: trunk/reactos/lib/kernel32/misc/dllmain.c
Modified: trunk/reactos/lib/kernel32/misc/lcformat.c
Modified: trunk/reactos/lib/kernel32/misc/nls.c
Modified: trunk/reactos/lib/kernel32/misc/profile.c
Modified: trunk/reactos/lib/kernel32/synch/critical.c
Modified: trunk/reactos/lib/ntdll/ldr/startup.c
Modified: trunk/reactos/lib/ntdll/rtl/critical.c
Modified: trunk/reactos/subsys/csrss/api/process.c
Modified: trunk/reactos/subsys/csrss/include/api.h
Modified: trunk/reactos/subsys/csrss/win32csr/conio.c
Modified: trunk/reactos/subsys/csrss/win32csr/dllmain.c
Modified: trunk/reactos/subsys/csrss/win32csr/guiconsole.c
_____
Modified: trunk/reactos/include/funcs.h
--- trunk/reactos/include/funcs.h 2005-01-03 22:53:21 UTC (rev
12765)
+++ trunk/reactos/include/funcs.h 2005-01-03 23:02:15 UTC (rev
12766)
@@ -2082,8 +2082,6 @@
DWORD STDCALL RtlDeleteSecurityObject(DWORD x1);
DWORD STDCALL RtlNewSecurityObject(DWORD x1,DWORD x2,DWORD x3,DWORD
x4,DWORD x5,DWORD x6);
NTSTATUS STDCALL RtlWalkHeap( HANDLE heap, PVOID entry_ptr );
-NTSTATUS STDCALL RtlpUnWaitCriticalSection(RTL_CRITICAL_SECTION
*crit);
-NTSTATUS STDCALL RtlpWaitForCriticalSection(RTL_CRITICAL_SECTION
*crit);
NTSTATUS STDCALL LdrLockLoaderLock(ULONG flags, ULONG *result, ULONG
*magic);
NTSTATUS STDCALL LdrUnlockLoaderLock(ULONG flags, ULONG magic);
_____
Modified: trunk/reactos/include/ntdll/rtl.h
--- trunk/reactos/include/ntdll/rtl.h 2005-01-03 22:53:21 UTC (rev
12765)
+++ trunk/reactos/include/ntdll/rtl.h 2005-01-03 23:02:15 UTC (rev
12766)
@@ -99,8 +99,8 @@
LIST_ENTRY ProcessLocksList;
ULONG EntryCount;
ULONG ContentionCount;
- ULONG Depth;
- PVOID Spare[ 2 ];
+ PVOID OwnerBackTrace[2];
+ PVOID Spare[2];
} CRITICAL_SECTION_DEBUG, *PCRITICAL_SECTION_DEBUG;
@@ -114,9 +114,13 @@
ULONG_PTR SpinCount;
} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION;
+#define RTL_CRITSECT_TYPE 0
+
typedef CRITICAL_SECTION RTL_CRITICAL_SECTION;
typedef PCRITICAL_SECTION PRTL_CRITICAL_SECTION;
typedef LPCRITICAL_SECTION LPRTL_CRITICAL_SECTION;
+typedef CRITICAL_SECTION_DEBUG RTL_CRITICAL_SECTION_DEBUG;
+typedef PCRITICAL_SECTION_DEBUG PRTL_CRITICAL_SECTION_DEBUG;
#endif /* !__USE_W32API */
@@ -166,7 +170,30 @@
#define PDI_HEAP_BLOCKS 0x10 /* The heap blocks */
#define PDI_LOCKS 0x20 /* The locks created by the process */
+NTSTATUS
+STDCALL
+RtlpWaitForCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection
+);
+VOID
+STDCALL
+RtlpUnWaitCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+VOID
+STDCALL
+RtlpCreateCriticalSectionSem(
+ PRTL_CRITICAL_SECTION CriticalSection
+);
+
+VOID
+STDCALL
+RtlpInitDeferedCriticalSection(
+ VOID
+);
+
NTSTATUS STDCALL
RtlAddAccessAllowedAceEx (IN OUT PACL Acl,
IN ULONG Revision,
@@ -191,19 +218,19 @@
IN BOOLEAN Failure);
NTSTATUS STDCALL
-RtlDeleteCriticalSection (PCRITICAL_SECTION CriticalSection);
+RtlDeleteCriticalSection (PRTL_CRITICAL_SECTION CriticalSection);
WCHAR STDCALL
RtlDowncaseUnicodeChar(IN WCHAR Source);
NTSTATUS STDCALL
-RtlEnterCriticalSection (PCRITICAL_SECTION CriticalSection);
+RtlEnterCriticalSection (PRTL_CRITICAL_SECTION CriticalSection);
NTSTATUS STDCALL
-RtlInitializeCriticalSection (PCRITICAL_SECTION CriticalSection);
+RtlInitializeCriticalSection (PRTL_CRITICAL_SECTION CriticalSection);
NTSTATUS STDCALL
-RtlInitializeCriticalSectionAndSpinCount (PCRITICAL_SECTION
CriticalSection,
+RtlInitializeCriticalSectionAndSpinCount (PRTL_CRITICAL_SECTION
CriticalSection,
ULONG SpinCount);
NTSTATUS STDCALL
@@ -212,10 +239,10 @@
PUNICODE_STRING String);
NTSTATUS STDCALL
-RtlLeaveCriticalSection (PCRITICAL_SECTION CriticalSection);
+RtlLeaveCriticalSection (PRTL_CRITICAL_SECTION CriticalSection);
BOOLEAN STDCALL
-RtlTryEnterCriticalSection (PCRITICAL_SECTION CriticalSection);
+RtlTryEnterCriticalSection (PRTL_CRITICAL_SECTION CriticalSection);
DWORD STDCALL
RtlCompactHeap (
_____
Modified: trunk/reactos/lib/advapi32/reg/reg.c
--- trunk/reactos/lib/advapi32/reg/reg.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/advapi32/reg/reg.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -1,4 +1,4 @@
-/* $Id: reg.c,v 1.67 2004/12/26 23:09:51 gvg Exp $
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@@ -24,7 +24,7 @@
/* GLOBALS
******************************************************************/
-static CRITICAL_SECTION HandleTableCS;
+static RTL_CRITICAL_SECTION HandleTableCS;
static HANDLE DefaultHandleTable[MAX_DEFAULT_HANDLES];
static HANDLE ProcessHeap;
_____
Modified: trunk/reactos/lib/kernel32/include/kernel32.h
--- trunk/reactos/lib/kernel32/include/kernel32.h 2005-01-03
22:53:21 UTC (rev 12765)
+++ trunk/reactos/lib/kernel32/include/kernel32.h 2005-01-03
23:02:15 UTC (rev 12766)
@@ -39,7 +39,7 @@
extern HANDLE hBaseDir;
extern HMODULE hCurrentModule;
-extern CRITICAL_SECTION DllLock;
+extern RTL_CRITICAL_SECTION DllLock;
extern UNICODE_STRING DllDirectory;
_____
Modified: trunk/reactos/lib/kernel32/misc/console.c
--- trunk/reactos/lib/kernel32/misc/console.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/kernel32/misc/console.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.89 2004/12/24 17:45:57 weiden Exp $
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@@ -21,7 +21,7 @@
extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
extern __declspec(noreturn) VOID CALLBACK
ConsoleControlDispatcher(DWORD CodeAndFlag);
-extern CRITICAL_SECTION ConsoleLock;
+extern RTL_CRITICAL_SECTION ConsoleLock;
extern BOOL WINAPI IsDebuggerPresent(VOID);
_____
Modified: trunk/reactos/lib/kernel32/misc/dllmain.c
--- trunk/reactos/lib/kernel32/misc/dllmain.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/kernel32/misc/dllmain.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -1,4 +1,4 @@
-/* $Id: dllmain.c,v 1.38 2004/11/29 00:08:59 gdalsnes Exp $
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@@ -33,8 +33,8 @@
LPVOID lpReserved);
/* Critical section for various kernel32 data structures */
-CRITICAL_SECTION DllLock;
-CRITICAL_SECTION ConsoleLock;
+RTL_CRITICAL_SECTION DllLock;
+RTL_CRITICAL_SECTION ConsoleLock;
extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
_____
Modified: trunk/reactos/lib/kernel32/misc/lcformat.c
--- trunk/reactos/lib/kernel32/misc/lcformat.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/kernel32/misc/lcformat.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -82,15 +82,15 @@
#define GetShortMonth(fmt,mth) fmt->lppszStrings[30 + mth]
/* Write access to the cache is protected by this critical section */
-static CRITICAL_SECTION NLS_FormatsCS;
-static CRITICAL_SECTION_DEBUG NLS_FormatsCS_debug =
+static RTL_CRITICAL_SECTION NLS_FormatsCS;
+static RTL_CRITICAL_SECTION_DEBUG NLS_FormatsCS_debug =
{
0, 0, &NLS_FormatsCS,
{ &NLS_FormatsCS_debug.ProcessLocksList,
&NLS_FormatsCS_debug.ProcessLocksList },
0, 0, { 0, (DWORD)(__FILE__ ": NLS_Formats") }
};
-static CRITICAL_SECTION NLS_FormatsCS = { &NLS_FormatsCS_debug, -1, 0,
0, 0, 0 };
+static RTL_CRITICAL_SECTION NLS_FormatsCS = { &NLS_FormatsCS_debug, -1,
0, 0, 0, 0 };
/***********************************************************************
***
* NLS_GetLocaleNumber <internal>
_____
Modified: trunk/reactos/lib/kernel32/misc/nls.c
--- trunk/reactos/lib/kernel32/misc/nls.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/kernel32/misc/nls.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -58,7 +58,7 @@
static LIST_ENTRY CodePageListHead;
static CODEPAGE_ENTRY AnsiCodePage;
static CODEPAGE_ENTRY OemCodePage;
-static CRITICAL_SECTION CodePageListLock;
+static RTL_CRITICAL_SECTION CodePageListLock;
/* FORWARD DECLARATIONS
*******************************************************/
_____
Modified: trunk/reactos/lib/kernel32/misc/profile.c
--- trunk/reactos/lib/kernel32/misc/profile.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/kernel32/misc/profile.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -72,14 +72,14 @@
static const WCHAR emptystringW[] = {0};
-static CRITICAL_SECTION PROFILE_CritSect;
-static CRITICAL_SECTION_DEBUG critsect_debug =
+static RTL_CRITICAL_SECTION PROFILE_CritSect;
+static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &PROFILE_CritSect,
{ &critsect_debug.ProcessLocksList,
&critsect_debug.ProcessLocksList },
0, 0, { 0, (DWORD)(__FILE__ ": PROFILE_CritSect") }
};
-static CRITICAL_SECTION PROFILE_CritSect = { &critsect_debug, -1, 0, 0,
0, 0 };
+static RTL_CRITICAL_SECTION PROFILE_CritSect = { &critsect_debug, -1,
0, 0, 0, 0 };
static const char hex[16] = "0123456789ABCDEF";
_____
Modified: trunk/reactos/lib/kernel32/synch/critical.c
--- trunk/reactos/lib/kernel32/synch/critical.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/kernel32/synch/critical.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -1,4 +1,4 @@
-/* $Id: critical.c,v 1.16 2004/01/29 23:41:36 navaraf Exp $
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
@@ -26,7 +26,7 @@
{
NTSTATUS Status;
- Status = RtlInitializeCriticalSection(lpCriticalSection);
+ Status =
RtlInitializeCriticalSection((PRTL_CRITICAL_SECTION)lpCriticalSection);
if (!NT_SUCCESS(Status))
{
RtlRaiseStatus(Status);
@@ -45,7 +45,7 @@
{
NTSTATUS Status;
- Status =
RtlInitializeCriticalSectionAndSpinCount(lpCriticalSection,
dwSpinCount);
+ Status =
RtlInitializeCriticalSectionAndSpinCount((PRTL_CRITICAL_SECTION)lpCritic
alSection, dwSpinCount);
if (Status)
{
RtlRaiseStatus(Status);
_____
Modified: trunk/reactos/lib/ntdll/ldr/startup.c
--- trunk/reactos/lib/ntdll/ldr/startup.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/ntdll/ldr/startup.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -1,4 +1,4 @@
-/* $Id: startup.c,v 1.60 2004/12/15 03:00:33 royce Exp $
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@@ -259,6 +259,7 @@
/* If MZ header exists */
PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
DPRINT("PEDosHeader %x\n", PEDosHeader);
+
if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
PEDosHeader->e_lfanew == 0L ||
*(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) !=
IMAGE_PE_MAGIC)
@@ -279,6 +280,9 @@
NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase +
PEDosHeader->e_lfanew);
+ /* Initialize Critical Section Data */
+ RtlpInitDeferedCriticalSection();
+
/* create process heap */
RtlInitializeHeapManager();
Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
@@ -292,7 +296,7 @@
DPRINT1("Failed to create process heap\n");
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
}
-
+
/* initalize peb lock support */
RtlInitializeCriticalSection (&PebLock);
Peb->FastPebLock = &PebLock;
@@ -311,7 +315,7 @@
RtlAllocateHeap(RtlGetProcessHeap(),
0,
sizeof(PVOID) * (USER32_CALLBACK_MAXIMUM +
1));
-
+
/* initalize loader lock */
RtlInitializeCriticalSection (&LoaderLock);
Peb->LoaderLock = &LoaderLock;
_____
Modified: trunk/reactos/lib/ntdll/rtl/critical.c
--- trunk/reactos/lib/ntdll/rtl/critical.c 2005-01-03 22:53:21 UTC
(rev 12765)
+++ trunk/reactos/lib/ntdll/rtl/critical.c 2005-01-03 23:02:15 UTC
(rev 12766)
@@ -6,6 +6,8 @@
* PURPOSE: Critical sections
* UPDATE HISTORY:
* Created 30/09/98
+ * Rewritten ROS version, based on WINE code plus
+ * some fixes useful only for ROS right now - 03/01/05
*/
/* INCLUDES
******************************************************************/
@@ -19,391 +21,532 @@
/* FUNCTIONS
*****************************************************************/
-inline static HANDLE RtlGetCurrentThreadId()
-{
- return (HANDLE)NtCurrentTeb()->Cid.UniqueThread;
-}
+static RTL_CRITICAL_SECTION RtlCriticalSectionLock;
+static LIST_ENTRY RtlCriticalSectionList;
+static BOOLEAN RtlpCritSectInitialized = FALSE;
-inline static void small_pause(void)
+/*++
+ * RtlDeleteCriticalSection
+ * @implemented NT4
+ *
+ * Deletes a Critical Section
+ *
+ * Params:
+ * CriticalSection - Critical section to delete.
+ *
+ * Returns:
+ * STATUS_SUCCESS, or error value returned by NtClose.
+ *
+ * Remarks:
+ * The critical section members should not be read after this call.
+ *
+ *--*/
+NTSTATUS
+STDCALL
+RtlDeleteCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
{
-#ifdef __i386__
- __asm__ __volatile__( "rep;nop" : : : "memory" );
-#else
- __asm__ __volatile__( "" : : : "memory" );
-#endif
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /* Close the Event Object Handle if it exists */
+ if (CriticalSection->LockSemaphore) {
+ Status = NtClose(CriticalSection->LockSemaphore);
+ }
+
+ /* Protect List */
+ RtlEnterCriticalSection(&RtlCriticalSectionLock);
+
+ /* Delete the Debug Data, if it exists */
+ if (CriticalSection->DebugInfo) {
+
+ /* Remove it from the list */
+ RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList);
+
+ /* Free it */
+ RtlFreeHeap(RtlGetProcessHeap(), 0,
CriticalSection->DebugInfo);
+ }
+
+ /* Unprotect */
+ RtlLeaveCriticalSection(&RtlCriticalSectionLock);
+
+ /* Wipe it out */
+ RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
+
+ /* Return */
+ return Status;
}
-/**********************************************************************
*
- * get_semaphore
- */
-static inline HANDLE get_semaphore( PCRITICAL_SECTION crit )
-{
- HANDLE ret = crit->LockSemaphore;
- if (!ret)
- {
- HANDLE sem;
- if (!NT_SUCCESS(NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS,
NULL, 0, 1 ))) return 0;
- if (!(ret = (HANDLE)InterlockedCompareExchangePointer( (PVOID
*)&crit->LockSemaphore,
- (PVOID)sem, 0 )))
- ret = sem;
- else
- NtClose(sem); /* somebody beat us to it */
- }
- return ret;
+/*++
+ * RtlSetCriticalSectionSpinCount
+ * @implemented NT4
+ *
+ * Sets the spin count for a critical section.
+ *
+ * Params:
+ * CriticalSection - Critical section to set the spin count for.
+ *
+ * SpinCount - Spin count for the critical section.
+ *
+ * Returns:
+ * STATUS_SUCCESS.
+ *
+ * Remarks:
+ * SpinCount is ignored on single-processor systems.
+ *
+ *--*/
+DWORD
+STDCALL
+RtlSetCriticalSectionSpinCount(
+ PRTL_CRITICAL_SECTION CriticalSection,
+ DWORD SpinCount
+ )
+{
+ DWORD OldCount = CriticalSection->SpinCount;
+
+ /* Set to parameter if MP, or to 0 if this is Uniprocessor */
+ CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors >
1) ? SpinCount : 0;
+ return OldCount;
}
-/**********************************************************************
*
- * RtlInitializeCriticalSection (NTDLL.@)
+/*++
+ * RtlEnterCriticalSection
+ * @implemented NT4
*
- * Initialises a new critical section.
+ * Waits to gain ownership of the critical section.
*
- * PARAMS
- * crit [O] Critical section to initialise
+ * Params:
+ * CriticalSection - Critical section to wait for.
*
- * RETURNS
- * STATUS_SUCCESS.
+ * Returns:
+ * STATUS_SUCCESS.
*
- * SEE
- * RtlInitializeCriticalSectionAndSpinCount(),
RtlDeleteCriticalSection(),
- * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
- * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
- */
-NTSTATUS STDCALL RtlInitializeCriticalSection( PCRITICAL_SECTION crit )
+ * Remarks:
+ * Uses a fast-path unless contention happens.
+ *
+ *--*/
+NTSTATUS
+STDCALL
+RtlEnterCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
{
- return RtlInitializeCriticalSectionAndSpinCount( crit, 0 );
+ HANDLE Thread = (HANDLE)NtCurrentTeb()->Cid.UniqueThread;
+
+ /* Try to Lock it */
+ if (InterlockedIncrement(&CriticalSection->LockCount)) {
+
+ /*
+ * We've failed to lock it! Does this thread
+ * actually own it?
+ */
+ if (Thread == CriticalSection->OwningThread) {
+
+ /* You own it, so you'll get it when you're done with it!
*/
+ CriticalSection->RecursionCount++;
+ return STATUS_SUCCESS;
+ }
+
+ /* We don't own it, so we must wait for it */
+ RtlpWaitForCriticalSection(CriticalSection);
+ }
+
+ /* Lock successful */
+ CriticalSection->OwningThread = Thread;
+ CriticalSection->RecursionCount = 1;
+ return STATUS_SUCCESS;
}
-/**********************************************************************
*
- * RtlInitializeCriticalSectionAndSpinCount (NTDLL.@)
+/*++
+ * RtlInitializeCriticalSection
+ * @implemented NT4
*
- * Initialises a new critical section with a given spin count.
+ * Initialises a new critical section.
*
- * PARAMS
- * crit [O] Critical section to initialise
- * spincount [I] Spin count for crit
- *
- * RETURNS
- * STATUS_SUCCESS.
+ * Params:
+ * CriticalSection - Critical section to initialise
*
- * NOTES
- * Available on NT4 SP3 or later.
+ * Returns:
+ * STATUS_SUCCESS.
*
- * SEE
- * RtlInitializeCriticalSection(), RtlDeleteCriticalSection(),
- * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
- * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
- */
-NTSTATUS STDCALL RtlInitializeCriticalSectionAndSpinCount(
PCRITICAL_SECTION crit, ULONG spincount )
-{
- /* Does ROS need this, or is this special to Wine? And if ros need
it, should
- it be enabled in the release build? -Gunnar */
- if (RtlGetProcessHeap()) crit->DebugInfo = NULL;
- else
- {
- crit->DebugInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0,
sizeof(CRITICAL_SECTION_DEBUG));
- if (crit->DebugInfo)
- {
- crit->DebugInfo->Type = 0;
- crit->DebugInfo->CreatorBackTraceIndex = 0;
- crit->DebugInfo->CriticalSection = crit;
- crit->DebugInfo->ProcessLocksList.Blink =
&(crit->DebugInfo->ProcessLocksList);
- crit->DebugInfo->ProcessLocksList.Flink =
&(crit->DebugInfo->ProcessLocksList);
- crit->DebugInfo->EntryCount = 0;
- crit->DebugInfo->ContentionCount = 0;
- crit->DebugInfo->Spare[0] = 0;
- crit->DebugInfo->Spare[1] = 0;
- }
- }
- crit->LockCount = -1;
- crit->RecursionCount = 0;
- crit->OwningThread = 0;
- crit->LockSemaphore = 0;
- crit->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ?
spincount : 0;
- return STATUS_SUCCESS;
+ * Remarks:
+ * Simply calls RtlInitializeCriticalSectionAndSpinCount
+ *
+ *--*/
+NTSTATUS
+STDCALL
+RtlInitializeCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
+{
+ /* Call the Main Function */
+ return RtlInitializeCriticalSectionAndSpinCount(CriticalSection,
0);
}
-/**********************************************************************
*
- * RtlSetCriticalSectionSpinCount (NTDLL.@)
+/*++
+ * RtlInitializeCriticalSectionAndSpinCount
+ * @implemented NT4
*
- * Sets the spin count of a critical section.
+ * Initialises a new critical section.
*
- * PARAMS
- * crit [I/O] Critical section
- * spincount [I] Spin count for crit
+ * Params:
+ * CriticalSection - Critical section to initialise
*
- * RETURNS
- * The previous spin count.
+ * SpinCount - Spin count for the critical section.
*
- * NOTES
- * If the system is not SMP, spincount is ignored and set to 0.
+ * Returns:
+ * STATUS_SUCCESS.
*
- * SEE
- * RtlInitializeCriticalSection(),
RtlInitializeCriticalSectionAndSpinCount(),
- * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
- * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
- */
-ULONG STDCALL RtlSetCriticalSectionSpinCount( PCRITICAL_SECTION crit,
ULONG spincount )
+ * Remarks:
+ * SpinCount is ignored on single-processor systems.
+ *
+ *--*/
+NTSTATUS
+STDCALL
+RtlInitializeCriticalSectionAndSpinCount (
+ PRTL_CRITICAL_SECTION CriticalSection,
+ DWORD SpinCount)
{
- ULONG oldspincount = crit->SpinCount;
- crit->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ?
spincount : 0;
- return oldspincount;
+ PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
+ PVOID Heap;
+
+ /* First things first, set up the Object */
+ CriticalSection->LockCount = -1;
+ CriticalSection->RecursionCount = 0;
+ CriticalSection->OwningThread = 0;
+ CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors >
1) ? SpinCount : 0;
+
+ /*
+ * Now set up the Debug Data
+ * Think of a better way to allocate it, because the Heap Manager
won't
+ * have any debug data since the Heap isn't initalized!
+ */
+ if ((Heap = RtlGetProcessHeap())) {
+
+ CritcalSectionDebugData = RtlAllocateHeap(Heap, 0,
sizeof(RTL_CRITICAL_SECTION_DEBUG));
+ CritcalSectionDebugData->Type = RTL_CRITSECT_TYPE;
+ CritcalSectionDebugData->ContentionCount = 0;
+ CritcalSectionDebugData->EntryCount = 0;
+ CritcalSectionDebugData->CriticalSection = CriticalSection;
+ CriticalSection->DebugInfo = CritcalSectionDebugData;
+
+ /*
+ * Add it to the List of Critical Sections owned by the
process.
+ * If we've initialized the Lock, then use it. If not, then
probably
+ * this is the lock initialization itself, so insert it
directly.
+ */
+ if ((CriticalSection != &RtlCriticalSectionLock) &&
(RtlpCritSectInitialized)) {
+
+ /* Protect List */
+ RtlEnterCriticalSection(&RtlCriticalSectionLock);
+
+ /* Add this one */
+ InsertTailList(&RtlCriticalSectionList,
&CritcalSectionDebugData->ProcessLocksList);
+
+ /* Unprotect */
+ RtlLeaveCriticalSection(&RtlCriticalSectionLock);
+
+ } else {
+
+ /* Add it directly */
+ InsertTailList(&RtlCriticalSectionList,
&CritcalSectionDebugData->ProcessLocksList);
+ }
+
+ } else {
+
+ /* This shouldn't happen... */
+ CritcalSectionDebugData = NULL;
+ }
+
+ return STATUS_SUCCESS;
}
-/**********************************************************************
*
- * RtlDeleteCriticalSection (NTDLL.@)
+/*++
+ * RtlLeaveCriticalSection
+ * @implemented NT4
*
- * Frees the resources used by a critical section.
+ * Releases a critical section and makes if available for new
owners.
*
- * PARAMS
- * crit [I/O] Critical section to free
+ * Params:
+ * CriticalSection - Critical section to release.
*
- * RETURNS
- * STATUS_SUCCESS.
+ * Returns:
+ * STATUS_SUCCESS.
*
- * SEE
- * RtlInitializeCriticalSection(),
RtlInitializeCriticalSectionAndSpinCount(),
- * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
- * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
- */
-NTSTATUS STDCALL RtlDeleteCriticalSection( PCRITICAL_SECTION crit )
-{
- crit->LockCount = -1;
- crit->RecursionCount = 0;
- crit->OwningThread = (HANDLE)0;
- if (crit->LockSemaphore)
- NtClose( crit->LockSemaphore );
- crit->LockSemaphore = 0;
- if (crit->DebugInfo)
- {
- /* only free the ones we made in here */
- if (!crit->DebugInfo->Spare[1])
- {
- RtlFreeHeap( RtlGetProcessHeap(), 0, crit->DebugInfo );
- crit->DebugInfo = NULL;
- }
- }
- return STATUS_SUCCESS;
+ * Remarks:
+ * If another thread was waiting, the slow path is entered.
+ *
+ *--*/
+NTSTATUS
+STDCALL
+RtlLeaveCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
+{
+ /* Decrease the Recursion Count */
+ if (--CriticalSection->RecursionCount) {
+
+ /* Someone still owns us, but we are free */
+ InterlockedDecrement(&CriticalSection->LockCount);
+
+ } else {
+
+ /* Nobody owns us anymore */
+ CriticalSection->OwningThread = 0;
+
+ /* Was someone wanting us? */
+ if (InterlockedDecrement(&CriticalSection->LockCount) >= 0) {
+
+ /* Let him have us */
+ RtlpUnWaitCriticalSection(CriticalSection);
+
+ }
+ }
+
+ /* Sucessful! */
+ return STATUS_SUCCESS;
}
-
-/**********************************************************************
*
- * RtlpWaitForCriticalSection (NTDLL.@)
+/*++
+ * RtlTryEnterCriticalSection
+ * @implemented NT4
*
- * Waits for a busy critical section to become free.
- *
- * PARAMS
- * crit [I/O] Critical section to wait for
+ * Attemps to gain ownership of the critical section without
waiting.
*
- * RETURNS
- * STATUS_SUCCESS.
+ * Params:
+ * CriticalSection - Critical section to attempt acquiring.
*
- * NOTES
- * Use RtlEnterCriticalSection() instead of this function as it is
often much
- * faster.
+ * Returns:
+ * TRUE if the critical section has been acquired, FALSE otherwise.
*
- * SEE
- * RtlInitializeCriticalSection(),
RtlInitializeCriticalSectionAndSpinCount(),
- * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
- * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
- */
-NTSTATUS STDCALL RtlpWaitForCriticalSection( PCRITICAL_SECTION crit )
-{
- for (;;)
- {
- EXCEPTION_RECORD rec;
- HANDLE sem = get_semaphore( crit );
- LARGE_INTEGER time;
- NTSTATUS status;
+ * Remarks:
+ * None
+ *
+ *--*/
+BOOLEAN
+STDCALL
+RtlTryEnterCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
+{
+ /* Try to take control */
+ if (InterlockedCompareExchange(&CriticalSection->LockCount,
+ 0,
+ -1) == -1) {
- time.QuadPart = -5000 * 10000; /* 5 seconds */
- status = NtWaitForSingleObject( sem, FALSE, &time );
- if ( status == STATUS_TIMEOUT )
- {
- const char *name = NULL;
- if (crit->DebugInfo) name = (char *)crit->DebugInfo->Spare[1];
- if (!name) name = "?";
- DPRINT1( "section %p %s wait timed out in thread %04lx,
blocked by %04lx, retrying (60 sec)\n",
- crit, name, RtlGetCurrentThreadId(),
(DWORD)crit->OwningThread );
- time.QuadPart = -60000 * 10000;
- status = NtWaitForSingleObject( sem, FALSE, &time );
- if ( status == STATUS_TIMEOUT /*&& TRACE_ON(relay)*/ )
- {
- DPRINT1( "section %p %s wait timed out in thread %04lx,
blocked by %04lx, retrying (5 min)\n",
- crit, name, RtlGetCurrentThreadId(), (DWORD)
crit->OwningThread );
- time.QuadPart = -300000 * (ULONGLONG)10000;
- status = NtWaitForSingleObject( sem, FALSE, &time );
- }
- }
- if (status == STATUS_WAIT_0) return STATUS_SUCCESS;
-
- /* Throw exception only for Wine internal locks */
- if ((!crit->DebugInfo) || (!crit->DebugInfo->Spare[1])) continue;
-
- rec.ExceptionCode = STATUS_POSSIBLE_DEADLOCK;
- rec.ExceptionFlags = 0;
- rec.ExceptionRecord = NULL;
- rec.ExceptionAddress = RtlRaiseException; /* sic */
- rec.NumberParameters = 1;
- rec.ExceptionInformation[0] = (DWORD)crit;
- RtlRaiseException( &rec );
- }
+ /* It's ours */
+ CriticalSection->OwningThread =
NtCurrentTeb()->Cid.UniqueThread;
+ CriticalSection->RecursionCount = 1;
+ return TRUE;
+
+ } else if (CriticalSection->OwningThread ==
NtCurrentTeb()->Cid.UniqueThread) {
+
+ /* It's already ours */
+ InterlockedIncrement(&CriticalSection->LockCount);
+ CriticalSection->RecursionCount++;
+ return TRUE;
+ }
+
+ /* It's not ours */
+ return FALSE;
}
-
-/**********************************************************************
*
- * RtlpUnWaitCriticalSection (NTDLL.@)
+/*++
+ * RtlpWaitForCriticalSection
*
- * Notifies other threads waiting on the busy critical section that it
has
- * become free.
- *
- * PARAMS
- * crit [I/O] Critical section
+ * Slow path of RtlEnterCriticalSection. Waits on an Event Object.
*
- * RETURNS
- * Success: STATUS_SUCCESS.
- * Failure: Any error returned by NtReleaseSemaphore()
+ * Params:
+ * CriticalSection - Critical section to acquire.
*
- * NOTES
- * Use RtlLeaveCriticalSection() instead of this function as it is
often much
- * faster.
+ * Returns:
+ * STATUS_SUCCESS, or raises an exception if a deadlock is
occuring.
*
- * SEE
- * RtlInitializeCriticalSection(),
RtlInitializeCriticalSectionAndSpinCount(),
- * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
- * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
- */
-NTSTATUS STDCALL RtlpUnWaitCriticalSection( PCRITICAL_SECTION crit )
+ * Remarks:
+ * None
+ *
+ *--*/
+NTSTATUS
+STDCALL
+RtlpWaitForCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
{
- HANDLE sem = get_semaphore( crit );
- NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
- if (!NT_SUCCESS(res)) RtlRaiseStatus( res );
- return res;
+ NTSTATUS Status;
+ EXCEPTION_RECORD ExceptionRecord;
+ BOOLEAN LastChance = FALSE;
+ LARGE_INTEGER Timeout;
+
+ Timeout = RtlConvertLongToLargeInteger(150000);
+ /* ^^ HACK HACK HACK. Good way:
+ Timeout = &NtCurrentPeb()->CriticalSectionTimeout */
+
+ /* Do we have an Event yet? */
+ if (!CriticalSection->LockSemaphore) {
+ RtlpCreateCriticalSectionSem(CriticalSection);
+ }
+
+ /* Increase the Debug Entry count */
+ CriticalSection->DebugInfo->EntryCount++;
+
+ for (;;) {
+
+ /* Increase the number of times we've had contention */
+ CriticalSection->DebugInfo->ContentionCount++;
+
+ /* Wait on the Event */
+ Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
+ FALSE,
+ &Timeout);
+
+ /* We have Timed out */
+ if (Status == STATUS_TIMEOUT) {
+
+ /* Is this the 2nd time we've timed out? */
+ if (LastChance) {
+
+ /* Yes it is, we are raising an exception */
+ ExceptionRecord.ExceptionCode =
STATUS_POSSIBLE_DEADLOCK;
+ ExceptionRecord.ExceptionFlags = 0;
+ ExceptionRecord.ExceptionRecord = NULL;
+ ExceptionRecord.ExceptionAddress = RtlRaiseException;
+ ExceptionRecord.NumberParameters = 1;
+ ExceptionRecord.ExceptionInformation[0] =
(ULONG_PTR)CriticalSection;
+ RtlRaiseException(&ExceptionRecord);
+
+ }
+
+ /* One more try */
+ LastChance = TRUE;
+
+ } else {
+
+ /* If we are here, everything went fine */
+ return STATUS_SUCCESS;
+ }
+ }
}
-
-/**********************************************************************
*
- * RtlEnterCriticalSection (NTDLL.@)
+/*++
+ * RtlpUnWaitCriticalSection
*
- * Enters a critical section, waiting for it to become available if
necessary.
+ * Slow path of RtlLeaveCriticalSection. Fires an Event Object.
*
- * PARAMS
- * crit [I/O] Critical section to enter
+ * Params:
+ * CriticalSection - Critical section to release.
*
- * RETURNS
- * STATUS_SUCCESS. The critical section is held by the caller.
- *
- * SEE
- * RtlInitializeCriticalSection(),
RtlInitializeCriticalSectionAndSpinCount(),
- * RtlDeleteCriticalSection(), RtlSetCriticalSectionSpinCount(),
- * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
- */
-NTSTATUS STDCALL RtlEnterCriticalSection( PCRITICAL_SECTION crit )
+ * Returns:
+ * None. Raises an exception if the system call failed.
+ *
+ * Remarks:
+ * None
+ *
+ *--*/
+VOID
+STDCALL
+RtlpUnWaitCriticalSection(
+ PRTL_CRITICAL_SECTION CriticalSection)
+
{
- if (crit->SpinCount)
- {
- ULONG count;
-
- if (RtlTryEnterCriticalSection( crit )) return STATUS_SUCCESS;
- for (count = crit->SpinCount; count > 0; count--)
- {
- 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();
- }
- }
-
- if (InterlockedIncrement( &crit->LockCount ))
- {
- if (crit->OwningThread == (HANDLE)RtlGetCurrentThreadId())
[truncated at 1000 lines; 302 more skipped]