[RTL/NTDLL]
[reactos.git] / reactos / lib / rtl / critical.c
index 8270b46..ab3590b 100644 (file)
@@ -21,6 +21,7 @@ static LIST_ENTRY RtlCriticalSectionList;
 static BOOLEAN RtlpCritSectInitialized = FALSE;
 static RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS];
 static BOOLEAN RtlpDebugInfoFreeList[MAX_STATIC_CS_DEBUG_OBJECTS];
+LARGE_INTEGER RtlpTimeout;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -39,6 +40,7 @@ static BOOLEAN RtlpDebugInfoFreeList[MAX_STATIC_CS_DEBUG_OBJECTS];
  *     None
  *
  *--*/
+_At_(CriticalSection->LockSemaphore, _Post_notnull_)
 VOID
 NTAPI
 RtlpCreateCriticalSectionSem(PRTL_CRITICAL_SECTION CriticalSection)
@@ -47,31 +49,38 @@ RtlpCreateCriticalSectionSem(PRTL_CRITICAL_SECTION CriticalSection)
     HANDLE hNewEvent;
     NTSTATUS Status;
 
-    /* Chevk if we have an event */
-    if (!hEvent) {
+    /* Check if we have an event */
+    if (!hEvent)
+    {
 
         /* No, so create it */
-        if (!NT_SUCCESS(Status = NtCreateEvent(&hNewEvent,
-                                               EVENT_ALL_ACCESS,
-                                               NULL,
-                                               SynchronizationEvent,
-                                               FALSE))) {
-
-                /* We failed, this is bad... */
+        Status = NtCreateEvent(&hNewEvent,
+                               EVENT_ALL_ACCESS,
+                               NULL,
+                               SynchronizationEvent,
+                               FALSE);
+        if (!NT_SUCCESS(Status))
+        {
                 DPRINT1("Failed to Create Event!\n");
-                InterlockedDecrement(&CriticalSection->LockCount);
-                RtlRaiseStatus(Status);
-                return;
+
+                /* Use INVALID_HANDLE_VALUE (-1) to signal that the global
+                   keyed event must be used */
+                hNewEvent = INVALID_HANDLE_VALUE;
         }
+
         DPRINT("Created Event: %p \n", hNewEvent);
 
+        /* Exchange the LockSemaphore field with the new handle, if it is still 0 */
         if (InterlockedCompareExchangePointer((PVOID*)&CriticalSection->LockSemaphore,
                                               (PVOID)hNewEvent,
-                                               0)) {
-
-            /* Some just created an event */
-            DPRINT("Closing already created event: %p\n", hNewEvent);
-            NtClose(hNewEvent);
+                                               NULL) != NULL)
+        {
+            /* Someone else just created an event */
+            if (hEvent != INVALID_HANDLE_VALUE)
+            {
+                DPRINT("Closing already created event: %p\n", hNewEvent);
+                NtClose(hNewEvent);
+            }
         }
     }
 
@@ -100,13 +109,6 @@ RtlpWaitForCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
     NTSTATUS Status;
     EXCEPTION_RECORD ExceptionRecord;
     BOOLEAN LastChance = FALSE;
-    LARGE_INTEGER Timeout;
-
-    /* Wait 2.5 minutes */
-    Timeout.QuadPart = 150000L * (ULONGLONG)10000;
-    Timeout.QuadPart = -Timeout.QuadPart;
-    /* ^^ HACK HACK HACK. Good way:
-    Timeout = &NtCurrentPeb()->CriticalSectionTimeout   */
 
     /* Do we have an Event yet? */
     if (!CriticalSection->LockSemaphore) {
@@ -127,10 +129,22 @@ RtlpWaitForCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
         if (CriticalSection->DebugInfo)
             CriticalSection->DebugInfo->ContentionCount++;
 
-        /* Wait on the Event */
-        Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
-                                       FALSE,
-                                       &Timeout);
+        /* Check if allocating the event failed */
+        if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE)
+        {
+            /* Use the global keyed event (NULL as keyed event handle) */
+            Status = NtWaitForKeyedEvent(NULL,
+                                         CriticalSection,
+                                         FALSE,
+                                         &RtlpTimeout);
+        }
+        else
+        {
+            /* Wait on the Event */
+            Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
+                                           FALSE,
+                                           &RtlpTimeout);
+        }
 
         /* We have Timed out */
         if (Status == STATUS_TIMEOUT) {
@@ -192,7 +206,18 @@ RtlpUnWaitCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
     DPRINT("Signaling Critical Section Event: %p, %p\n",
             CriticalSection,
             CriticalSection->LockSemaphore);
-    Status = NtSetEvent(CriticalSection->LockSemaphore, NULL);
+
+    /* Check if this critical section needs to use the keyed event */
+    if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE)
+    {
+        /* Release keyed event */
+        Status = NtReleaseKeyedEvent(NULL, CriticalSection, FALSE, &RtlpTimeout);
+    }
+    else
+    {
+        /* Set the event */
+        Status = NtSetEvent(CriticalSection->LockSemaphore, NULL);
+    }
 
     if (!NT_SUCCESS(Status)) {
 
@@ -200,7 +225,7 @@ RtlpUnWaitCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
         DPRINT1("Signaling Failed for: %p, %p, 0x%08lx\n",
                 CriticalSection,
                 CriticalSection->LockSemaphore,
-               Status);
+                Status);
         RtlRaiseStatus(Status);
     }
 }
