mirror of
https://github.com/reactos/reactos.git
synced 2024-07-14 08:26:08 +00:00
Significantly improved performance of Critical Section code by using a static buffer. Increased debug info dramatically and, if enabled, leaks can be found with ease. Future revision will include Spincount support.
svn path=/trunk/; revision=12810
This commit is contained in:
parent
ff4ae27d2f
commit
2b9f762918
|
@ -278,7 +278,10 @@ __true_LdrInitializeThunk (ULONG Unknown1,
|
|||
RtlResetRtlTranslations (&NlsTable);
|
||||
|
||||
NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
|
||||
|
||||
|
||||
/* Initialize Critical Section Data */
|
||||
RtlpInitDeferedCriticalSection();
|
||||
|
||||
|
||||
/* Get number of processors */
|
||||
Status = ZwQuerySystemInformation(SystemBasicInformation,
|
||||
|
@ -304,10 +307,7 @@ __true_LdrInitializeThunk (ULONG Unknown1,
|
|||
DPRINT1("Failed to create process heap\n");
|
||||
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
/* Initialize Critical Section Data */
|
||||
RtlpInitDeferedCriticalSection();
|
||||
|
||||
|
||||
/* initalize peb lock support */
|
||||
RtlInitializeCriticalSection (&PebLock);
|
||||
Peb->FastPebLock = &PebLock;
|
||||
|
|
|
@ -21,11 +21,13 @@
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
#define MAX_STATIC_CS_DEBUG_OBJECTS 64
|
||||
|
||||
static RTL_CRITICAL_SECTION RtlCriticalSectionLock;
|
||||
static LIST_ENTRY RtlCriticalSectionList;
|
||||
static BOOLEAN RtlpCritSectInitialized = FALSE;
|
||||
//static RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[64];
|
||||
//static PRTL_CRITICAL_SECTION_DEBUG RtlpDebugInfoFreeList;
|
||||
static RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS];
|
||||
static BOOLEAN RtlpDebugInfoFreeList[MAX_STATIC_CS_DEBUG_OBJECTS];
|
||||
|
||||
/*++
|
||||
* RtlDeleteCriticalSection
|
||||
|
@ -50,26 +52,26 @@ RtlDeleteCriticalSection(
|
|||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
DPRINT("Deleting Critical Section: %x\n", CriticalSection);
|
||||
/* Close the Event Object Handle if it exists */
|
||||
if (CriticalSection->LockSemaphore) {
|
||||
|
||||
/* In case NtClose fails, return the status */
|
||||
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);
|
||||
}
|
||||
|
||||
/* Remove it from the list */
|
||||
RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList);
|
||||
|
||||
/* Unprotect */
|
||||
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
/* Free it */
|
||||
RtlpFreeDebugInfo(CriticalSection->DebugInfo);
|
||||
|
||||
/* Wipe it out */
|
||||
RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
|
||||
|
@ -148,7 +150,6 @@ RtlEnterCriticalSection(
|
|||
}
|
||||
|
||||
/* We don't own it, so we must wait for it */
|
||||
DPRINT ("Waiting\n");
|
||||
RtlpWaitForCriticalSection(CriticalSection);
|
||||
}
|
||||
|
||||
|
@ -208,7 +209,6 @@ RtlInitializeCriticalSectionAndSpinCount (
|
|||
DWORD SpinCount)
|
||||
{
|
||||
PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
|
||||
PVOID Heap;
|
||||
|
||||
/* First things first, set up the Object */
|
||||
DPRINT("Initializing Critical Section: %x\n", CriticalSection);
|
||||
|
@ -217,56 +217,56 @@ RtlInitializeCriticalSectionAndSpinCount (
|
|||
CriticalSection->OwningThread = 0;
|
||||
CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0;
|
||||
|
||||
/* Allocate the Debug Data */
|
||||
CritcalSectionDebugData = RtlpAllocateDebugInfo();
|
||||
DPRINT("Allocated Debug Data: %x inside Process: %x\n",
|
||||
CritcalSectionDebugData,
|
||||
NtCurrentTeb()->Cid.UniqueProcess);
|
||||
|
||||
if (!CritcalSectionDebugData) {
|
||||
|
||||
/* This is bad! */
|
||||
DPRINT1("Couldn't allocate Debug Data for: %x\n", CriticalSection);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Set it up */
|
||||
CritcalSectionDebugData->Type = RTL_CRITSECT_TYPE;
|
||||
CritcalSectionDebugData->ContentionCount = 0;
|
||||
CritcalSectionDebugData->EntryCount = 0;
|
||||
CritcalSectionDebugData->CriticalSection = CriticalSection;
|
||||
CriticalSection->DebugInfo = CritcalSectionDebugData;
|
||||
|
||||
/*
|
||||
* 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));
|
||||
DPRINT("Allocated Critical Section Debug Data: %x\n", CritcalSectionDebugData);
|
||||
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)) {
|
||||
|
||||
DPRINT("Securely Inserting into ProcessLocks: %x, %x\n",
|
||||
&CritcalSectionDebugData->ProcessLocksList,
|
||||
CriticalSection);
|
||||
|
||||
/* Protect List */
|
||||
RtlEnterCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
/* Add this one */
|
||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||
|
||||
/* Unprotect */
|
||||
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||
* 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)) {
|
||||
|
||||
} else {
|
||||
|
||||
DPRINT("Inserting into ProcessLocks: %x, %x\n",
|
||||
&CritcalSectionDebugData->ProcessLocksList,
|
||||
CriticalSection);
|
||||
|
||||
/* Add it directly */
|
||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||
}
|
||||
DPRINT("Securely Inserting into ProcessLocks: %x, %x, %x\n",
|
||||
&CritcalSectionDebugData->ProcessLocksList,
|
||||
CriticalSection,
|
||||
&RtlCriticalSectionList);
|
||||
|
||||
/* Protect List */
|
||||
RtlEnterCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
/* Add this one */
|
||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||
|
||||
/* Unprotect */
|
||||
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
} else {
|
||||
|
||||
DPRINT1("No Debug Data was allocated for: %x\n", CriticalSection);
|
||||
/* This shouldn't happen... */
|
||||
CritcalSectionDebugData = NULL;
|
||||
DPRINT("Inserting into ProcessLocks: %x, %x, %x\n",
|
||||
&CritcalSectionDebugData->ProcessLocksList,
|
||||
CriticalSection,
|
||||
&RtlCriticalSectionList);
|
||||
|
||||
/* Add it directly */
|
||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -397,16 +397,17 @@ RtlpWaitForCriticalSection(
|
|||
}
|
||||
|
||||
/* Increase the Debug Entry count */
|
||||
DPRINT("Waiting on Critical Section: %x\n", CriticalSection);
|
||||
if (CriticalSection->DebugInfo) CriticalSection->DebugInfo->EntryCount++;
|
||||
DPRINT("Waiting on Critical Section Event: %x %x\n",
|
||||
CriticalSection,
|
||||
CriticalSection->LockSemaphore);
|
||||
CriticalSection->DebugInfo->EntryCount++;
|
||||
|
||||
for (;;) {
|
||||
|
||||
/* Increase the number of times we've had contention */
|
||||
if (CriticalSection->DebugInfo) CriticalSection->DebugInfo->ContentionCount++;
|
||||
CriticalSection->DebugInfo->ContentionCount++;
|
||||
|
||||
/* Wait on the Event */
|
||||
DPRINT("Waiting on Event: %x\n", CriticalSection->LockSemaphore);
|
||||
Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
|
||||
FALSE,
|
||||
&Timeout);
|
||||
|
@ -470,13 +471,17 @@ RtlpUnWaitCriticalSection(
|
|||
}
|
||||
|
||||
/* Signal the Event */
|
||||
DPRINT("Signaling CS Event\n");
|
||||
DPRINT("Signaling Critical Section Event: %x, %x\n",
|
||||
CriticalSection,
|
||||
CriticalSection->LockSemaphore);
|
||||
Status = NtSetEvent(CriticalSection->LockSemaphore, NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
|
||||
/* We've failed */
|
||||
DPRINT1("Signaling Failed\n");
|
||||
DPRINT1("Signaling Failed for: %x, %x\n",
|
||||
CriticalSection,
|
||||
CriticalSection->LockSemaphore);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
}
|
||||
|
@ -508,7 +513,6 @@ RtlpCreateCriticalSectionSem(
|
|||
/* Chevk if we have an event */
|
||||
if (!hEvent) {
|
||||
|
||||
DPRINT("Creating Event\n");
|
||||
/* No, so create it */
|
||||
if (!NT_SUCCESS(Status = NtCreateEvent(&hNewEvent,
|
||||
EVENT_ALL_ACCESS,
|
||||
|
@ -522,23 +526,16 @@ RtlpCreateCriticalSectionSem(
|
|||
RtlRaiseStatus(Status);
|
||||
return;
|
||||
}
|
||||
DPRINT("Created Event: %x \n", hNewEvent);
|
||||
|
||||
if (!(hEvent = InterlockedCompareExchangePointer((PVOID*)&CriticalSection->LockSemaphore,
|
||||
if ((hEvent = InterlockedCompareExchangePointer((PVOID*)&CriticalSection->LockSemaphore,
|
||||
(PVOID)hNewEvent,
|
||||
0))) {
|
||||
|
||||
/* We created a new event succesffuly */
|
||||
hEvent = hNewEvent;
|
||||
} else {
|
||||
|
||||
/* Some just created an event */
|
||||
DPRINT("Closing already created event!\n");
|
||||
DPRINT("Closing already created event: %x\n", hNewEvent);
|
||||
NtClose(hNewEvent);
|
||||
}
|
||||
|
||||
/* Set either the new or the old */
|
||||
CriticalSection->LockSemaphore = hEvent;
|
||||
DPRINT("Event set!\n");
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -567,7 +564,7 @@ RtlpInitDeferedCriticalSection(
|
|||
|
||||
/* Initialize the Process Critical Section List */
|
||||
InitializeListHead(&RtlCriticalSectionList);
|
||||
|
||||
|
||||
/* Initialize the CS Protecting the List */
|
||||
RtlInitializeCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
|
@ -575,4 +572,98 @@ RtlpInitDeferedCriticalSection(
|
|||
RtlpCritSectInitialized = TRUE;
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlpAllocateDebugInfo
|
||||
*
|
||||
* Finds or allocates memory for a Critical Section Debug Object
|
||||
*
|
||||
* Params:
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to an empty Critical Section Debug Object.
|
||||
*
|
||||
* Remarks:
|
||||
* For optimization purposes, the first 64 entries can be cached. From
|
||||
* then on, future Critical Sections will allocate memory from the heap.
|
||||
*
|
||||
*--*/
|
||||
PRTL_CRITICAL_SECTION_DEBUG
|
||||
STDCALL
|
||||
RtlpAllocateDebugInfo(
|
||||
VOID)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
/* Try to allocate from our buffer first */
|
||||
for (i = 0; i < MAX_STATIC_CS_DEBUG_OBJECTS; i++) {
|
||||
|
||||
/* Check if Entry is free */
|
||||
if (!RtlpDebugInfoFreeList[i]) {
|
||||
|
||||
/* Mark entry in use */
|
||||
DPRINT("Using entry: %d. Buffer: %x\n", i, &RtlpStaticDebugInfo[i]);
|
||||
RtlpDebugInfoFreeList[i] = TRUE;
|
||||
|
||||
/* Use free entry found */
|
||||
return &RtlpStaticDebugInfo[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We are out of static buffer, allocate dynamic */
|
||||
return RtlAllocateHeap(NtCurrentPeb()->ProcessHeap,
|
||||
0,
|
||||
sizeof(RTL_CRITICAL_SECTION_DEBUG));
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlpFreeDebugInfo
|
||||
*
|
||||
* Frees the memory for a Critical Section Debug Object
|
||||
*
|
||||
* Params:
|
||||
* DebugInfo - Pointer to Critical Section Debug Object to free.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Remarks:
|
||||
* If the pointer is part of the static buffer, then the entry is made
|
||||
* free again. If not, the object is de-allocated from the heap.
|
||||
*
|
||||
*--*/
|
||||
VOID
|
||||
STDCALL
|
||||
RtlpFreeDebugInfo(
|
||||
PRTL_CRITICAL_SECTION_DEBUG DebugInfo)
|
||||
{
|
||||
ULONG EntryId;
|
||||
|
||||
/* Is it part of our cached entries? */
|
||||
if ((DebugInfo >= RtlpStaticDebugInfo) &&
|
||||
(DebugInfo <= &RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS-1])) {
|
||||
|
||||
/* Yes. zero it out */
|
||||
RtlZeroMemory(DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG));
|
||||
|
||||
/* Mark as free */
|
||||
EntryId = (DebugInfo - RtlpStaticDebugInfo);
|
||||
DPRINT("Freeing from Buffer: %x. Entry: %d inside Process: %x\n",
|
||||
DebugInfo,
|
||||
EntryId,
|
||||
NtCurrentTeb()->Cid.UniqueProcess);
|
||||
RtlpDebugInfoFreeList[EntryId] = FALSE;
|
||||
|
||||
} else {
|
||||
|
||||
/* It's a dynamic one, so free from the heap */
|
||||
DPRINT("Freeing from Heap: %x inside Process: %x\n",
|
||||
DebugInfo,
|
||||
NtCurrentTeb()->Cid.UniqueProcess);
|
||||
RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, DebugInfo);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -180,8 +180,6 @@ void FreeChangeNotifications(void)
|
|||
DeleteNode( head );
|
||||
|
||||
LeaveCriticalSection(&SHELL32_ChangenotifyCS);
|
||||
|
||||
DeleteCriticalSection(&SHELL32_ChangenotifyCS);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -292,7 +292,6 @@ void SIC_Destroy(void)
|
|||
ShellBigIconList = 0;
|
||||
|
||||
LeaveCriticalSection(&SHELL32_SicCS);
|
||||
DeleteCriticalSection(&SHELL32_SicCS);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
Loading…
Reference in a new issue