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.
Modified: trunk/reactos/lib/ntdll/ldr/startup.c
Modified: trunk/reactos/lib/ntdll/rtl/critical.c
Modified: trunk/reactos/lib/shell32/changenotify.c
Modified: trunk/reactos/lib/shell32/iconcache.c

Modified: trunk/reactos/lib/ntdll/ldr/startup.c
--- trunk/reactos/lib/ntdll/ldr/startup.c	2005-01-05 00:08:45 UTC (rev 12809)
+++ trunk/reactos/lib/ntdll/ldr/startup.c	2005-01-05 01:09:30 UTC (rev 12810)
@@ -278,8 +278,11 @@
        RtlResetRtlTranslations (&NlsTable);
 
        NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
-      
 
+       /* Initialize Critical Section Data */
+       RtlpInitDeferedCriticalSection();
+             
+
        /* Get number of processors */
        Status = ZwQuerySystemInformation(SystemBasicInformation,
 	                                 &SystemInformation,
@@ -304,10 +307,7 @@
            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;

Modified: trunk/reactos/lib/ntdll/rtl/critical.c
--- trunk/reactos/lib/ntdll/rtl/critical.c	2005-01-05 00:08:45 UTC (rev 12809)
+++ trunk/reactos/lib/ntdll/rtl/critical.c	2005-01-05 01:09:30 UTC (rev 12810)
@@ -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 @@
 {
     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);      
         
-        /* Remove it from the list */
-        RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList);
-        
-        /* Free it */
-        RtlFreeHeap(RtlGetProcessHeap(), 0, CriticalSection->DebugInfo);
-    }
-    
     /* Unprotect */
     RtlLeaveCriticalSection(&RtlCriticalSectionLock);
+        
+    /* Free it */
+    RtlpFreeDebugInfo(CriticalSection->DebugInfo);
     
     /* Wipe it out */
     RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
@@ -148,7 +150,6 @@
         }
         
         /* We don't own it, so we must wait for it */
-        DPRINT ("Waiting\n");
         RtlpWaitForCriticalSection(CriticalSection);
     }
     
@@ -208,7 +209,6 @@
     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 @@
     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())) {
+    * 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, %x\n", 
+               &CritcalSectionDebugData->ProcessLocksList,
+               CriticalSection,
+               &RtlCriticalSectionList);
+        
+        /* Protect List */
+        RtlEnterCriticalSection(&RtlCriticalSectionLock);
 
-        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 this one */
+        InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
 
-        /* 
-         * 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);
+        /* Unprotect */
+        RtlLeaveCriticalSection(&RtlCriticalSectionLock);
+    
+    } else {
 
-            /* Add this one */
-            InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
-
-            /* Unprotect */
-            RtlLeaveCriticalSection(&RtlCriticalSectionLock);
+        DPRINT("Inserting into ProcessLocks: %x, %x, %x\n", 
+               &CritcalSectionDebugData->ProcessLocksList,
+               CriticalSection,
+               &RtlCriticalSectionList);
         
-        } else {
-
-            DPRINT("Inserting into ProcessLocks: %x, %x\n", 
-                   &CritcalSectionDebugData->ProcessLocksList,
-                   CriticalSection);
-            
-            /* Add it directly */
-            InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
-        }
-        
-    } else {
-
-        DPRINT1("No Debug Data was allocated for: %x\n", CriticalSection);
-        /* This shouldn't happen... */
-        CritcalSectionDebugData = NULL;
+        /* Add it directly */
+        InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
     }
 
     return STATUS_SUCCESS;
@@ -397,16 +397,17 @@
     }
     
     /* 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 @@
     }
     
     /* 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 @@
     /* 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 @@
                 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 @@
            
     /* Initialize the Process Critical Section List */
     InitializeListHead(&RtlCriticalSectionList);
-    
+       
     /* Initialize the CS Protecting the List */
     RtlInitializeCriticalSection(&RtlCriticalSectionLock);
     
@@ -575,4 +572,98 @@
     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 */

Modified: trunk/reactos/lib/shell32/changenotify.c
--- trunk/reactos/lib/shell32/changenotify.c	2005-01-05 00:08:45 UTC (rev 12809)
+++ trunk/reactos/lib/shell32/changenotify.c	2005-01-05 01:09:30 UTC (rev 12810)
@@ -180,8 +180,6 @@
         DeleteNode( head );
 
     LeaveCriticalSection(&SHELL32_ChangenotifyCS);
-
-    DeleteCriticalSection(&SHELL32_ChangenotifyCS);
 }
 
 /*************************************************************************

Modified: trunk/reactos/lib/shell32/iconcache.c
--- trunk/reactos/lib/shell32/iconcache.c	2005-01-05 00:08:45 UTC (rev 12809)
+++ trunk/reactos/lib/shell32/iconcache.c	2005-01-05 01:09:30 UTC (rev 12810)
@@ -292,7 +292,6 @@
 	ShellBigIconList = 0;
 
 	LeaveCriticalSection(&SHELL32_SicCS);
-	DeleteCriticalSection(&SHELL32_SicCS);
 }
 
 /*************************************************************************