[NTDLL/LDR]
authorAleksey Bragin <aleksey@reactos.org>
Tue, 15 Mar 2011 18:56:17 +0000 (18:56 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Tue, 15 Mar 2011 18:56:17 +0000 (18:56 +0000)
- Rewrite loader lock APIs. Now they support proper flags, return correct error codes and generate/check a cookie.

svn path=/trunk/; revision=51056

reactos/dll/ntdll/include/ntdllp.h
reactos/dll/ntdll/ldr/ldrapi.c [new file with mode: 0644]
reactos/dll/ntdll/ldr/ldrinit.c
reactos/dll/ntdll/ldr/startup.c
reactos/dll/ntdll/ldr/utils.c
reactos/dll/ntdll/ntdll.rbuild

index 41e996c..b7b20ff 100644 (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);
diff --git a/reactos/dll/ntdll/ldr/ldrapi.c b/reactos/dll/ntdll/ldr/ldrapi.c
new file mode 100644 (file)
index 0000000..db71d74
--- /dev/null
@@ -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 */
index 9d4e378..72e717b 100644 (file)
@@ -28,6 +28,8 @@ LIST_ENTRY LdrpTlsList;
 ULONG LdrpNumberOfTlsEntries;
 ULONG LdrpNumberOfProcessors;
 
+RTL_CRITICAL_SECTION LdrpLoaderLock;
+
 BOOLEAN ShowSnaps;
 
 /* FUNCTIONS *****************************************************************/
index 06b90b0..fb814c4 100644 (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,
index 41c2802..cd7c7d6 100644 (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)
index 0a319e5..544a53b 100644 (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>