@@ -274,7 +299,7 @@ RtlpAllocateDebugInfo(VOID)
     }
 
     /* We are out of static buffer, allocate dynamic */
-    return RtlAllocateHeap(NtCurrentPeb()->ProcessHeap,
+    return RtlAllocateHeap(RtlGetProcessHeap(),
                            0,
                            sizeof(RTL_CRITICAL_SECTION_DEBUG));
 }
@@ -299,7 +324,7 @@ VOID
 NTAPI
 RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo)
 {
-    ULONG EntryId;
+    SIZE_T EntryId;
 
     /* Is it part of our cached entries? */
     if ((DebugInfo >= RtlpStaticDebugInfo) &&
@@ -310,13 +335,13 @@ RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo)
 
         /* Mark as free */
         EntryId = (DebugInfo - RtlpStaticDebugInfo);
-        DPRINT("Freeing from Buffer: %p. Entry: %lu inside Process: %p\n",
+        DPRINT("Freeing from Buffer: %p. Entry: %Iu inside Process: %p\n",
                DebugInfo,
                EntryId,
                NtCurrentTeb()->ClientId.UniqueProcess);
         RtlpDebugInfoFreeList[EntryId] = FALSE;
 
-    } else {
+    } else if (!DebugInfo->Flags) {
 
         /* It's a dynamic one, so free from the heap */
         DPRINT("Freeing from Heap: %p inside Process: %p\n",
@@ -324,6 +349,13 @@ RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo)
                NtCurrentTeb()->ClientId.UniqueProcess);
         RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, DebugInfo);
 
+    } else {
+
+        /* Wine stores a section name pointer in the Flags member */
+        DPRINT("Assuming static: %p inside Process: %p\n",
+               DebugInfo,
+               NtCurrentTeb()->ClientId.UniqueProcess);
+
     }
 }
 
@@ -365,7 +397,9 @@ RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
     {
         /* Remove it from the list */
         RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList);
+#if 0 /* We need to preserve Flags for RtlpFreeDebugInfo */
         RtlZeroMemory(CriticalSection->DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG));
+#endif
     }
 
     /* Unprotect */
@@ -402,12 +436,12 @@ RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
  *     SpinCount is ignored on single-processor systems.
  *
  *--*/
-DWORD
+ULONG
 NTAPI
 RtlSetCriticalSectionSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
                                ULONG SpinCount)
 {
-    ULONG OldCount = CriticalSection->SpinCount;
+    ULONG OldCount = (ULONG)CriticalSection->SpinCount;
 
     /* Set to parameter if MP, or to 0 if this is Uniprocessor */
     CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0;
@@ -546,6 +580,7 @@ RtlInitializeCriticalSectionAndSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
     CritcalSectionDebugData->ContentionCount = 0;
     CritcalSectionDebugData->EntryCount = 0;
     CritcalSectionDebugData->CriticalSection = CriticalSection;
+    CritcalSectionDebugData->Flags = 0;
     CriticalSection->DebugInfo = CritcalSectionDebugData;
 
     /*
@@ -583,6 +618,45 @@ RtlInitializeCriticalSectionAndSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
     return STATUS_SUCCESS;
 }
 
+/*++
+ * RtlGetCriticalSectionRecursionCount
+ * @implemented NT5.2 SP1
+ *
+ *     Retrieves the recursion count of a given critical section.
+ *
+ * Params:
+ *     CriticalSection - Critical section to retrieve its recursion count.
+ *
+ * Returns:
+ *     The recursion count.
+ *
+ * Remarks:
+ *     We return the recursion count of the critical section if it is owned
+ *     by the current thread, and otherwise we return zero.
+ *
+ *--*/
+LONG
+NTAPI
+RtlGetCriticalSectionRecursionCount(PRTL_CRITICAL_SECTION CriticalSection)
+{
+    if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread)
+    {
+        /*
+         * The critical section is owned by the current thread,
+         * therefore retrieve its actual recursion count.
+         */
+        return CriticalSection->RecursionCount;
+    }
+    else
+    {
+        /*
+         * It is not owned by the current thread, so
+         * for this thread there is no recursion.
+         */
+        return 0;
+    }
+}
+
 /*++
  * RtlLeaveCriticalSection
  * @implemented NT4
@@ -603,7 +677,7 @@ NTSTATUS
 NTAPI
 RtlLeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
 {
-#ifndef NDEBUG
+#if DBG
     HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread;
 
     /* In win this case isn't checked. However it's a valid check so it should only
@@ -683,4 +757,12 @@ RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
     return FALSE;
 }
 
+VOID
+NTAPI
+RtlCheckForOrphanedCriticalSections(
+    HANDLE ThreadHandle)
+{
+    UNIMPLEMENTED;
+}
+
 /* EOF */