[RTL][NTDLL] Implement and export RtlInitializeCriticalSectionEx

This commit is contained in:
Timo Kreuzer 2023-08-13 14:03:48 +03:00
parent 1d59cf43af
commit 8f6aaa8af6
2 changed files with 143 additions and 71 deletions

View file

@ -940,7 +940,7 @@
@ stdcall RtlInitializeContext(ptr ptr ptr ptr ptr) @ stdcall RtlInitializeContext(ptr ptr ptr ptr ptr)
@ stdcall RtlInitializeCriticalSection(ptr) @ stdcall RtlInitializeCriticalSection(ptr)
@ stdcall RtlInitializeCriticalSectionAndSpinCount(ptr long) @ stdcall RtlInitializeCriticalSectionAndSpinCount(ptr long)
@ stub -version=0x600+ RtlInitializeCriticalSectionEx @ stdcall -version=0x600+ RtlInitializeCriticalSectionEx(ptr long long)
@ stub -version=0x600+ -arch=i386 RtlInitializeExceptionChain @ stub -version=0x600+ -arch=i386 RtlInitializeExceptionChain
@ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr) @ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr)
@ stdcall RtlInitializeGenericTableAvl(ptr ptr ptr ptr ptr) @ stdcall RtlInitializeGenericTableAvl(ptr ptr ptr ptr ptr)

View file

@ -28,6 +28,10 @@ extern HANDLE LdrpShutdownThreadId;
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
#define CRITSECT_HAS_DEBUG_INFO(CriticalSection) \
(((CriticalSection)->DebugInfo != NULL) && \
((CriticalSection)->DebugInfo != LongToPtr(-1)))
/*++ /*++
* RtlpCreateCriticalSectionSem * RtlpCreateCriticalSectionSem
* *
@ -119,7 +123,7 @@ RtlpWaitForCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
CriticalSection, CriticalSection,
CriticalSection->LockSemaphore); CriticalSection->LockSemaphore);
if (CriticalSection->DebugInfo) if (CRITSECT_HAS_DEBUG_INFO(CriticalSection))
CriticalSection->DebugInfo->EntryCount++; CriticalSection->DebugInfo->EntryCount++;
/* /*
@ -142,7 +146,7 @@ RtlpWaitForCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
for (;;) for (;;)
{ {
/* Increase the number of times we've had contention */ /* Increase the number of times we've had contention */
if (CriticalSection->DebugInfo) if (CRITSECT_HAS_DEBUG_INFO(CriticalSection))
CriticalSection->DebugInfo->ContentionCount++; CriticalSection->DebugInfo->ContentionCount++;
/* Check if allocating the event failed */ /* Check if allocating the event failed */
@ -404,7 +408,7 @@ RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
/* Protect List */ /* Protect List */
RtlEnterCriticalSection(&RtlCriticalSectionLock); RtlEnterCriticalSection(&RtlCriticalSectionLock);
if (CriticalSection->DebugInfo) if (CRITSECT_HAS_DEBUG_INFO(CriticalSection))
{ {
/* Remove it from the list */ /* Remove it from the list */
RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList); RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList);
@ -417,7 +421,7 @@ RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
/* Unprotect */ /* Unprotect */
RtlLeaveCriticalSection(&RtlCriticalSectionLock); RtlLeaveCriticalSection(&RtlCriticalSectionLock);
if (CriticalSection->DebugInfo) if (CRITSECT_HAS_DEBUG_INFO(CriticalSection))
{ {
/* Free it */ /* Free it */
RtlpFreeDebugInfo(CriticalSection->DebugInfo); RtlpFreeDebugInfo(CriticalSection->DebugInfo);
@ -542,6 +546,135 @@ RtlInitializeCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
return RtlInitializeCriticalSectionAndSpinCount(CriticalSection, 0); return RtlInitializeCriticalSectionAndSpinCount(CriticalSection, 0);
} }
/*++
* RtlInitializeCriticalSectionEx
* @implemented NT6.0
*
* Initialises a new critical section.
*
* Params:
* CriticalSection - Critical section to initialise
*
* SpinCount - Spin count for the critical section.
*
* Flags - Flags for initialization.
*
* Returns:
* STATUS_SUCCESS.
*
* Remarks:
* SpinCount is ignored on single-processor systems.
*
*--*/
NTSTATUS
NTAPI
RtlInitializeCriticalSectionEx(
_Out_ PRTL_CRITICAL_SECTION CriticalSection,
_In_ ULONG SpinCount,
_In_ ULONG Flags)
{
PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
ULONG AllowedFlags;
ULONG OsVersion;
/* Remove lower bits from flags */
Flags &= RTL_CRITICAL_SECTION_ALL_FLAG_BITS;
/* These flags generally allowed */
AllowedFlags = RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO |
RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN |
RTL_CRITICAL_SECTION_FLAG_STATIC_INIT;
/* Flags for Windows 7+ (CHECKME) */
OsVersion = NtCurrentPeb()->OSMajorVersion << 8 |
NtCurrentPeb()->OSMinorVersion;
if (OsVersion >= _WIN32_WINNT_WIN7)
{
AllowedFlags |= RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE |
RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO;
}
if (Flags & ~AllowedFlags)
{
return STATUS_INVALID_PARAMETER_3;
}
if (SpinCount & RTL_CRITICAL_SECTION_ALL_FLAG_BITS)
{
return STATUS_INVALID_PARAMETER_2;
}
/* 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;
if (Flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO)
{
CriticalSection->DebugInfo = LongToPtr(-1);
}
else
{
/* 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;
}
/*++ /*++
* RtlInitializeCriticalSectionAndSpinCount * RtlInitializeCriticalSectionAndSpinCount
* @implemented NT4 * @implemented NT4
@ -562,73 +695,12 @@ RtlInitializeCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
*--*/ *--*/
NTSTATUS NTSTATUS
NTAPI NTAPI
RtlInitializeCriticalSectionAndSpinCount(PRTL_CRITICAL_SECTION CriticalSection, RtlInitializeCriticalSectionAndSpinCount(
ULONG SpinCount) _Out_ PRTL_CRITICAL_SECTION CriticalSection,
_In_ ULONG SpinCount)
{ {
PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData; SpinCount &= ~RTL_CRITICAL_SECTION_ALL_FLAG_BITS;
return RtlInitializeCriticalSectionEx(CriticalSection, SpinCount, 0);
/* 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;
} }
/*++ /*++