[NTDLL/LDR]

- Rewrite loader lock APIs. Now they support proper flags, return correct error codes and generate/check a cookie.

svn path=/trunk/; revision=51056
This commit is contained in:
Aleksey Bragin 2011-03-15 18:56:17 +00:00
parent 62fce851b1
commit 10346cccb2
6 changed files with 256 additions and 76 deletions

View file

@ -21,6 +21,8 @@ typedef BOOL
ULONG ul_reason_for_call,
LPVOID lpReserved);
/* Global data */
extern RTL_CRITICAL_SECTION LdrpLoaderLock;
/* ldrinit.c */
NTSTATUS NTAPI LdrpInitializeTls(VOID);

View file

@ -0,0 +1,249 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS NT User Mode Library
* FILE: dll/ntdll/ldr/ldrapi.c
* PURPOSE: PE Loader Public APIs
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Aleksey Bragin (aleksey@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include <ntdll.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
#define LDR_LOCK_HELD 0x2
#define LDR_LOCK_FREE 0x1
LONG LdrpLoaderLockAcquisitonCount;
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrUnlockLoaderLock(IN ULONG Flags,
IN ULONG Cookie OPTIONAL)
{
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie);
/* Check for valid flags */
if (Flags & ~1)
{
/* Flags are invalid, check how to fail */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
}
else
{
/* A normal failure */
return STATUS_INVALID_PARAMETER_1;
}
}
/* If we don't have a cookie, just return */
if (!Cookie) return STATUS_SUCCESS;
/* Validate the cookie */
if ((Cookie & 0xF0000000) ||
((Cookie >> 16) ^ ((ULONG)(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF)))
{
DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
/* Invalid cookie, check how to fail */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
}
else
{
/* A normal failure */
return STATUS_INVALID_PARAMETER_2;
}
}
/* Ready to release the lock */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* Do a direct leave */
RtlLeaveCriticalSection(&LdrpLoaderLock);
}
else
{
/* Wrap this in SEH, since we're not supposed to raise */
_SEH2_TRY
{
/* Leave the lock */
RtlLeaveCriticalSection(&LdrpLoaderLock);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* We should use the LDR Filter instead */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
/* All done */
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
LdrLockLoaderLock(IN ULONG Flags,
OUT PULONG Result OPTIONAL,
OUT PULONG Cookie OPTIONAL)
{
LONG OldCount;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN InInit = FALSE; // FIXME
//BOOLEAN InInit = LdrpInLdrInit;
DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Result, Cookie);
/* Zero out the outputs */
if (Result) *Result = 0;
if (Cookie) *Cookie = 0;
/* Validate the flags */
if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS |
LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY))
{
/* Flags are invalid, check how to fail */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
}
/* A normal failure */
return STATUS_INVALID_PARAMETER_1;
}
/* Make sure we got a cookie */
if (!Cookie)
{
/* No cookie check how to fail */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_3);
}
/* A normal failure */
return STATUS_INVALID_PARAMETER_3;
}
/* If the flag is set, make sure we have a valid pointer to use */
if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Result))
{
/* No pointer to return the data to */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* The caller wants us to raise status */
RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
}
/* Fail */
return STATUS_INVALID_PARAMETER_2;
}
/* Return now if we are in the init phase */
if (InInit) return STATUS_SUCCESS;
/* Check what locking semantic to use */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS)
{
/* Check if we should enter or simply try */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
{
/* Do a try */
if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
{
/* It's locked */
*Result = LDR_LOCK_HELD;
goto Quickie;
}
else
{
/* It worked */
*Result = LDR_LOCK_FREE;
}
}
else
{
/* Do a enter */
RtlEnterCriticalSection(&LdrpLoaderLock);
/* See if result was requested */
if (Result) *Result = LDR_LOCK_FREE;
}
/* Increase the acquisition count */
OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
/* Generate a cookie */
*Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
}
else
{
/* Wrap this in SEH, since we're not supposed to raise */
_SEH2_TRY
{
/* Check if we should enter or simply try */
if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
{
/* Do a try */
if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
{
/* It's locked */
*Result = LDR_LOCK_HELD;
_SEH2_YIELD(return STATUS_SUCCESS);
}
else
{
/* It worked */
*Result = LDR_LOCK_FREE;
}
}
else
{
/* Do an enter */
RtlEnterCriticalSection(&LdrpLoaderLock);
/* See if result was requested */
if (Result) *Result = LDR_LOCK_FREE;
}
/* Increase the acquisition count */
OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
/* Generate a cookie */
*Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* We should use the LDR Filter instead */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
}
Quickie:
return Status;
}
/* EOF */

