diff --git a/reactos/dll/ntdll/include/ntdllp.h b/reactos/dll/ntdll/include/ntdllp.h index 41e996c17b1..b7b20ff7f92 100644 --- a/reactos/dll/ntdll/include/ntdllp.h +++ b/reactos/dll/ntdll/include/ntdllp.h @@ -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); diff --git a/reactos/dll/ntdll/ldr/ldrapi.c b/reactos/dll/ntdll/ldr/ldrapi.c new file mode 100644 index 00000000000..db71d74ca3c --- /dev/null +++ b/reactos/dll/ntdll/ldr/ldrapi.c @@ -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 +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/dll/ntdll/ldr/ldrinit.c b/reactos/dll/ntdll/ldr/ldrinit.c index 9d4e378d22a..72e717beb33 100644 --- a/reactos/dll/ntdll/ldr/ldrinit.c +++ b/reactos/dll/ntdll/ldr/ldrinit.c @@ -28,6 +28,8 @@ LIST_ENTRY LdrpTlsList; ULONG LdrpNumberOfTlsEntries; ULONG LdrpNumberOfProcessors; +RTL_CRITICAL_SECTION LdrpLoaderLock; + BOOLEAN ShowSnaps; /* FUNCTIONS *****************************************************************/ diff --git a/reactos/dll/ntdll/ldr/startup.c b/reactos/dll/ntdll/ldr/startup.c index 06b90b07558..fb814c499f2 100644 --- a/reactos/dll/ntdll/ldr/startup.c +++ b/reactos/dll/ntdll/ldr/startup.c @@ -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, diff --git a/reactos/dll/ntdll/ldr/utils.c b/reactos/dll/ntdll/ldr/utils.c index 41c2802cafb..cd7c7d69023 100644 --- a/reactos/dll/ntdll/ldr/utils.c +++ b/reactos/dll/ntdll/ldr/utils.c @@ -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) diff --git a/reactos/dll/ntdll/ntdll.rbuild b/reactos/dll/ntdll/ntdll.rbuild index 0a319e5603e..544a53b67ea 100644 --- a/reactos/dll/ntdll/ntdll.rbuild +++ b/reactos/dll/ntdll/ntdll.rbuild @@ -47,6 +47,7 @@ ntdll.h + ldrapi.c ldrinit.c ldrutils.c startup.c