mirror of
https://github.com/reactos/reactos.git
synced 2024-08-16 00:19:32 +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);
|
RtlResetRtlTranslations (&NlsTable);
|
||||||
|
|
||||||
NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
|
NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
|
||||||
|
|
||||||
|
/* Initialize Critical Section Data */
|
||||||
|
RtlpInitDeferedCriticalSection();
|
||||||
|
|
||||||
|
|
||||||
/* Get number of processors */
|
/* Get number of processors */
|
||||||
Status = ZwQuerySystemInformation(SystemBasicInformation,
|
Status = ZwQuerySystemInformation(SystemBasicInformation,
|
||||||
|
@ -304,10 +307,7 @@ __true_LdrInitializeThunk (ULONG Unknown1,
|
||||||
DPRINT1("Failed to create process heap\n");
|
DPRINT1("Failed to create process heap\n");
|
||||||
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize Critical Section Data */
|
|
||||||
RtlpInitDeferedCriticalSection();
|
|
||||||
|
|
||||||
/* initalize peb lock support */
|
/* initalize peb lock support */
|
||||||
RtlInitializeCriticalSection (&PebLock);
|
RtlInitializeCriticalSection (&PebLock);
|
||||||
Peb->FastPebLock = &PebLock;
|
Peb->FastPebLock = &PebLock;
|
||||||
|
|
|
@ -21,11 +21,13 @@
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
#define MAX_STATIC_CS_DEBUG_OBJECTS 64
|
||||||
|
|
||||||
static RTL_CRITICAL_SECTION RtlCriticalSectionLock;
|
static RTL_CRITICAL_SECTION RtlCriticalSectionLock;
|
||||||
static LIST_ENTRY RtlCriticalSectionList;
|
static LIST_ENTRY RtlCriticalSectionList;
|
||||||
static BOOLEAN RtlpCritSectInitialized = FALSE;
|
static BOOLEAN RtlpCritSectInitialized = FALSE;
|
||||||
//static RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[64];
|
static RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS];
|
||||||
//static PRTL_CRITICAL_SECTION_DEBUG RtlpDebugInfoFreeList;
|
static BOOLEAN RtlpDebugInfoFreeList[MAX_STATIC_CS_DEBUG_OBJECTS];
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
* RtlDeleteCriticalSection
|
* RtlDeleteCriticalSection
|
||||||
|
@ -50,26 +52,26 @@ RtlDeleteCriticalSection(
|
||||||
{
|
{
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
DPRINT("Deleting Critical Section: %x\n", CriticalSection);
|
||||||
/* Close the Event Object Handle if it exists */
|
/* Close the Event Object Handle if it exists */
|
||||||
if (CriticalSection->LockSemaphore) {
|
if (CriticalSection->LockSemaphore) {
|
||||||
|
|
||||||
|
/* In case NtClose fails, return the status */
|
||||||
Status = NtClose(CriticalSection->LockSemaphore);
|
Status = NtClose(CriticalSection->LockSemaphore);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Protect List */
|
/* Protect List */
|
||||||
RtlEnterCriticalSection(&RtlCriticalSectionLock);
|
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 */
|
/* Unprotect */
|
||||||
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||||
|
|
||||||
|
/* Free it */
|
||||||
|
RtlpFreeDebugInfo(CriticalSection->DebugInfo);
|
||||||
|
|
||||||
/* Wipe it out */
|
/* Wipe it out */
|
||||||
RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
|
RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
|
||||||
|
@ -148,7 +150,6 @@ RtlEnterCriticalSection(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We don't own it, so we must wait for it */
|
/* We don't own it, so we must wait for it */
|
||||||
DPRINT ("Waiting\n");
|
|
||||||
RtlpWaitForCriticalSection(CriticalSection);
|
RtlpWaitForCriticalSection(CriticalSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +209,6 @@ RtlInitializeCriticalSectionAndSpinCount (
|
||||||
DWORD SpinCount)
|
DWORD SpinCount)
|
||||||
{
|
{
|
||||||
PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
|
PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
|
||||||
PVOID Heap;
|
|
||||||
|
|
||||||
/* First things first, set up the Object */
|
/* First things first, set up the Object */
|
||||||
DPRINT("Initializing Critical Section: %x\n", CriticalSection);
|
DPRINT("Initializing Critical Section: %x\n", CriticalSection);
|
||||||
|
@ -217,56 +217,56 @@ RtlInitializeCriticalSectionAndSpinCount (
|
||||||
CriticalSection->OwningThread = 0;
|
CriticalSection->OwningThread = 0;
|
||||||
CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 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
|
* Add it to the List of Critical Sections owned by the process.
|
||||||
* Think of a better way to allocate it, because the Heap Manager won't
|
* If we've initialized the Lock, then use it. If not, then probably
|
||||||
* have any debug data since the Heap isn't initalized!
|
* this is the lock initialization itself, so insert it directly.
|
||||||
*/
|
*/
|
||||||
if ((Heap = RtlGetProcessHeap())) {
|
if ((CriticalSection != &RtlCriticalSectionLock) && (RtlpCritSectInitialized)) {
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
} else {
|
DPRINT("Securely Inserting into ProcessLocks: %x, %x, %x\n",
|
||||||
|
&CritcalSectionDebugData->ProcessLocksList,
|
||||||
DPRINT("Inserting into ProcessLocks: %x, %x\n",
|
CriticalSection,
|
||||||
&CritcalSectionDebugData->ProcessLocksList,
|
&RtlCriticalSectionList);
|
||||||
CriticalSection);
|
|
||||||
|
|
||||||
/* Add it directly */
|
|
||||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Protect List */
|
||||||
|
RtlEnterCriticalSection(&RtlCriticalSectionLock);
|
||||||
|
|
||||||
|
/* Add this one */
|
||||||
|
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||||
|
|
||||||
|
/* Unprotect */
|
||||||
|
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
DPRINT1("No Debug Data was allocated for: %x\n", CriticalSection);
|
DPRINT("Inserting into ProcessLocks: %x, %x, %x\n",
|
||||||
/* This shouldn't happen... */
|
&CritcalSectionDebugData->ProcessLocksList,
|
||||||
CritcalSectionDebugData = NULL;
|
CriticalSection,
|
||||||
|
&RtlCriticalSectionList);
|
||||||
|
|
||||||
|
/* Add it directly */
|
||||||
|
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
@ -397,16 +397,17 @@ RtlpWaitForCriticalSection(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Increase the Debug Entry count */
|
/* Increase the Debug Entry count */
|
||||||
DPRINT("Waiting on Critical Section: %x\n", CriticalSection);
|
DPRINT("Waiting on Critical Section Event: %x %x\n",
|
||||||
if (CriticalSection->DebugInfo) CriticalSection->DebugInfo->EntryCount++;
|
CriticalSection,
|
||||||
|
CriticalSection->LockSemaphore);
|
||||||
|
CriticalSection->DebugInfo->EntryCount++;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
/* Increase the number of times we've had contention */
|
/* Increase the number of times we've had contention */
|
||||||
if (CriticalSection->DebugInfo) CriticalSection->DebugInfo->ContentionCount++;
|
CriticalSection->DebugInfo->ContentionCount++;
|
||||||
|
|
||||||
/* Wait on the Event */
|
/* Wait on the Event */
|
||||||
DPRINT("Waiting on Event: %x\n", CriticalSection->LockSemaphore);
|
|
||||||
Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
|
Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
|
||||||
FALSE,
|
FALSE,
|
||||||
&Timeout);
|
&Timeout);
|
||||||
|
@ -470,13 +471,17 @@ RtlpUnWaitCriticalSection(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signal the Event */
|
/* Signal the Event */
|
||||||
DPRINT("Signaling CS Event\n");
|
DPRINT("Signaling Critical Section Event: %x, %x\n",
|
||||||
|
CriticalSection,
|
||||||
|
CriticalSection->LockSemaphore);
|
||||||
Status = NtSetEvent(CriticalSection->LockSemaphore, NULL);
|
Status = NtSetEvent(CriticalSection->LockSemaphore, NULL);
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status)) {
|
if (!NT_SUCCESS(Status)) {
|
||||||
|
|
||||||
/* We've failed */
|
/* We've failed */
|
||||||
DPRINT1("Signaling Failed\n");
|
DPRINT1("Signaling Failed for: %x, %x\n",
|
||||||
|
CriticalSection,
|
||||||
|
CriticalSection->LockSemaphore);
|
||||||
RtlRaiseStatus(Status);
|
RtlRaiseStatus(Status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,7 +513,6 @@ RtlpCreateCriticalSectionSem(
|
||||||
/* Chevk if we have an event */
|
/* Chevk if we have an event */
|
||||||
if (!hEvent) {
|
if (!hEvent) {
|
||||||
|
|
||||||
DPRINT("Creating Event\n");
|
|
||||||
/* No, so create it */
|
/* No, so create it */
|
||||||
if (!NT_SUCCESS(Status = NtCreateEvent(&hNewEvent,
|
if (!NT_SUCCESS(Status = NtCreateEvent(&hNewEvent,
|
||||||
EVENT_ALL_ACCESS,
|
EVENT_ALL_ACCESS,
|
||||||
|
@ -522,23 +526,16 @@ RtlpCreateCriticalSectionSem(
|
||||||
RtlRaiseStatus(Status);
|
RtlRaiseStatus(Status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
DPRINT("Created Event: %x \n", hNewEvent);
|
||||||
|
|
||||||
if (!(hEvent = InterlockedCompareExchangePointer((PVOID*)&CriticalSection->LockSemaphore,
|
if ((hEvent = InterlockedCompareExchangePointer((PVOID*)&CriticalSection->LockSemaphore,
|
||||||
(PVOID)hNewEvent,
|
(PVOID)hNewEvent,
|
||||||
0))) {
|
0))) {
|
||||||
|
|
||||||
/* We created a new event succesffuly */
|
|
||||||
hEvent = hNewEvent;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* Some just created an event */
|
/* Some just created an event */
|
||||||
DPRINT("Closing already created event!\n");
|
DPRINT("Closing already created event: %x\n", hNewEvent);
|
||||||
NtClose(hNewEvent);
|
NtClose(hNewEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set either the new or the old */
|
|
||||||
CriticalSection->LockSemaphore = hEvent;
|
|
||||||
DPRINT("Event set!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -567,7 +564,7 @@ RtlpInitDeferedCriticalSection(
|
||||||
|
|
||||||
/* Initialize the Process Critical Section List */
|
/* Initialize the Process Critical Section List */
|
||||||
InitializeListHead(&RtlCriticalSectionList);
|
InitializeListHead(&RtlCriticalSectionList);
|
||||||
|
|
||||||
/* Initialize the CS Protecting the List */
|
/* Initialize the CS Protecting the List */
|
||||||
RtlInitializeCriticalSection(&RtlCriticalSectionLock);
|
RtlInitializeCriticalSection(&RtlCriticalSectionLock);
|
||||||
|
|
||||||
|
@ -575,4 +572,98 @@ RtlpInitDeferedCriticalSection(
|
||||||
RtlpCritSectInitialized = TRUE;
|
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 */
|
/* EOF */
|
||||||
|
|
|
@ -180,8 +180,6 @@ void FreeChangeNotifications(void)
|
||||||
DeleteNode( head );
|
DeleteNode( head );
|
||||||
|
|
||||||
LeaveCriticalSection(&SHELL32_ChangenotifyCS);
|
LeaveCriticalSection(&SHELL32_ChangenotifyCS);
|
||||||
|
|
||||||
DeleteCriticalSection(&SHELL32_ChangenotifyCS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
|
|
@ -292,7 +292,6 @@ void SIC_Destroy(void)
|
||||||
ShellBigIconList = 0;
|
ShellBigIconList = 0;
|
||||||
|
|
||||||
LeaveCriticalSection(&SHELL32_SicCS);
|
LeaveCriticalSection(&SHELL32_SicCS);
|
||||||
DeleteCriticalSection(&SHELL32_SicCS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
|
Loading…
Reference in a new issue