View file

@ -28,6 +28,8 @@ LIST_ENTRY LdrpTlsList;
ULONG LdrpNumberOfTlsEntries;
ULONG LdrpNumberOfProcessors;
RTL_CRITICAL_SECTION LdrpLoaderLock;
BOOLEAN ShowSnaps;
/* FUNCTIONS *****************************************************************/

View file

@ -25,7 +25,6 @@ extern PTEB LdrpTopLevelDllBeingLoadedTeb;
PLDR_DATA_TABLE_ENTRY ExeModule;
static RTL_CRITICAL_SECTION PebLock;
static RTL_CRITICAL_SECTION LoaderLock;
static RTL_BITMAP TlsBitMap;
static RTL_BITMAP TlsExpansionBitMap;
static volatile BOOLEAN LdrpInitialized = FALSE;
@ -467,8 +466,8 @@ LdrpInit2(PCONTEXT Context,
}
/* initalize loader lock */
RtlInitializeCriticalSection(&LoaderLock);
Peb->LoaderLock = &LoaderLock;
RtlInitializeCriticalSection(&LdrpLoaderLock);
Peb->LoaderLock = &LdrpLoaderLock;
/* create loader information */
Peb->Ldr = (PPEB_LDR_DATA) RtlAllocateHeap(Peb->ProcessHeap,

View file

@ -3154,79 +3154,6 @@ LdrProcessRelocationBlock(
return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
}
NTSTATUS
NTAPI
LdrLockLoaderLock(IN ULONG Flags,
OUT PULONG Disposition OPTIONAL,
OUT PULONG Cookie OPTIONAL)
{
NTSTATUS Status;
BOOLEAN Ret;
BOOLEAN CookieSet = FALSE;
if ((Flags != 0x01) && (Flags != 0x02))
return STATUS_INVALID_PARAMETER_1;
if (!Cookie) return STATUS_INVALID_PARAMETER_3;
/* Set some defaults for failure while verifying params */
_SEH2_TRY
{
*Cookie = 0;
CookieSet = TRUE;
if (Disposition) *Disposition = 0;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
if (CookieSet)
Status = STATUS_INVALID_PARAMETER_3;
else
Status = STATUS_INVALID_PARAMETER_2;
}
_SEH2_END;
if (Flags == 0x01)
{
DPRINT1("Warning: Reporting errors with exception not supported yet!\n");
RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
Status = STATUS_SUCCESS;
}
else
{
if (!Disposition) return STATUS_INVALID_PARAMETER_2;
Ret = RtlTryEnterCriticalSection(NtCurrentPeb()->LoaderLock);
if (Ret)
*Disposition = 0x01;
else
*Disposition = 0x02;
Status = STATUS_SUCCESS;
}
/* FIXME: Cookie is based on part of the thread id */
*Cookie = (ULONG)NtCurrentTeb()->RealClientId.UniqueThread;
return Status;
}
NTSTATUS
NTAPI
LdrUnlockLoaderLock(IN ULONG Flags,
IN ULONG Cookie OPTIONAL)
{
if (Flags != 0x01)
return STATUS_INVALID_PARAMETER_1;
if (Cookie != (ULONG)NtCurrentTeb()->RealClientId.UniqueThread)
return STATUS_INVALID_PARAMETER_2;
RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
return STATUS_SUCCESS;
}
BOOLEAN
NTAPI
LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)

View file

@ -47,6 +47,7 @@
<pch>ntdll.h</pch>
</directory>
<directory name="ldr">
<file>ldrapi.c</file>
<file>ldrinit.c</file>
<file>ldrutils.c</file>
<file>startup.c</file>