mirror of
https://github.com/reactos/reactos.git
synced 2025-07-31 21:11:54 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
804
sdk/lib/rtl/critical.c
Normal file
804
sdk/lib/rtl/critical.c
Normal file
|
@ -0,0 +1,804 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS system libraries
|
||||
* FILE: lib/rtl/critical.c
|
||||
* PURPOSE: Critical sections
|
||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||
* Gunnar Dalsnes
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <rtl.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#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[MAX_STATIC_CS_DEBUG_OBJECTS];
|
||||
static BOOLEAN RtlpDebugInfoFreeList[MAX_STATIC_CS_DEBUG_OBJECTS];
|
||||
LARGE_INTEGER RtlpTimeout;
|
||||
|
||||
extern BOOLEAN LdrpShutdownInProgress;
|
||||
extern HANDLE LdrpShutdownThreadId;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/*++
|
||||
* RtlpCreateCriticalSectionSem
|
||||
*
|
||||
* Checks if an Event has been created for the critical section.
|
||||
*
|
||||
* Params:
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
* None. Raises an exception if the system call failed.
|
||||
*
|
||||
* Remarks:
|
||||
* None
|
||||
*
|
||||
*--*/
|
||||
_At_(CriticalSection->LockSemaphore, _Post_notnull_)
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpCreateCriticalSectionSem(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
HANDLE hEvent = CriticalSection->LockSemaphore;
|
||||
HANDLE hNewEvent;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Check if we have an event */
|
||||
if (!hEvent)
|
||||
{
|
||||
/* No, so create it */
|
||||
Status = NtCreateEvent(&hNewEvent,
|
||||
EVENT_ALL_ACCESS,
|
||||
NULL,
|
||||
SynchronizationEvent,
|
||||
FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to Create Event!\n");
|
||||
|
||||
/*
|
||||
* 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,
|
||||
NULL) != NULL)
|
||||
{
|
||||
/* Someone else just created an event */
|
||||
if (hEvent != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DPRINT("Closing already created event: %p\n", hNewEvent);
|
||||
NtClose(hNewEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlpWaitForCriticalSection
|
||||
*
|
||||
* Slow path of RtlEnterCriticalSection. Waits on an Event Object.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to acquire.
|
||||
*
|
||||
* Returns:
|
||||
* STATUS_SUCCESS, or raises an exception if a deadlock is occuring.
|
||||
*
|
||||
* Remarks:
|
||||
* None
|
||||
*
|
||||
*--*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlpWaitForCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
EXCEPTION_RECORD ExceptionRecord;
|
||||
BOOLEAN LastChance = FALSE;
|
||||
|
||||
/* Do we have an Event yet? */
|
||||
if (!CriticalSection->LockSemaphore)
|
||||
{
|
||||
RtlpCreateCriticalSectionSem(CriticalSection);
|
||||
}
|
||||
|
||||
/* Increase the Debug Entry count */
|
||||
DPRINT("Waiting on Critical Section Event: %p %p\n",
|
||||
CriticalSection,
|
||||
CriticalSection->LockSemaphore);
|
||||
|
||||
if (CriticalSection->DebugInfo)
|
||||
CriticalSection->DebugInfo->EntryCount++;
|
||||
|
||||
/*
|
||||
* If we're shutting down the process, we're allowed to acquire any
|
||||
* critical sections by force (the loader lock in particular)
|
||||
*/
|
||||
if (LdrpShutdownInProgress &&
|
||||
LdrpShutdownThreadId == NtCurrentTeb()->RealClientId.UniqueThread)
|
||||
{
|
||||
DPRINT("Forcing ownership of critical section %p\n", CriticalSection);
|
||||
CriticalSection->LockCount = 0;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Increase the number of times we've had contention */
|
||||
if (CriticalSection->DebugInfo)
|
||||
CriticalSection->DebugInfo->ContentionCount++;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* Is this the 2nd time we've timed out? */
|
||||
if (LastChance)
|
||||
{
|
||||
ERROR_DBGBREAK("Deadlock: 0x%p\n", CriticalSection);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlpUnWaitCriticalSection
|
||||
*
|
||||
* Slow path of RtlLeaveCriticalSection. Fires an Event Object.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to release.
|
||||
*
|
||||
* Returns:
|
||||
* None. Raises an exception if the system call failed.
|
||||
*
|
||||
* Remarks:
|
||||
* None
|
||||
*
|
||||
*--*/
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpUnWaitCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Do we have an Event yet? */
|
||||
if (!CriticalSection->LockSemaphore)
|
||||
{
|
||||
RtlpCreateCriticalSectionSem(CriticalSection);
|
||||
}
|
||||
|
||||
/* Signal the Event */
|
||||
DPRINT("Signaling Critical Section Event: %p, %p\n",
|
||||
CriticalSection,
|
||||
CriticalSection->LockSemaphore);
|
||||
|
||||
/* 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))
|
||||
{
|
||||
/* We've failed */
|
||||
DPRINT1("Signaling Failed for: %p, %p, 0x%08lx\n",
|
||||
CriticalSection,
|
||||
CriticalSection->LockSemaphore,
|
||||
Status);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlpInitDeferedCriticalSection
|
||||
*
|
||||
* Initializes the Critical Section implementation.
|
||||
*
|
||||
* Params:
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Remarks:
|
||||
* After this call, the Process Critical Section list is protected.
|
||||
*
|
||||
*--*/
|
||||
VOID
|
||||
NTAPI
|
||||
RtlpInitDeferedCriticalSection(VOID)
|
||||
{
|
||||
/* Initialize the Process Critical Section List */
|
||||
InitializeListHead(&RtlCriticalSectionList);
|
||||
|
||||
/* Initialize the CS Protecting the List */
|
||||
RtlInitializeCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
/* It's now safe to enter it */
|
||||
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
|
||||
NTAPI
|
||||
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: %lu. Buffer: %p\n", i, &RtlpStaticDebugInfo[i]);
|
||||
RtlpDebugInfoFreeList[i] = TRUE;
|
||||
|
||||
/* Use free entry found */
|
||||
return &RtlpStaticDebugInfo[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* We are out of static buffer, allocate dynamic */
|
||||
return RtlAllocateHeap(RtlGetProcessHeap(),
|
||||
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
|
||||
NTAPI
|
||||
RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo)
|
||||
{
|
||||
SIZE_T 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: %p. Entry: %Iu inside Process: %p\n",
|
||||
DebugInfo,
|
||||
EntryId,
|
||||
NtCurrentTeb()->ClientId.UniqueProcess);
|
||||
RtlpDebugInfoFreeList[EntryId] = FALSE;
|
||||
|
||||
}
|
||||
else if (!DebugInfo->Flags)
|
||||
{
|
||||
/* It's a dynamic one, so free from the heap */
|
||||
DPRINT("Freeing from Heap: %p inside Process: %p\n",
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*++
|
||||
* 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
|
||||
NTAPI
|
||||
RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
DPRINT("Deleting Critical Section: %p\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);
|
||||
|
||||
if (CriticalSection->DebugInfo)
|
||||
{
|
||||
/* 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 */
|
||||
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
if (CriticalSection->DebugInfo)
|
||||
{
|
||||
/* Free it */
|
||||
RtlpFreeDebugInfo(CriticalSection->DebugInfo);
|
||||
}
|
||||
|
||||
/* Wipe it out */
|
||||
RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
|
||||
|
||||
/* Return */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*++
|
||||
* 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.
|
||||
*
|
||||
*--*/
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlSetCriticalSectionSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
|
||||
ULONG 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;
|
||||
return OldCount;
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlEnterCriticalSection
|
||||
* @implemented NT4
|
||||
*
|
||||
* Waits to gain ownership of the critical section.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to wait for.
|
||||
*
|
||||
* Returns:
|
||||
* STATUS_SUCCESS.
|
||||
*
|
||||
* Remarks:
|
||||
* Uses a fast-path unless contention happens.
|
||||
*
|
||||
*--*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread;
|
||||
|
||||
/* Try to lock it */
|
||||
if (InterlockedIncrement(&CriticalSection->LockCount) != 0)
|
||||
{
|
||||
/* 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! No need to
|
||||
* use the interlocked functions as only the thread who already owns
|
||||
* the lock can modify this data.
|
||||
*/
|
||||
CriticalSection->RecursionCount++;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* NOTE - CriticalSection->OwningThread can be NULL here because changing
|
||||
this information is not serialized. This happens when thread a
|
||||
acquires the lock (LockCount == 0) and thread b tries to
|
||||
acquire it as well (LockCount == 1) but thread a hasn't had a
|
||||
chance to set the OwningThread! So it's not an error when
|
||||
OwningThread is NULL here! */
|
||||
|
||||
/* We don't own it, so we must wait for it */
|
||||
RtlpWaitForCriticalSection(CriticalSection);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock successful. Changing this information has not to be serialized
|
||||
* because only one thread at a time can actually change it (the one who
|
||||
* acquired the lock)!
|
||||
*/
|
||||
CriticalSection->OwningThread = Thread;
|
||||
CriticalSection->RecursionCount = 1;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlInitializeCriticalSection
|
||||
* @implemented NT4
|
||||
*
|
||||
* Initialises a new critical section.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to initialise
|
||||
*
|
||||
* Returns:
|
||||
* STATUS_SUCCESS.
|
||||
*
|
||||
* Remarks:
|
||||
* Simply calls RtlInitializeCriticalSectionAndSpinCount
|
||||
*
|
||||
*--*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlInitializeCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
/* Call the Main Function */
|
||||
return RtlInitializeCriticalSectionAndSpinCount(CriticalSection, 0);
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlInitializeCriticalSectionAndSpinCount
|
||||
* @implemented NT4
|
||||
*
|
||||
* Initialises a new critical section.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to initialise
|
||||
*
|
||||
* SpinCount - Spin count for the critical section.
|
||||
*
|
||||
* Returns:
|
||||
* STATUS_SUCCESS.
|
||||
*
|
||||
* Remarks:
|
||||
* SpinCount is ignored on single-processor systems.
|
||||
*
|
||||
*--*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlInitializeCriticalSectionAndSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
|
||||
ULONG SpinCount)
|
||||
{
|
||||
PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
|
||||
|
||||
/* First things first, set up the Object */
|
||||
DPRINT("Initializing Critical Section: %p\n", CriticalSection);
|
||||
CriticalSection->LockCount = -1;
|
||||
CriticalSection->RecursionCount = 0;
|
||||
CriticalSection->OwningThread = 0;
|
||||
CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0;
|
||||
CriticalSection->LockSemaphore = 0;
|
||||
|
||||
/* Allocate the Debug Data */
|
||||
CritcalSectionDebugData = RtlpAllocateDebugInfo();
|
||||
DPRINT("Allocated Debug Data: %p inside Process: %p\n",
|
||||
CritcalSectionDebugData,
|
||||
NtCurrentTeb()->ClientId.UniqueProcess);
|
||||
|
||||
if (!CritcalSectionDebugData)
|
||||
{
|
||||
/* This is bad! */
|
||||
DPRINT1("Couldn't allocate Debug Data for: %p\n", CriticalSection);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Set it up */
|
||||
CritcalSectionDebugData->Type = RTL_CRITSECT_TYPE;
|
||||
CritcalSectionDebugData->ContentionCount = 0;
|
||||
CritcalSectionDebugData->EntryCount = 0;
|
||||
CritcalSectionDebugData->CriticalSection = CriticalSection;
|
||||
CritcalSectionDebugData->Flags = 0;
|
||||
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: %p, %p, %p\n",
|
||||
&CritcalSectionDebugData->ProcessLocksList,
|
||||
CriticalSection,
|
||||
&RtlCriticalSectionList);
|
||||
|
||||
/* Protect List */
|
||||
RtlEnterCriticalSection(&RtlCriticalSectionLock);
|
||||
|
||||
/* Add this one */
|
||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||
|
||||
/* Unprotect */
|
||||
RtlLeaveCriticalSection(&RtlCriticalSectionLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Inserting into ProcessLocks: %p, %p, %p\n",
|
||||
&CritcalSectionDebugData->ProcessLocksList,
|
||||
CriticalSection,
|
||||
&RtlCriticalSectionList);
|
||||
|
||||
/* Add it directly */
|
||||
InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* Releases a critical section and makes if available for new owners.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to release.
|
||||
*
|
||||
* Returns:
|
||||
* STATUS_SUCCESS.
|
||||
*
|
||||
* Remarks:
|
||||
* If another thread was waiting, the slow path is entered.
|
||||
*
|
||||
*--*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
RtlLeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
#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 be performed in debug builds!
|
||||
*/
|
||||
if (Thread != CriticalSection->OwningThread)
|
||||
{
|
||||
DPRINT1("Releasing critical section not owned!\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Decrease the Recursion Count. No need to do this atomically because only
|
||||
* the thread who holds the lock can call this function (unless the program
|
||||
* is totally screwed...
|
||||
*/
|
||||
if (--CriticalSection->RecursionCount)
|
||||
{
|
||||
/* Someone still owns us, but we are free. This needs to be done atomically. */
|
||||
InterlockedDecrement(&CriticalSection->LockCount);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Nobody owns us anymore. No need to do this atomically.
|
||||
* See comment above.
|
||||
*/
|
||||
CriticalSection->OwningThread = 0;
|
||||
|
||||
/* Was someone wanting us? This needs to be done atomically. */
|
||||
if (-1 != InterlockedDecrement(&CriticalSection->LockCount))
|
||||
{
|
||||
/* Let him have us */
|
||||
RtlpUnWaitCriticalSection(CriticalSection);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sucessful! */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*++
|
||||
* RtlTryEnterCriticalSection
|
||||
* @implemented NT4
|
||||
*
|
||||
* Attemps to gain ownership of the critical section without waiting.
|
||||
*
|
||||
* Params:
|
||||
* CriticalSection - Critical section to attempt acquiring.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE if the critical section has been acquired, FALSE otherwise.
|
||||
*
|
||||
* Remarks:
|
||||
* None
|
||||
*
|
||||
*--*/
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
/* Try to take control */
|
||||
if (InterlockedCompareExchange(&CriticalSection->LockCount, 0, -1) == -1)
|
||||
{
|
||||
/* It's ours */
|
||||
CriticalSection->OwningThread = NtCurrentTeb()->ClientId.UniqueThread;
|
||||
CriticalSection->RecursionCount = 1;
|
||||
return TRUE;
|
||||
}
|
||||
else if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread)
|
||||
{
|
||||
/* It's already ours */
|
||||
InterlockedIncrement(&CriticalSection->LockCount);
|
||||
CriticalSection->RecursionCount++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* It's not ours */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
RtlCheckForOrphanedCriticalSections(HANDLE ThreadHandle)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlIsCriticalSectionLocked(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
return CriticalSection->RecursionCount != 0;
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
RtlIsCriticalSectionLockedByThread(PRTL_CRITICAL_SECTION CriticalSection)
|
||||
{
|
||||
return CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread &&
|
||||
CriticalSection->RecursionCount != 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue