- New ERESOURCE implementation: fixes the return value of some functions (VOID vs...
authorAlex Ionescu <aionescu@gmail.com>
Thu, 5 Jan 2006 16:24:32 +0000 (16:24 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Thu, 5 Jan 2006 16:24:32 +0000 (16:24 +0000)
- Also, the spinlock is not actually acquired on non-SMP builds; instead, interrupts are blocked and unblocked for acquire/release, this optimizes locking.
- Added many asserts and bugcheck scenarios.
- Added thread priority boosting.
- Added some debugging helpers and deadlock detection.
- Added RESOURCE_NOT_OWNED bugcehck message.
* Thanks again to Waxdragon (Andrew) for testing this build.

svn path=/trunk/; revision=20580

reactos/include/ndk/extypes.h
reactos/ntoskrnl/ex/init.c
reactos/ntoskrnl/ex/resource.c
reactos/ntoskrnl/include/internal/ex.h
reactos/ntoskrnl/include/internal/tag.h
reactos/ntoskrnl/ntoskrnl.mc
reactos/w32api/include/ddk/winddk.h

index 64557d4..bd7c6f1 100644 (file)
@@ -117,6 +117,11 @@ extern ULONG NTSYSAPI NtBuildNumber;
 #define EX_PUSH_LOCK_FLAGS_EXCLUSIVE        1
 #define EX_PUSH_LOCK_FLAGS_WAIT             2
 
+//
+// Resource (ERESOURCE) Flags
+//
+#define ResourceHasDisabledPriorityBoost    0x08
+
 //
 // Shutdown types for NtShutdownSystem
 //
index 2847aaf..82df1cf 100644 (file)
@@ -489,7 +489,7 @@ ExpLoadInitialProcess(PHANDLE ProcessHandle,
     DPRINT("Process created successfully\n");
     return STATUS_SUCCESS;
 }
-   
+
 VOID
 INIT_FUNCTION
 STDCALL
@@ -543,6 +543,9 @@ ExpInitializeExecutive(VOID)
     InitializeListHead(&KiProfileSourceListHead);
     KeInitializeSpinLock(&KiProfileLock);
 
+    /* Initialize resources */
+    ExpResourceInitialization();
+
     /* Load basic Security for other Managers */
     if (!SeInit1()) KEBUGCHECK(SECURITY_INITIALIZATION_FAILED);
 
index 1d67326..2b87a4b 100644 (file)
-/* $Id$
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
  * FILE:            ntoskrnl/ex/resource.c
- * PURPOSE:         Resource synchronization construct
- *
- * PROGRAMMERS:     No programmer listed.
+ * PURPOSE:         ERESOURCE Implementation
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
  */
 
-
-/*
- * Usage of ERESOURCE members is not documented.
- * From names of members and functionnalities, we can assume :
- *
- * OwnerTable = list of threads who have shared access(if more than one)
- * ActiveCount = number of threads who have access to the resource
- * Flag = bits : ResourceOwnedExclusive=0x80
- *               ResourceNeverExclusive=0x10
- *               ResourceReleaseByOtherThread=0x20
- *               ResourceDisableBoost=0x08
- * SharedWaiters = semaphore, used to manage wait list of shared waiters.
- * ExclusiveWaiters = event, used to manage wait list of exclusive waiters.
- * OwnerThreads[0]= thread who have exclusive access
- * OwnerThreads[1]= if only one thread own the resource
- *                     thread who have shared access
- *                  else
- *                     OwnerThread=0
- *                     and TableSize = number of entries in the owner table
- * NumberOfExclusiveWaiters = number of threads waiting for exclusive access.
- * NumberOfSharedWaiters = number of threads waiting for exclusive access.
- *
+/* WARNING:
+ * This implementation is the Windows NT 5.x one.
+ * NT 6.0 beta has optimized the OwnerThread entry array
+ * and the internals of ExpFindEntryForThread and ExpFindFreeEntry
+ * need to be modified accordingly in order to support the WDK.
+ * These changes will not be made here until NT 6.0 reaches RTM status since
+ * there is a possibility that they will be removed; as such, do NOT
+ * update ERESOURCE/relevant code to the WDK definition.
  */
 
-#define ResourceDisableBoost   0x08
-
 /* INCLUDES *****************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
-/* FUNCTIONS *****************************************************************/
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, ExpResourceInitialization)
+#endif
 
+/* Macros for reading resource flags */
+#define IsExclusiveWaiting(r)   (r->NumberOfExclusiveWaiters)
+#define IsSharedWaiting(r)      (r->NumberOfSharedWaiters)
+#define IsOwnedExclusive(r)     (r->Flag & ResourceOwnedExclusive)
 
-BOOLEAN
-STDCALL
-ExTryToAcquireResourceExclusiveLite (
-       PERESOURCE      Resource
-       )
-/*
- * FUNCTION: Attempts to require the resource for exclusive access
- * ARGUMENTS:
- *         Resource = Points to the resource of be acquired
- * RETURNS: TRUE if the resource was acquired for the caller
- * NOTES: Must be acquired at IRQL < DISPATCH_LEVEL
- */
+/* DATA***********************************************************************/
+
+LARGE_INTEGER ExpTimeout;
+ULONG ExpResourceTimeoutCount = 90 * 3600 / 2;
+KSPIN_LOCK ExpResourceSpinLock;
+LIST_ENTRY ExpSystemResourcesList;
+BOOLEAN ExResourceStrict = FALSE; /* FIXME */
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+#if DBG
+/*++
+ * @name ExpVerifyResource
+ *
+ *     The ExpVerifyResource routine verifies the correctness of an ERESOURCE
+ *
+ * @param Resource
+ *        Pointer to the resource being verified.
+ *
+ * @return None.
+ *
+ * @remarks Only present on DBG builds.
+ *
+ *--*/
+VOID
+NTAPI
+ExpVerifyResource(IN PERESOURCE Resource)
 {
-  return(ExAcquireResourceExclusiveLite(Resource,FALSE));
+    /* Verify the resource data */
+    ASSERT((((ULONG_PTR)Resource) & (sizeof(ULONG_PTR) - 1)) == 0);
+    ASSERT(!Resource->SharedWaiters ||
+            Resource->SharedWaiters->Header.Type == SemaphoreObject);
+    ASSERT(!Resource->SharedWaiters ||
+            Resource->SharedWaiters->Header.Size == (sizeof(KSEMAPHORE) / sizeof(ULONG)));
+    ASSERT(!Resource->ExclusiveWaiters ||
+            Resource->ExclusiveWaiters->Header.Type == SynchronizationEvent);
+    ASSERT(!Resource->ExclusiveWaiters ||
+            Resource->ExclusiveWaiters->Header.Size == (sizeof(KEVENT) / sizeof(ULONG)));
 }
 
-#ifdef ExAcquireResourceExclusive
-#undef ExAcquireResourceExclusive
+/*++
+ * @name ExpCheckForApcsDisabled
+ *
+ *     The ExpCheckForApcsDisabled routine checks if Kernel APCs are still
+ *     enabled when they should be disabled, and optionally breakpoints.
+ *
+ * @param BreakIfTrue
+ *        Specifies if we should break if an invalid APC State is detected.
+ *
+ * @param Resource
+ *        Pointer to the resource being checked.
+ *
+ * @param Thread
+ *        Pointer to the thread being checked.
+ *
+ * @return None.
+ *
+ * @remarks Only present on DBG builds. Depends on ExResourceStrict value.
+ *
+ *--*/
+VOID
+NTAPI
+ExpCheckForApcsDisabled(IN BOOLEAN BreakIfTrue,
+                        IN PERESOURCE Resource,
+                        IN PETHREAD Thread)
+{
+    /* Check if we should care and check if we should break */
+    if ((ExResourceStrict) &&
+        (BreakIfTrue) &&
+        !(Thread->SystemThread) &&
+        !(Thread->Tcb.CombinedApcDisable))
+    {
+        /* Bad! */
+        DPRINT1("EX: resource: APCs still enabled before resource %p acquire "
+                "!!!\n", Resource);
+        DbgBreakPoint();
+    }
+}
 #endif
 
-/*
- * @implemented
- */
+/*++
+ * @name ExpResourceInitialization
+ *
+ *     The ExpResourceInitialization routine initializes resources for use.
+ *
+ * @param None.
+ *
+ * @return None.
+ *
+ * @remarks This routine should only be called once, during system startup.
+ *
+ *--*/
+VOID
+NTAPI
+INIT_FUNCTION
+ExpResourceInitialization(VOID)
+{
+    /* Setup the timeout */
+    ExpTimeout.QuadPart = Int32x32To64(4, -10000000);
+    InitializeListHead(&ExpSystemResourcesList);
+    KeInitializeSpinLock(&ExpResourceSpinLock);
+}
+
+/*++
+ * @name ExpAllocateExclusiveWaiterEvent
+ *
+ *     The ExpAllocateExclusiveWaiterEvent routine creates the event that will
+ *     be used by exclusive waiters on the resource.
+ *
+ * @param Resource
+ *        Pointer to the resource.
+ *
+ * @param OldIrql
+ *        Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return None.
+ *
+ * @remarks The pointer to the event must be atomically set.
+ *
+ *--*/
+VOID
+NTAPI
+ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource,
+                                IN PKIRQL OldIrql)
+{
+    PKEVENT Event;
+
+    /* Release the lock */
+    ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+    /* Allocate the event */
+    Event = ExAllocatePoolWithTag(NonPagedPool,
+                                  sizeof(KEVENT),
+                                  TAG_RESOURCE_EVENT);
+
+    /* Initialize it */
+    KeInitializeEvent(Event, SynchronizationEvent, FALSE);
+
+    /* Set it */
+    if (InterlockedCompareExchangePointer(&Resource->ExclusiveWaiters,
+                                          Event,
+                                          NULL))
+    {
+        /* Someone already set it, free our event */
+        DPRINT1("WARNING: Handling race condition\n");
+        ExFreePool(Event);
+    }
+
+    /* Re-acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
+}
+
+/*++
+ * @name ExpAllocateSharedWaiterSemaphore
+ *
+ *     The ExpAllocateSharedWaiterSemaphore routine creates the semaphore that
+ *     will be used by shared waiters on the resource.
+ *
+ * @param Resource
+ *        Pointer to the resource.
+ *
+ * @param OldIrql
+ *        Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return None.
+ *
+ * @remarks The pointer to the semaphore must be atomically set.
+ *
+ *--*/
+VOID
+NTAPI
+ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource,
+                                 IN PKIRQL OldIrql)
+{
+    PKSEMAPHORE Semaphore;
+
+    /* Release the lock */
+    ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+    /* Allocate the semaphore */
+    Semaphore = ExAllocatePoolWithTag(NonPagedPool,
+                                      sizeof(KSEMAPHORE),
+                                      TAG_RESOURCE_SEMAPHORE);
+
+    /* Initialize it */
+    KeInitializeSemaphore(Semaphore, 0, MAXLONG);
+
+    /* Set it */
+    if (InterlockedCompareExchangePointer(&Resource->SharedWaiters,
+                                          Semaphore,
+                                          NULL))
+    {
+        /* Someone already set it, free our semaphore */
+        DPRINT1("WARNING: Handling race condition\n");
+        ExFreePool(Semaphore);
+    }
+
+    /* Re-acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
+}
+
+/*++
+ * @name ExpExpandResourceOwnerTable
+ *
+ *     The ExpExpandResourceOwnerTable routine expands the owner table of the
+ *     specified resource.
+ *
+ * @param Resource
+ *        Pointer to the resource.
+ *
+ * @param OldIrql
+ *        Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+NTAPI
+ExpExpandResourceOwnerTable(IN PERESOURCE Resource,
+                            IN PKIRQL OldIrql)
+{
+    POWNER_ENTRY Owner, Table;
+    ULONG NewSize, OldSize;
+    DPRINT("ExpExpandResourceOwnerTable: %p\n", Resource);
+
+    /* Get the owner table */
+    Owner = Resource->OwnerTable;
+    if (!Owner)
+    {
+        /* Start with the default size of 3 */
+        OldSize = 0;
+        NewSize = 3;
+    }
+    else
+    {
+        /* Add 4 more entries */
+        OldSize = Owner->TableSize;
+        NewSize = OldSize + 4;
+    }
+
+    /* Release the lock */
+    ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+    /* Allocate memory for the table */
+    Table = ExAllocatePoolWithTag(NonPagedPool,
+                                  NewSize * sizeof(OWNER_ENTRY),
+                                  TAG_RESOURCE_TABLE);
+
+    /* Zero the table */
+    RtlZeroMemory((PVOID)(Table + OldSize),
+                  (NewSize - OldSize) * sizeof(OWNER_ENTRY));
+
+    /* Lock the resource */
+    ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
+
+    /* Make sure nothing has changed */
+    if ((Owner != Resource->OwnerTable) ||
+        ((Owner) && (OldSize != Resource->OwnerTable->TableSize)))
+    {
+        /* Resource changed while we weren't holding the lock; bail out */
+        ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+        ExFreePool(Table);
+    }
+    else
+    {
+        /* Copy the table */
+        RtlCopyMemory((PVOID)Table,
+                      Owner,
+                      OldSize * sizeof(OWNER_ENTRY));
+
+        /* Acquire dispatcher lock to prevent thread boosting */
+        //KeAcquireDispatcherDatabaseLockAtDpcLevel();
+
+        /* Set the new table data */
+        Table->TableSize = NewSize;
+        Resource->OwnerTable = Table;
+
+        /* Sanity check */
+        ExpVerifyResource(Resource);
+
+        /* Release locks */
+        //KeReleaseDispatcherDatabaseLockFromDpcLevel();
+        ExReleaseResourceLock(&Resource->SpinLock, *OldIrql);
+
+        /* Free the old table */
+        if (Owner) ExFreePool(Owner);
+
+        /* Set the resource index */
+        if (!OldSize) OldSize = 1;
+    }
+
+    /* Set the resource index */
+    KeGetCurrentThread()->ResourceIndex = (UCHAR)OldSize;
+
+    /* Lock the resource again */
+    ExAcquireResourceLock(&Resource->SpinLock, OldIrql);
+}
+
+/*++
+ * @name ExpFindFreeEntry
+ *
+ *     The ExpFindFreeEntry routine locates an empty owner entry in the
+ *     specified resource. If none was found, then the owner table is
+ *     expanded.
+ *
+ * @param Resource
+ *        Pointer to the resource.
+ *
+ * @param OldIrql
+ *        Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return Pointer to an empty OWNER_ENTRY structure.
+ *
+ * @remarks None.
+ *
+ *--*/
+POWNER_ENTRY
+FASTCALL
+ExpFindFreeEntry(IN PERESOURCE Resource,
+                 IN PKIRQL OldIrql)
+{
+    POWNER_ENTRY Owner, Limit;
+    ULONG Size;
+    POWNER_ENTRY FreeEntry = NULL;
+    DPRINT("ExpFindFreeEntry: %p\n", Resource);
+
+    /* Sanity check */
+    ASSERT(OldIrql != 0);
+    ASSERT(Resource->OwnerThreads[0].OwnerThread != 0);
+
+    /* Check if the next built-in entry is free */
+    if (!Resource->OwnerThreads[1].OwnerThread)
+    {
+        /* Return it */
+        FreeEntry = &Resource->OwnerThreads[1];
+    }
+    else
+    {
+        /* Get the current table pointer */
+        Owner = Resource->OwnerTable;
+        if (Owner)
+        {
+            /* Loop every entry */
+            Size = Owner->TableSize;
+            Limit = &Owner[Size];
+
+            /* Go to the next entry and loop */
+            Owner++;
+            do
+            {
+                /* Check for a free entry */
+                if (!Owner->OwnerThread)
+                {
+                    /* Found one, return it!*/
+                    FreeEntry = Owner;
+                    break;
+                }
+
+                /* Move on */
+                Owner++;
+            } while (Owner != Limit);
+
+            /* If we found a free entry by now, return it */
+            if (FreeEntry)
+            {
+                /* Set the resource index */
+                KeGetCurrentThread()->ResourceIndex = 
+                    (UCHAR)(Owner - Resource->OwnerTable);
+                return FreeEntry;
+            }
+        }
+
+        /* No free entry, expand the table */
+        ExpExpandResourceOwnerTable(Resource, OldIrql);
+        FreeEntry = NULL;
+    }
+
+    /* Return the entry found */
+    return FreeEntry;
+}
+
+/*++
+ * @name ExpFindEntryForThread
+ *
+ *     The ExpFindEntryForThread routine locates the owner entry associated with
+ *     the specified thread in the given resource. If none was found, then the
+ *     owner table is expanded.
+ *
+ * @param Resource
+ *        Pointer to the resource.
+ *
+ * @param Thread
+ *        Pointer to the thread to find.
+ *
+ * @param OldIrql
+ *        Pointer to current IRQL. TBC: Pointer to in-stack queued spinlock.
+ *
+ * @return Pointer to an empty OWNER_ENTRY structure.
+ *
+ * @remarks None.
+ *
+ *--*/
+POWNER_ENTRY
+FASTCALL
+ExpFindEntryForThread(IN PERESOURCE Resource,
+                      IN ERESOURCE_THREAD Thread,
+                      IN PKIRQL OldIrql)
+{
+    POWNER_ENTRY FreeEntry, Owner, Limit;
+    ULONG Size;
+    DPRINT("ExpFindEntryForThread: %p\n", Resource);
+
+    /* Start by looking in the static array */
+    if (Resource->OwnerThreads[0].OwnerThread == Thread)
+    {
+        /* Found it, return it! */
+        return &Resource->OwnerThreads[0];
+    }
+    else if (Resource->OwnerThreads[1].OwnerThread == Thread)
+    {
+        /* Return it */
+        return &Resource->OwnerThreads[1];
+    }
+    else
+    {
+        /* Check if the first array is empty for our use */
+        FreeEntry = NULL;
+        if (!Resource->OwnerThreads[1].OwnerThread)
+        {
+            /* Use this as the first free entry */
+            FreeEntry = &Resource->OwnerThreads[1];
+        }
+
+        /* Get the current table pointer */
+        Owner = Resource->OwnerTable;
+        if (!Owner)
+        {
+            /* The current table is empty, so no size */
+            Size = 0;
+        }
+        else
+        {
+            /* We have a table, get it's size and limit */
+            Size = Owner->TableSize;
+            Limit = &Owner[Size];
+
+            /* Go to the next entry and loop */
+            Owner++;
+            do
+            {
+                /* Check for a match */
+                if (Owner->OwnerThread == Thread)
+                {
+                    /* Match found! Set the resource index */
+                    KeGetCurrentThread()->ResourceIndex = 
+                        (UCHAR)(Owner - Resource->OwnerTable);
+                    return Owner;
+                }
+
+                /* If we don't have a free entry yet, make this one free */
+                if (!(FreeEntry) && !(Owner->OwnerThread)) FreeEntry = Owner;
+
+                /* Move on */
+                Owner++;
+            } while (Owner != Limit);
+        }
+    }
+
+    /* Check if it's OK to do an expansion */
+    if (!OldIrql) return NULL;
+
+    /* If we found a free entry by now, return it */
+    if (FreeEntry)
+    {
+        /* Set the resource index */
+        KeGetCurrentThread()->ResourceIndex = (UCHAR)
+                                              (Owner - Resource->OwnerTable);
+        return FreeEntry;
+    }
+
+    /* No free entry, expand the table */
+    ExpExpandResourceOwnerTable(Resource, OldIrql);
+    return NULL;
+}
+
+/*++
+ * @name ExpBoostOwnerThread
+ *
+ *     The ExpBoostOwnerThread routine increases the priority of a waiting
+ *     thread in an attempt to fight a possible deadlock.
+ *
+ * @param Thread
+ *        Pointer to the current thread.
+ *
+ * @param OwnerThread
+ *        Pointer to thread that owns the resource.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+FASTCALL
+ExpBoostOwnerThread(IN PKTHREAD Thread,
+                    IN PKTHREAD OwnerThread)
+{
+    BOOLEAN Released = FALSE;
+    DPRINT("ExpBoostOwnerThread: %p\n", Thread);
+
+    /* Make sure the owner thread is a pointer, not an ID */
+    if (!((ULONG_PTR)OwnerThread & 0x3))
+    {
+        /* Check if we can actually boost it */
+        if ((OwnerThread->Priority < Thread->Priority) &&
+            (OwnerThread->Priority < 14))
+        {
+            /* Make sure we're at dispatch */
+            ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+
+            /* Set the new priority */
+            OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority;
+
+            /* Update quantum */
+            OwnerThread->Quantum = OwnerThread->QuantumReset;
+
+            /* Update the kernel state */
+            KiSetPriorityThread(OwnerThread, 14, &Released);
+
+            /* Release Lock if needed */
+            if (!Released) KeReleaseDispatcherDatabaseLockFromDpcLevel();
+
+            /* Make sure we're still at dispatch */
+            ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+        }
+    }
+}
+
+/*++
+ * @name ExpWaitForResource
+ *
+ *     The ExpWaitForResource routine performs a wait on the specified resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to wait on.
+ *
+ * @param OwnerThread
+ *        Pointer to object (exclusive event or shared semaphore) to wait on.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
+VOID
+FASTCALL
+ExpWaitForResource(IN PERESOURCE Resource,
+                   IN PVOID Object)
+{
+    ULONG i;
+    ULONG Size, WaitCount = 0;
+    KIRQL OldIrql;
+    POWNER_ENTRY Owner;
+    PKTHREAD OwnerThread, Thread;
+    NTSTATUS Status;
+    LARGE_INTEGER Timeout;
+
+    /* Increase contention count and use a 5 second timeout */
+    Resource->ContentionCount++;
+    Timeout.QuadPart = 500 * -10000;
+    for(;;)
+    {
+        /* Wait for ownership */
+        Status = KeWaitForSingleObject(Object,
+                                       WrResource,
+                                       KernelMode,
+                                       FALSE,
+                                       &Timeout);
+        if (Status != STATUS_TIMEOUT) break;
+
+        /* Increase wait count */
+        WaitCount++;
+        Timeout = ExpTimeout;
+
+        /* Check if we've exceeded the limit */
+        if (WaitCount > ExpResourceTimeoutCount)
+        {
+            /* Reset wait count */
+            WaitCount = 0;
+#if DBG
+            /* Lock the resource */
+            ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+            /* Dump debug information */
+            DPRINT1("Resource @ %lx\n", Resource);
+            DPRINT1(" ActiveCount = %04lx  Flags = %s%s%s\n",
+                    Resource->ActiveCount,
+                    IsOwnedExclusive(Resource) ? "IsOwnedExclusive " : "",
+                    IsSharedWaiting(Resource) ? "SharedWaiter "     : "",
+                    IsExclusiveWaiting(Resource) ? "ExclusiveWaiter "  : "");
+            DPRINT1(" NumberOfExclusiveWaiters = %04lx\n",
+                    Resource->NumberOfExclusiveWaiters);
+            DPRINT1("   Thread = %08lx, Count = %02x\n",
+                    Resource->OwnerThreads[0].OwnerThread,
+                    Resource->OwnerThreads[0].OwnerCount);
+            DPRINT1("   Thread = %08lx, Count = %02x\n",
+                    Resource->OwnerThreads[1].OwnerThread,
+                    Resource->OwnerThreads[1].OwnerCount);
+
+            /* Dump out the table too */
+            Owner = Resource->OwnerTable;
+            if (Owner)
+            {
+                /* Loop every entry */
+                Size = Owner->TableSize;
+                for (i = 1; i < Size; i++)
+                {
+                    /* Print the data */
+                    Owner++;
+                    DPRINT1("   Thread = %08lx, Count = %02x\n",
+                            Owner->OwnerThread,
+                            Owner->OwnerCount);
+                }
+            }
+
+            /* Break */
+            DbgBreakPoint();
+            DPRINT1("EX - Rewaiting\n");
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+#endif
+        }
+
+        /* Check if we can boost */
+        if (!(Resource->Flag & ResourceHasDisabledPriorityBoost))
+        {
+            /* Get the current kernel thread and lock the dispatcher */
+            Thread = KeGetCurrentThread();
+            Thread->WaitIrql = KeAcquireDispatcherDatabaseLock();
+            Thread->WaitNext = TRUE;
+
+            /* Get the owner thread and boost it */
+            OwnerThread = (PKTHREAD)Resource->OwnerThreads[0].OwnerThread;
+            if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
+
+            /* If it's a shared resource */
+            if (!IsOwnedExclusive(Resource))
+            {
+                /* Boost the other owner thread too */
+                OwnerThread = (PKTHREAD)Resource->OwnerThreads[1].OwnerThread;
+                if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
+
+                /* Get the table */
+                Owner = Resource->OwnerTable;
+                if (Owner)
+                {
+                    /* Loop every entry */
+                    Size = Owner->TableSize;
+                    for (i = 1; i < Size; i++)
+                    {
+                        /* Boot every thread in the table */
+                        OwnerThread = (PKTHREAD)
+                                       Resource->OwnerThreads[1].OwnerThread;
+                        if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
+                    }
+                }
+            }
+        }
+    }
+}
+
+/* FUNCTIONS *****************************************************************/
+
+/*++
+ * @name ExAcquireResourceExclusiveLite
+ * @implemented NT4
+ *
+ *     The ExAcquireResourceExclusiveLite routine acquires the given resource
+ *     for exclusive access by the calling thread.
+ *
+ * @param Resource
+ *        Pointer to the resource to acquire.
+ *
+ * @param Wait
+ *        Specifies the routine's behavior whenever the resource cannot be
+ *        acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ *         and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ *          Normal kernel APC delivery must be disabled before calling this
+ *          routine. Disable normal kernel APC delivery by calling
+ *          KeEnterCriticalRegion. Delivery must remain disabled until the
+ *          resource is released, at which point it can be reenabled by calling
+ *          KeLeaveCriticalRegion.
+ *
+ *          For better performance, call ExTryToAcquireResourceExclusiveLite,
+ *          rather than calling ExAcquireResourceExclusiveLite with Wait set
+ *          to FALSE.
+ *
+ *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ *          DISPATCH_LEVEL.
+ *
+ *--*/
 BOOLEAN
-STDCALL
-ExAcquireResourceExclusive (
-       PERESOURCE      Resource,
-       BOOLEAN         Wait
-       )
+NTAPI
+ExAcquireResourceExclusiveLite(PERESOURCE Resource,
+                               BOOLEAN Wait)
 {
-   return(ExAcquireResourceExclusiveLite(Resource,Wait));
+    KIRQL OldIrql = PASSIVE_LEVEL;
+    ERESOURCE_THREAD Thread;
+    BOOLEAN Success;
+
+    /* Sanity check */
+    ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
+
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
+
+    /* Sanity check and validation */
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
+
+    /* Acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+    ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread);
+
+    /* Check if there is a shared owner or exclusive owner */
+TryAcquire:
+    DPRINT("ExAcquireResourceExclusiveLite(Resource 0x%p, Wait %d)\n",
+           Resource, Wait);
+    if (Resource->ActiveCount)
+    {
+        /* Check if it's exclusively owned, and we own it */
+        if ((IsOwnedExclusive(Resource)) &&
+            (Resource->OwnerThreads[0].OwnerThread == Thread))
+        {
+            /* Increase the owning count */
+            Resource->OwnerThreads[0].OwnerCount++;
+            Success = TRUE;
+        }
+        else
+        {
+            /*
+             * If the caller doesn't want us to wait, we can't acquire the
+             * resource because someone else then us owns it. If we can wait,
+             * then we'll wait.
+             */
+            if (!Wait)
+            {
+                Success = FALSE;
+            }
+            else
+            {
+                /* Check if it has exclusive waiters */
+                if (!Resource->ExclusiveWaiters)
+                {
+                    /* It doesn't, allocate the event and try acquiring again */
+                    ExpAllocateExclusiveWaiterEvent(Resource, &OldIrql);
+                    goto TryAcquire;
+                }
+                else
+                {
+                    /* Has exclusive waiters, wait on it */
+                    Resource->NumberOfExclusiveWaiters++;
+                    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                    ExpWaitForResource(Resource, Resource->ExclusiveWaiters);
+
+                    /* Set owner and return success */
+                    Resource->OwnerThreads[0].OwnerThread = Thread;
+                    return TRUE;
+                }
+            }
+        }
+    }
+    else
+    {
+        /* Nobody owns it, so let's! */
+        Resource->Flag |= ResourceOwnedExclusive;
+        Resource->ActiveCount = 1;
+        Resource->OwnerThreads[0].OwnerThread = Thread;
+        Resource->OwnerThreads[0].OwnerCount = 1;
+        Success = TRUE;
+    }
+
+    /* Release the lock and return */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    return Success;
 }
 
+/*++
+ * @name ExAcquireResourceSharedLite
+ * @implemented NT4
+ *
+ *     The ExAcquireResourceSharedLite routine acquires the given resource
+ *     for shared access by the calling thread.
+ *
+ * @param Resource
+ *        Pointer to the resource to acquire.
+ *
+ * @param Wait
+ *        Specifies the routine's behavior whenever the resource cannot be
+ *        acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ *         and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ *          Normal kernel APC delivery must be disabled before calling this
+ *          routine. Disable normal kernel APC delivery by calling
+ *          KeEnterCriticalRegion. Delivery must remain disabled until the
+ *          resource is released, at which point it can be reenabled by calling
+ *          KeLeaveCriticalRegion.
+ *
+ *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ *          DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExAcquireResourceSharedLite(PERESOURCE Resource,
+                            BOOLEAN Wait)
+{
+    KIRQL OldIrql;
+    ERESOURCE_THREAD Thread;
+    POWNER_ENTRY Owner;
+
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
+
+    /* Sanity check and validation */
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
+
+    /* Acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+    ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread);
+
+    /* See if nobody owns us */
+TryAcquire:
+    DPRINT("ExAcquireResourceSharedLite(Resource 0x%p, Wait %d)\n",
+            Resource, Wait);
+    if (!Resource->ActiveCount)
+    {
+        /* Nobody owns it, so let's take control */
+        Resource->ActiveCount = 1;
+        Resource->OwnerThreads[1].OwnerThread = Thread;
+        Resource->OwnerThreads[1].OwnerCount = 1;
+
+        /* Release the lock and return */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        return TRUE;
+    }
+
+    /* Check if it's exclusively owned */
+    if (IsOwnedExclusive(Resource))
+    {
+        /* Check if we own it */
+        if (Resource->OwnerThreads[0].OwnerThread == Thread)
+        {
+            /* Increase the owning count */
+            Resource->OwnerThreads[0].OwnerCount++;
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
 
-/*
- * @implemented
- */
+        /* Find a free entry */
+        Owner = ExpFindFreeEntry(Resource, &OldIrql);
+        if (!Owner) goto TryAcquire;
+    }
+    else
+    {
+        /* Resource is shared, find who owns it */
+        Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+        if (!Owner) goto TryAcquire;
+
+        /* Is it us? */
+        if (Owner->OwnerThread == Thread)
+        {
+            /* Increase acquire count and return */
+            Owner->OwnerCount++;
+            ASSERT(Owner->OwnerCount != 0);
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+
+        /* Try to find if there are exclusive waiters */
+        if (!IsExclusiveWaiting(Resource))
+        {
+            /* There are none, so acquire it */
+            Owner->OwnerThread = Thread;
+            Owner->OwnerCount = 1;
+            Resource->ActiveCount++;
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+    }
+
+    /* If we got here, then we need to wait. Are we allowed? */
+    if (!Wait)
+    {
+        /* Release the lock and return */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        return TRUE;
+    }
+
+    /* Check if we have a shared waiters semaphore */
+    if (!Resource->SharedWaiters)
+    {
+        /* Allocate it and try another acquire */
+        ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
+        goto TryAcquire;
+    }
+
+    /* Now wait for the resource */
+    Owner->OwnerThread = Thread;
+    Owner->OwnerCount = 1;
+    Resource->NumberOfSharedWaiters++;
+
+    /* Release the lock and return */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    ExpWaitForResource(Resource, Resource->SharedWaiters);
+    return TRUE;
+}
+
+/*++
+ * @name ExAcquireSharedStarveExclusive
+ * @implemented NT4
+ *
+ *     The ExAcquireSharedStarveExclusive routine acquires the given resource
+ *     shared access without waiting for any pending attempts to acquire
+ *     exclusive access to the same resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to acquire.
+ *
+ * @param Wait
+ *        Specifies the routine's behavior whenever the resource cannot be
+ *        acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ *         and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ *          Normal kernel APC delivery must be disabled before calling this
+ *          routine. Disable normal kernel APC delivery by calling
+ *          KeEnterCriticalRegion. Delivery must remain disabled until the
+ *          resource is released, at which point it can be reenabled by calling
+ *          KeLeaveCriticalRegion.
+ *
+ *          Callers of ExAcquireSharedStarveExclusive usually need quick access
+ *          to a shared resource in order to save an exclusive accessor from
+ *          doing redundant work. For example, a file system might call this
+ *          routine to modify a cached resource, such as a BCB pinned in the
+ *          cache, before the Cache Manager can acquire exclusive access to the
+ *          resource and write the cache out to disk.
+ *
+ *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ *          DISPATCH_LEVEL.
+ *
+ *--*/
 BOOLEAN
-STDCALL
-ExAcquireResourceExclusiveLite (
-       PERESOURCE      Resource,
-       BOOLEAN         Wait
-       )
-/*
- * FUNCTION: Acquires a resource exclusively for the calling thread
- * ARGUMENTS:
- *       Resource = Points to the resource to acquire
- *       Wait = Is set to TRUE if the caller should wait to acquire the
- *              resource if it can't be acquired immediately
- * RETURNS: TRUE if the resource was acquired,
- *          FALSE otherwise
- * NOTES: Must be called at IRQL < DISPATCH_LEVEL
- */
+NTAPI
+ExAcquireSharedStarveExclusive(PERESOURCE Resource,
+                               BOOLEAN Wait)
 {
-   KIRQL oldIrql;
+    KIRQL OldIrql;
+    ERESOURCE_THREAD Thread;
+    POWNER_ENTRY Owner;
+
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
+
+    /* Sanity check and validation */
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
+
+    /* Acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+    /* See if nobody owns us */
+TryAcquire:
+    DPRINT("ExAcquireSharedStarveExclusive(Resource 0x%p, Wait %d)\n",
+            Resource, Wait);
+    if (!Resource->ActiveCount)
+    {
+        /* Nobody owns it, so let's take control */
+        Resource->ActiveCount = 1;
+        Resource->OwnerThreads[1].OwnerThread = Thread;
+        Resource->OwnerThreads[1].OwnerCount = 1;
+
+        /* Release the lock and return */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        return TRUE;
+    }
 
-   DPRINT("ExAcquireResourceExclusiveLite(Resource 0x%p, Wait %d)\n",
-         Resource, Wait);
+    /* Check if it's exclusively owned */
+    if (IsOwnedExclusive(Resource))
+    {
+        /* Check if we own it */
+        if (Resource->OwnerThreads[0].OwnerThread == Thread)
+        {
+            /* Increase the owning count */
+            Resource->OwnerThreads[0].OwnerCount++;
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
 
-   ASSERT_IRQL_LESS(DISPATCH_LEVEL);
+        /* Find a free entry */
+        Owner = ExpFindFreeEntry(Resource, &OldIrql);
+        if (!Owner) goto TryAcquire;
 
-/* undefed for now, since cdfs must be fixed first */
-#if 0
-   /* At least regular kmode APC's must be disabled
-    * Note that this requirement is missing in old DDK's */
-   ASSERT(KeGetCurrentThread() == NULL || /* <-Early in the boot process the current thread is obseved to be NULL */
-          KeGetCurrentThread()->KernelApcDisable ||
-          KeGetCurrentIrql() == APC_LEVEL);
-#endif
+        /* If we got here, then we need to wait. Are we allowed? */
+        if (!Wait)
+        {
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+
+        /* Check if we have a shared waiters semaphore */
+        if (!Resource->SharedWaiters)
+        {
+            /* Allocate one and try again */
+            ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
+            goto TryAcquire;
+        }
+    }
+    else
+    {
+        /* Resource is shared, find who owns it */
+        Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+        if (!Owner) goto TryAcquire;
+
+        /* Is it us? */
+        if (Owner->OwnerThread == Thread)
+        {
+            /* Increase acquire count and return */
+            Owner->OwnerCount++;
+            ASSERT(Owner->OwnerCount != 0);
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+
+        /* Acquire it */
+        Owner->OwnerThread = Thread;
+        Owner->OwnerCount = 1;
+        Resource->ActiveCount++;
+
+        /* Release the lock and return */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        return TRUE;
+    }
+
+    /* If we got here, then we need to wait. Are we allowed? */
+    if (!Wait)
+    {
+        /* Release the lock and return */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        return TRUE;
+    }
 
-   KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
-   /* resource already locked */
-   if((Resource->Flag & ResourceOwnedExclusive)
-      && Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
-     {
-       /* it's ok : same lock for same thread */
-    Resource->OwnerThreads[0].OwnerCount++;
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
-       return(TRUE);
-     }
-
-   if (Resource->ActiveCount && !Wait)
-     {
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExAcquireResourceExclusiveLite() = FALSE\n");
-       return(FALSE);
-     }
-
-   /*
-    * This is slightly better than it looks because other exclusive
-    * threads who are waiting won't be woken up but there is a race
-    * with new threads trying to grab the resource so we must have
-    * the spinlock, still normally this loop will only be executed
-    * once
-    * NOTE: We might want to set a timeout to detect deadlock
-    * (10 minutes?)
-    */
-   while (Resource->ActiveCount)
-     {
-       Resource->NumberOfExclusiveWaiters++;
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       KeWaitForSingleObject(Resource->ExclusiveWaiters,
-                             Executive,
-                             KernelMode,
-                             FALSE,
-                             NULL);
-       KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-       Resource->NumberOfExclusiveWaiters--;
-     }
-   Resource->Flag |= ResourceOwnedExclusive;
-   Resource->ActiveCount = 1;
-   Resource->OwnerThreads[0].OwnerThread = ExGetCurrentResourceThread();
-   Resource->OwnerThreads[0].OwnerCount = 1;
-   KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-   DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
-   return(TRUE);
+    /* Now wait for the resource */
+    Owner->OwnerThread = Thread;
+    Owner->OwnerCount = 1;
+    Resource->NumberOfSharedWaiters++;
+
+    /* Release the lock and return */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    ExpWaitForResource(Resource, Resource->SharedWaiters);
+    return TRUE;
 }
 
-static BOOLEAN EiRemoveSharedOwner(PERESOURCE Resource,
-                                  ERESOURCE_THREAD ResourceThreadId)
-/*
- * FUNCTION: Removes the current thread from the shared owners of the resource
- * ARGUMENTS:
- *      Resource = Pointer to the resource for which the thread is to be
- *                 added
- * NOTE: Must be called with the resource spinlock held
- */
+/*++
+ * @name ExAcquireSharedWaitForExclusive
+ * @implemented NT4
+ *
+ *     The ExAcquireSharedWaitForExclusive routine acquires the given resource
+ *     for shared access if shared access can be granted and there are no
+ *     exclusive waiters.
+ *
+ * @param Resource
+ *        Pointer to the resource to acquire.
+ *
+ * @param Wait
+ *        Specifies the routine's behavior whenever the resource cannot be
+ *        acquired immediately.
+ *
+ * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
+ *         and exclusive access cannot be granted immediately.
+ *
+ * @remarks The caller can release the resource by calling either
+ *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
+ *
+ *          Normal kernel APC delivery must be disabled before calling this
+ *          routine. Disable normal kernel APC delivery by calling
+ *          KeEnterCriticalRegion. Delivery must remain disabled until the
+ *          resource is released, at which point it can be reenabled by calling
+ *          KeLeaveCriticalRegion.
+ *
+ *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
+ *          DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExAcquireSharedWaitForExclusive(PERESOURCE Resource,
+                                BOOLEAN Wait)
+{
+    KIRQL OldIrql;
+    ERESOURCE_THREAD Thread;
+    POWNER_ENTRY Owner;
+
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
+
+    /* Sanity check and validation */
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
+
+    /* Acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+    /* See if nobody owns us */
+TryAcquire:
+    DPRINT("ExAcquireSharedWaitForExclusive(Resource 0x%p, Wait %d)\n",
+            Resource, Wait);
+    if (!Resource->ActiveCount)
+    {
+        /* Nobody owns it, so let's take control */
+        Resource->ActiveCount = 1;
+        Resource->OwnerThreads[1].OwnerThread = Thread;
+        Resource->OwnerThreads[1].OwnerCount = 1;
+
+        /* Release the lock and return */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        return TRUE;
+    }
+
+    /* Check if it's exclusively owned */
+    if (IsOwnedExclusive(Resource))
+    {
+        /* Check if we own it */
+        if (Resource->OwnerThreads[0].OwnerThread == Thread)
+        {
+            /* Increase the owning count */
+            Resource->OwnerThreads[0].OwnerCount++;
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+        else
+        {
+            /* Find a free entry */
+            Owner = ExpFindFreeEntry(Resource, &OldIrql);
+            if (!Owner) goto TryAcquire;
+
+            /* If we got here, then we need to wait. Are we allowed? */
+            if (!Wait)
+            {
+                /* Release the lock and return */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                return TRUE;
+            }
+
+            /* Check if we have a shared waiters semaphore */
+            if (!Resource->SharedWaiters)
+            {
+                /* Allocate one and try again */
+                ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
+                goto TryAcquire;
+            }
+
+            /* Now take control of the resource */
+            Owner->OwnerThread = Thread;
+            Owner->OwnerCount = 1;
+            Resource->NumberOfSharedWaiters++;
+
+            /* Release the lock and wait for it to be ours */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            ExpWaitForResource(Resource, Resource->SharedWaiters);
+            return TRUE;
+        }
+    }
+    else
+    {
+        /* Try to find if there are exclusive waiters */
+        if (IsExclusiveWaiting(Resource))
+        {
+            /* We have to wait for the exclusive waiter to be done */
+            if (!Wait)
+            {
+                /* So bail out if we're not allowed */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                return TRUE;
+            }
+
+            /* Check if we have a shared waiters semaphore */
+            if (!Resource->SharedWaiters)
+            {
+                /* Allocate one and try again */
+                ExpAllocateSharedWaiterSemaphore(Resource, &OldIrql);
+                goto TryAcquire;
+            }
+
+            /* Now wait for the resource */
+            Resource->NumberOfSharedWaiters++;
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            ExpWaitForResource(Resource, Resource->SharedWaiters);
+
+            /* Get the lock back */
+            ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+            /* Find who owns it now */
+            Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+
+            /* Sanity checks */
+            ASSERT(IsOwnedExclusive(Resource) == FALSE);
+            ASSERT(Resource->ActiveCount > 0);
+            ASSERT(Owner->OwnerThread != Thread);
+
+            /* Take control */
+            Owner->OwnerThread = Thread;
+            Owner->OwnerCount = 1;
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+        else
+        {
+            /* Resource is shared, find who owns it */
+            Owner = ExpFindEntryForThread(Resource, Thread, &OldIrql);
+            if (!Owner) goto TryAcquire;
+
+            /* Is it us? */
+            if (Owner->OwnerThread == Thread)
+            {
+                /* Increase acquire count and return */
+                Owner->OwnerCount++;
+                ASSERT(Owner->OwnerCount != 0);
+
+                /* Release the lock and return */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                return TRUE;
+            }
+
+            /* No exclusive waiters, so acquire it */
+            Owner->OwnerThread = Thread;
+            Owner->OwnerCount = 1;
+            Resource->ActiveCount++;
+
+            /* Release the lock and return */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return TRUE;
+        }
+    }
+}
+
+/*++
+ * @name ExConvertExclusiveToSharedLite
+ * @implemented NT4
+ *
+ *     The ExConvertExclusiveToSharedLite routine converts an exclusively
+ *     acquired resource into a resource that can be acquired shared.
+ *
+ * @param Resource
+ *        Pointer to the resource to convert.
+ *
+ * @return None.
+ *
+ * @remarks Callers of ExConvertExclusiveToSharedLite must be running at IRQL <
+ *          DISPATCH_LEVEL.
+ *
+ *--*/
+VOID
+NTAPI
+ExConvertExclusiveToSharedLite(PERESOURCE Resource)
 {
-   ULONG i;
-
-   if (Resource->OwnerThreads[1].OwnerThread == ResourceThreadId)
-     {
-    Resource->OwnerThreads[1].OwnerCount--;
-    if (Resource->OwnerThreads[1].OwnerCount == 0)
-         {
-             Resource->ActiveCount--;
-            Resource->OwnerThreads[1].OwnerThread = 0;
-         }
-       return(TRUE);
-     }
-
-   if (Resource->OwnerThreads[1].OwnerThread)
-     {
-       /* Oh dear, the caller didn't own the resource after all */
-       return(FALSE);
-     }
-
-   for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
-     {
-       if (Resource->OwnerTable[i].OwnerThread == ResourceThreadId)
-         {
-         Resource->OwnerTable[i].OwnerCount--;
-         if (Resource->OwnerTable[i].OwnerCount == 0)
-              {
-                 Resource->ActiveCount--;
-                 Resource->OwnerTable[i].OwnerThread = 0;
-              }
-            return TRUE;
-         }
-     }
-   return(FALSE);
+    ULONG OldWaiters;
+    KIRQL OldIrql;
+    DPRINT("ExConvertExclusiveToSharedLite(Resource 0x%p)\n", Resource);
+
+    /* Lock the resource */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+    /* Sanity checks */
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
+    ASSERT(IsOwnedExclusive(Resource));
+    ASSERT(Resource->OwnerThreads[0].OwnerThread == (ERESOURCE_THREAD)PsGetCurrentThread());
+
+    /* Erase the exclusive flag */
+    Resource->Flag &= ~ResourceOwnedExclusive;
+
+    /* Check if we have shared waiters */
+    OldWaiters = Resource->NumberOfSharedWaiters;
+    if (OldWaiters)
+    {
+        /* Make the waiters active owners */
+        Resource->ActiveCount = Resource->ActiveCount + (USHORT)OldWaiters;
+        Resource->NumberOfSharedWaiters = 0;
+
+        /* Release lock and wake the waiters */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        KeReleaseSemaphore(Resource->SharedWaiters, 0, OldWaiters, FALSE);
+    }
+    else
+    {
+        /* Release lock */
+        ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    }
 }
 
-static BOOLEAN EiAddSharedOwner(PERESOURCE Resource)
-/*
- * FUNCTION: Adds the current thread to the shared owners of the resource
- * ARGUMENTS:
- *         Resource = Pointer to the resource for which the thread is to be
- *                    added
- * NOTE: Must be called with the resource spinlock held
- */
+/*++
+ * @name ExDeleteResourceLite
+ * @implemented NT4
+ *
+ *     The ExConvertExclusiveToSharedLite routine deletes a given resource
+ *     from the system\92s resource list.
+ *
+ * @param Resource
+ *        Pointer to the resource to delete.
+ *
+ * @return STATUS_SUCCESS if the resource was deleted.
+ *
+ * @remarks Callers of ExDeleteResourceLite must be running at IRQL <
+ *          DISPATCH_LEVEL.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+ExDeleteResourceLite(PERESOURCE Resource)
 {
-   ERESOURCE_THREAD CurrentThread = ExGetCurrentResourceThread();
-   POWNER_ENTRY freeEntry;
-   ULONG i = 0;
-
-   DPRINT("EiAddSharedOwner(Resource 0x%p)\n", Resource);
-
-   if (Resource->ActiveCount == 0)
-     {
-       /* no owner, it's easy */
-       Resource->OwnerThreads[1].OwnerThread = ExGetCurrentResourceThread();
-    Resource->OwnerThreads[1].OwnerCount = 1;
-       if (Resource->OwnerTable != NULL)
-         {
-            ExFreePool(Resource->OwnerTable);
-         }
-       Resource->OwnerTable = NULL;
-       Resource->ActiveCount = 1;
-       DPRINT("EiAddSharedOwner() = TRUE\n");
-       return(TRUE);
-     }
-
-   /*
-    * now, we must search if this thread has already acquired this resource
-    * then increase ownercount if found, else create new entry or reuse free
-    * entry
-    */
-   if (Resource->OwnerTable == NULL)
-     {
-       DPRINT("Creating owner table\n");
-
-       /* allocate ownertable,memset to 0, initialize first entry */
-       Resource->OwnerTable =
-         ExAllocatePoolWithTag(NonPagedPool, sizeof(OWNER_ENTRY)*3,
-                               TAG_OWNER_TABLE);
-       if (Resource->OwnerTable == NULL)
-         {
-            KEBUGCHECK(0);
-            return(FALSE);
-         }
-       memset(Resource->OwnerTable,0,sizeof(OWNER_ENTRY)*3);
-       memcpy(&Resource->OwnerTable[0], &Resource->OwnerThreads[1],
-              sizeof(OWNER_ENTRY));
-
-       Resource->OwnerThreads[1].OwnerThread = 0;
-    Resource->OwnerThreads[1].TableSize = 3;
-
-       Resource->OwnerTable[1].OwnerThread = CurrentThread;
-    Resource->OwnerTable[1].OwnerCount = 1;
-        Resource->ActiveCount++;
+    KIRQL OldIrql;
+    DPRINT("ExDeleteResourceLite(Resource 0x%p)\n", Resource);
 
-       return(TRUE);
-     }
-
-   DPRINT("Search free entries\n");
-
-   DPRINT("Number of entries %d\n",
-      Resource->OwnerThreads[1].TableSize);
-
-   freeEntry = NULL;
-   for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
-     {
-       if (Resource->OwnerTable[i].OwnerThread == CurrentThread)
-         {
-            DPRINT("Thread already owns resource\n");
-         Resource->OwnerTable[i].OwnerCount++;
-            return(TRUE);
-         }
-       if (Resource->OwnerTable[i].OwnerThread == 0)
-         {
-            freeEntry = &Resource->OwnerTable[i];
-            break;
-         }
-     }
-
-   DPRINT("Found free entry 0x%p\n", freeEntry);
-
-   if (!freeEntry)
-     {
-       DPRINT("Allocating new entry\n");
-
-       /* reallocate ownertable with one more entry */
-       freeEntry =
-         ExAllocatePoolWithTag(NonPagedPool,
-                               sizeof(OWNER_ENTRY)*
-                (Resource->OwnerThreads[1].TableSize+1),
-                               TAG_OWNER_TABLE);
-       if (freeEntry == NULL)
-         {
-            KEBUGCHECK(0);
-            return(FALSE);
-         }
-       memcpy(freeEntry,Resource->OwnerTable,
-           sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].TableSize));
-       ExFreePool(Resource->OwnerTable);
-       Resource->OwnerTable=freeEntry;
-    freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].TableSize];
-    Resource->OwnerThreads[1].TableSize++;
-     }
-   DPRINT("Creating entry\n");
-   freeEntry->OwnerThread=ExGetCurrentResourceThread();
-   freeEntry->OwnerCount=1;
-   Resource->ActiveCount++;
-   return(TRUE);
-}
+    /* Sanity checks */
+    ASSERT(IsSharedWaiting(Resource) == FALSE);
+    ASSERT(IsExclusiveWaiting(Resource) == FALSE);
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExAcquireResourceSharedLite (
-       PERESOURCE      Resource,
-       BOOLEAN         Wait
-       )
-/*
- * FUNCTION: Acquires the given resource for shared access by the calling
- *           thread
- * ARGUMENTS:
- *       Resource = Points to the resource to acquire
- *       Wait = Is set to TRUE if the caller should be put into wait state
- *              until the resource can be acquired if it cannot be acquired
- *              immediately
- * RETURNS: TRUE, if the resource is acquire
- *          FALSE otherwise
- */
-{
-   KIRQL oldIrql;
+    /* Lock the resource */
+    KeAcquireSpinLock(&ExpResourceSpinLock, &OldIrql);
 
-   DPRINT("ExAcquireResourceSharedLite(Resource 0x%p, Wait %d)\n",
-         Resource, Wait);
+    /* Remove the resource */
+    RemoveEntryList(&Resource->SystemResourcesList);
 
-   ASSERT_IRQL_LESS(DISPATCH_LEVEL);
+    /* Release the lock */
+    KeReleaseSpinLock(&ExpResourceSpinLock, OldIrql);
 
-/* undefed for now, since cdfs must be fixed first */
-#if 0
-   /* At least regular kmode APC's must be disabled
-    * Note that this requirement is missing in old DDK's
-    */
-   ASSERT(KeGetCurrentThread() == NULL || /* <-Early in the boot process the current thread is obseved to be NULL */
-          KeGetCurrentThread()->KernelApcDisable ||
-          KeGetCurrentIrql() == APC_LEVEL);
-#endif
+    /* Free every  structure */
+    if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
+    if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
+    if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
 
-   KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
-   /* first, resolve trivial cases */
-   if (Resource->ActiveCount == 0)
-     {
-       EiAddSharedOwner(Resource);
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
-       return(TRUE);
-     }
-
-   if ((Resource->Flag & ResourceOwnedExclusive)
-       && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
-     {
-       /* exclusive, but by same thread : it's ok */
-       /*
-        * NOTE: Is this correct? Seems the same as ExConvertExclusiveToShared
-        */
-    Resource->OwnerThreads[0].OwnerCount++;
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
-       return(TRUE);
-     }
-
-   if ((Resource->Flag & ResourceOwnedExclusive)
-       || Resource->NumberOfExclusiveWaiters)
-     {
-       /* exclusive by another thread , or thread waiting for exclusive */
-       if (!Wait)
-         {
-            KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-            DPRINT("ExAcquireResourceSharedLite() = FALSE\n");
-            return(FALSE);
-         }
-       else
-         {
-           Resource->NumberOfSharedWaiters++;
-           do
-           {
-              /* wait for the semaphore */
-              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-              KeWaitForSingleObject(Resource->SharedWaiters,0, KernelMode, FALSE, NULL);
-              KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-              /* the spin lock was released we must check again */
-           }
-           while ((Resource->Flag & ResourceOwnedExclusive)
-               || Resource->NumberOfExclusiveWaiters);
-           Resource->NumberOfSharedWaiters--;
-         }
-     }
-
-   EiAddSharedOwner(Resource);
-   KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-   DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
-   return(TRUE);
+    /* Return success */
+    return STATUS_SUCCESS;
 }
 
-/*
- * @implemented
- */
+/*++
+ * @name ExDisableResourceBoostLite
+ * @implemented NT4
+ *
+ *     The ExDisableResourceBoostLite routine disables thread boosting for
+ *     the given resource.
+ *
+ * @param Resource
+ *        Pointer to the resource whose thread boosting will be disabled.
+ *
+ * @return None.
+ *
+ * @remarks None.
+ *
+ *--*/
 VOID
-STDCALL
-ExConvertExclusiveToSharedLite (
-       PERESOURCE      Resource
-       )
-/*
- * FUNCTION: Converts a given resource from acquired for exclusive access
- *           to acquire for shared access
- * ARGUMENTS:
- *      Resource = Points to the resource for which the access should be
- *                 converted
- * NOTES: Caller must be running at IRQL < DISPATCH_LEVEL
- */
+NTAPI
+ExDisableResourceBoostLite(PERESOURCE Resource)
 {
-   ULONG oldWaiters;
-   KIRQL oldIrql;
-
-   DPRINT("ExConvertExclusiveToSharedLite(Resource 0x%p)\n", Resource);
-
-   KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
-   oldWaiters = Resource->NumberOfSharedWaiters;
-
-   if (!(Resource->Flag & ResourceOwnedExclusive))
-     {
-       /* Might not be what the caller expects, better bug check */
-       KEBUGCHECK(0);
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       return;
-     }
-
-   //transfer infos from entry 0 to entry 1 and erase entry 0
-   Resource->OwnerThreads[1].OwnerThread=Resource->OwnerThreads[0].OwnerThread;
-   Resource->OwnerThreads[1].OwnerCount=Resource->OwnerThreads[0].OwnerCount;
-   Resource->OwnerThreads[0].OwnerThread=0;
-   Resource->OwnerThreads[0].OwnerCount=0;
-   /* erase exclusive flag */
-   Resource->Flag &= (~ResourceOwnedExclusive);
-   /* if no shared waiters, that's all */
-   if (!oldWaiters)
-     {
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       return;
-     }
-   /* else, awake the waiters */
-   KeReleaseSemaphore(Resource->SharedWaiters,0,oldWaiters,0);
-   KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-   DPRINT("ExConvertExclusiveToSharedLite() finished\n");
-}
+    KIRQL OldIrql;
 
-/*
- * @implemented
- */
-VOID
-STDCALL
-ExDisableResourceBoostLite (
-       PERESOURCE      Resource
-       )
-{
-   Resource->Flag |= ResourceDisableBoost;
+    /* Sanity check */
+    ExpVerifyResource(Resource);
+
+    /* Lock the resource */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+    /* Remove the flag */
+    Resource->Flag |= ResourceHasDisabledPriorityBoost;
+
+    /* Release the lock */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
 }
 
-/*
- * @implemented
- */
+/*++
+ * @name ExGetExclusiveWaiterCount
+ * @implemented NT4
+ *
+ *     The ExGetExclusiveWaiterCount routine returns the number of exclusive
+ *     waiters for the given resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to check.
+ *
+ * @return The number of exclusive waiters.
+ *
+ * @remarks None.
+ *
+ *--*/
 ULONG
-STDCALL
-ExGetExclusiveWaiterCount (
-       PERESOURCE      Resource
-       )
+NTAPI
+ExGetExclusiveWaiterCount(PERESOURCE Resource)
 {
-  return(Resource->NumberOfExclusiveWaiters);
+    /* Return the count */
+    return Resource->NumberOfExclusiveWaiters;
 }
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExAcquireSharedStarveExclusive (
-       PERESOURCE      Resource,
-       BOOLEAN         Wait
-       )
-/*
- * FUNCTION: Acquires a given resource for shared access without waiting
- *           for any pending attempts to acquire exclusive access to the
- *           same resource
- * ARGUMENTS:
- *       Resource = Points to the resource to be acquired for shared access
- *       Wait = Is set to TRUE if the caller will wait until the resource
- *              becomes available when access can't be granted immediately
- * RETURNS: TRUE if the requested access is granted. The routine returns
- *          FALSE if the input Wait is FALSE and shared access can't be
- *          granted immediately
- */
+/*++
+ * @name ExGetSharedWaiterCount
+ * @implemented NT4
+ *
+ *     The ExGetSharedWaiterCount routine returns the number of shared
+ *     waiters for the given resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to check.
+ *
+ * @return The number of shared waiters.
+ *
+ * @remarks None.
+ *
+ *--*/
+ULONG
+NTAPI
+ExGetSharedWaiterCount(PERESOURCE Resource)
 {
-   KIRQL oldIrql;
-
-   DPRINT("ExAcquireSharedStarveExclusive(Resource 0x%p, Wait %d)\n",
-         Resource, Wait);
-
-   KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
-   /* no owner, it's easy */
-   if (Resource->ActiveCount == 0)
-     {
-       Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread();
-    Resource->OwnerThreads[1].OwnerCount=1;
-       Resource->ActiveCount=1;
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
-       return(TRUE);
-     }
-
-   if ((Resource->Flag & ResourceOwnedExclusive)
-       &&  Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
-     {
-       /* exclusive, but by same thread : it's ok */
-    Resource->OwnerThreads[0].OwnerCount++;
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
-       return(TRUE);
-     }
-
-   if (Resource->Flag & ResourceOwnedExclusive)
-     {
-       /* exclusive by another thread */
-       if (!Wait)
-         {
-            KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-            DPRINT("ExAcquireSharedStarveExclusive() = FALSE\n");
-            return(FALSE);
-         }
-       else
-         {
-            Resource->NumberOfSharedWaiters++;
-            /* wait for the semaphore */
-            KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-            KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0);
-            KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-            Resource->NumberOfSharedWaiters--;
-         }
-     }
-   EiAddSharedOwner(Resource);
-   KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-   DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
-   return(TRUE);
+    /* Return the count */
+    return Resource->NumberOfSharedWaiters;
 }
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExAcquireSharedWaitForExclusive (
-       PERESOURCE      Resource,
-       BOOLEAN         Wait
-       )
+/*++
+ * @name ExInitializeResourceLite
+ * @implemented NT4
+ *
+ *     The ExInitializeResourceLite routine initializes a resource variable.
+ *
+ * @param Resource
+ *        Pointer to the resource to check.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks The storage for ERESOURCE must not be allocated from paged pool.
+ *
+ *          The storage must be 8-byte aligned.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+ExInitializeResourceLite(PERESOURCE Resource)
 {
-  return(ExAcquireResourceSharedLite(Resource,Wait));
-}
+    DPRINT("ExInitializeResourceLite(Resource 0x%p)\n", Resource);
 
+    /* Clear the structure */
+    RtlZeroMemory(Resource, sizeof(ERESOURCE));
 
-#ifdef ExDeleteResource
-#undef ExDeleteResource
-#endif
+    /* Initialize the lock */
+    KeInitializeSpinLock(&Resource->SpinLock);
 
+    /* Add it into the system list */
+    ExInterlockedInsertTailList(&ExpSystemResourcesList,
+                                &Resource->SystemResourcesList,
+                                &ExpResourceSpinLock);
 
-/*
- * @implemented
- */
-NTSTATUS
-STDCALL
-ExDeleteResource (
-       PERESOURCE      Resource
-       )
-{
-   return(ExDeleteResourceLite(Resource));
+    /* Return success */
+    return STATUS_SUCCESS;
 }
 
-/*
- * @implemented
- */
-NTSTATUS
-STDCALL
-ExDeleteResourceLite (
-       PERESOURCE      Resource
-       )
+/*++
+ * @name ExIsResourceAcquiredExclusiveLite
+ * @implemented NT4
+ *
+ *     The ExIsResourceAcquiredExclusiveLite routine returns whether the
+ *     current thread has exclusive access to a given resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to check.
+ *
+ * @return TRUE if the caller already has exclusive access to the given resource.
+ *
+ * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
+ *          IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExIsResourceAcquiredExclusiveLite(PERESOURCE Resource)
 {
-   DPRINT("ExDeleteResourceLite(Resource 0x%p)\n", Resource);
-   if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
-   if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
-   if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
-   return(STATUS_SUCCESS);
+    ERESOURCE_THREAD Thread = ExGetCurrentResourceThread();
+    BOOLEAN IsAcquired = FALSE;
+
+    /* Sanity check */
+    ExpVerifyResource(Resource);
+
+    /* Check if it's exclusively acquired */
+    if ((IsOwnedExclusive(Resource)) &&
+        (Resource->OwnerThreads[0].OwnerThread == Thread))
+    {
+        /* It is acquired */
+        IsAcquired = TRUE;
+    }
+
+    /* Return if it's acquired */
+    return IsAcquired;
 }
 
-/*
- * @implemented
- */
+/*++
+ * @name ExIsResourceAcquiredSharedLite
+ * @implemented NT4
+ *
+ *     The ExIsResourceAcquiredSharedLite routine returns whether the
+ *     current thread has has access (either shared or exclusive) to a
+ *     given resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to check.
+ *
+ * @return Number of times the caller has acquired the given resource for
+ *         shared or exclusive access.
+ *
+ * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
+ *          IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
 ULONG
-STDCALL
-ExGetSharedWaiterCount (
-       PERESOURCE      Resource
-       )
+NTAPI
+ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
 {
-   return(Resource->NumberOfSharedWaiters);
-}
+    ERESOURCE_THREAD Thread;
+    ULONG i, Size;
+    ULONG Count = 0;
+    KIRQL OldIrql;
+    POWNER_ENTRY Owner;
 
+    /* Sanity check */
+    ExpVerifyResource(Resource);
 
-#ifdef ExInitializeResource
-#undef ExInitializeResource
-#endif
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
 
-/*
- * @implemented
- */
-NTSTATUS
-STDCALL
-ExInitializeResource (
-       PERESOURCE      Resource
-       )
-{
-   return(ExInitializeResourceLite(Resource));
+    /* Check if we are in the thread list */
+    if (Resource->OwnerThreads[0].OwnerThread == Thread)
+    {
+        /* Found it, return count */
+        Count = Resource->OwnerThreads[0].OwnerCount;
+    }
+    else if (Resource->OwnerThreads[1].OwnerThread == Thread)
+    {
+        /* Found it on the second list, return count */
+        Count = Resource->OwnerThreads[1].OwnerCount;
+    }
+    else
+    {
+        /* Not in the list, do a full table look up */
+        Owner = Resource->OwnerTable;
+        if (Owner)
+        {
+            /* Lock the resource */
+            ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+            /* Get the resource index */
+            i = ((PKTHREAD)Thread)->ResourceIndex;
+            Size = Owner->TableSize;
+
+            /* Check if the index is valid and check if we don't match */
+            if ((i >= Size) || (Owner[i].OwnerThread != Thread))
+            {
+                /* Sh*t! We need to do a full search */
+                for (i = 1; i < Size; i++)
+                {
+                    /* Move to next owner */
+                    Owner++;
+
+                    /* Try to find a match */
+                    if (Owner->OwnerThread == Thread)
+                    {
+                        /* Finally! */
+                        Count = Owner->OwnerCount;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                /* We found the match directlry */
+                Count = Owner[i].OwnerCount;
+            }
+
+            /* Release the lock */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+        }
+    }
+
+    /* Return count */
+    return Count;
 }
 
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-ExInitializeResourceLite (PERESOURCE   Resource)
+/*++
+ * @name ExReinitializeResourceLite
+ * @implemented NT4
+ *
+ *     The ExReinitializeResourceLite routine routine reinitializes
+ *     an existing resource variable.
+ *
+ * @param Resource
+ *        Pointer to the resource to be reinitialized.
+ *
+ * @return STATUS_SUCCESS.
+ *
+ * @remarks With a single call to ExReinitializeResource, a driver writer can
+ *          replace three calls: one to ExDeleteResourceLite, another to
+ *          ExAllocatePool, and a third to ExInitializeResourceLite. As
+ *          contention for a resource variable increases, memory is dynamically
+ *          allocated and attached to the resource in order to track this
+ *          contention. As an optimization, ExReinitializeResourceLite retains
+ *          and zeroes this previously allocated memory.
+ *
+ *          Callers of ExReinitializeResourceLite must be running at
+ *          IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
+NTSTATUS
+NTAPI
+ExReinitializeResourceLite(PERESOURCE Resource)
 {
-   DPRINT("ExInitializeResourceLite(Resource 0x%p)\n", Resource);
-   memset(Resource,0,sizeof(ERESOURCE));
-   Resource->NumberOfSharedWaiters = 0;
-   Resource->NumberOfExclusiveWaiters = 0;
-   KeInitializeSpinLock(&Resource->SpinLock);
-   Resource->Flag = 0;
-   Resource->ExclusiveWaiters =
-     ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_EXCLUSIVE_LOCK);
-   KeInitializeEvent(Resource->ExclusiveWaiters,
-                    SynchronizationEvent,
-                    FALSE);
-   Resource->SharedWaiters =
-     ExAllocatePoolWithTag(NonPagedPool ,sizeof(KSEMAPHORE), TAG_SHARED_SEM);
-   KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
-   Resource->ActiveCount = 0;
-   return(0);
+    PKEVENT Event;
+    PKSEMAPHORE Semaphore;
+    ULONG i, Size;
+    POWNER_ENTRY Owner;
+
+    /* Get the owner table */
+    Owner = Resource->OwnerTable;
+    if (Owner)
+    {
+        /* Get the size and loop it */
+        Size = Owner->TableSize;
+        for (i = 0; i < Size; i++)
+        {
+            /* Zero the table */
+            Owner[i].OwnerThread = 0;
+            Owner[i].OwnerCount = 0;
+        }
+    }
+
+    /* Zero the flags and count */
+    Resource->Flag = 0;
+    Resource->ActiveCount = 0;
+
+    /* Reset the semaphore */
+    Semaphore = Resource->SharedWaiters;
+    if (Semaphore) KeInitializeSemaphore(Semaphore, 0, MAXLONG);
+
+    /* Reset the event */
+    Event = Resource->ExclusiveWaiters;
+    if (Event) KeInitializeEvent(Event, SynchronizationEvent, FALSE);
+
+    /* Clear the resource data */
+    Resource->OwnerThreads[0].OwnerThread = 0;
+    Resource->OwnerThreads[1].OwnerThread = 0;
+    Resource->OwnerThreads[0].OwnerCount = 0;
+    Resource->OwnerThreads[1].OwnerCount = 0;
+    Resource->ContentionCount = 0;
+    Resource->NumberOfSharedWaiters = 0;
+    Resource->NumberOfExclusiveWaiters = 0;
+
+    /* Reset the spinlock */
+    KeInitializeSpinLock(&Resource->SpinLock);
+    return STATUS_SUCCESS;
 }
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-ExIsResourceAcquiredExclusiveLite (
-       PERESOURCE      Resource
-       )
-/*
- * FUNCTION: Returns whether the current thread has exclusive access to
- * a given resource
- * ARGUMENTS:
- *        Resource = Points to the resource to be queried
- * RETURNS: TRUE if the caller has exclusive access to the resource,
- *          FALSE otherwise
- */
+/*++
+ * @name ExReleaseResourceLite
+ * @implemented NT4
+ *
+ *     The ExReleaseResourceLite routine routine releases
+ *     a specified executive resource owned by the current thread.
+ *
+ * @param Resource
+ *        Pointer to the resource to be released.
+ *
+ * @return None.
+ *
+ * @remarks Callers of ExReleaseResourceLite must be running at
+ *          IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
+VOID
+FASTCALL
+ExReleaseResourceLite(PERESOURCE Resource)
 {
-   return((Resource->Flag & ResourceOwnedExclusive)
-         && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
-}
+    ERESOURCE_THREAD Thread;
+    ULONG Count, i;
+    KIRQL OldIrql;
+    POWNER_ENTRY Owner, Limit;
+    DPRINT("ExReleaseResourceLite: %p\n", Resource);
+
+    /* Sanity check */
+    ExpVerifyResource(Resource);
+
+    /* Get the thread and lock the resource */
+    Thread = ExGetCurrentResourceThread();
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+    ExpCheckForApcsDisabled(TRUE, Resource, (PETHREAD)Thread);
+
+    /* Check if it's exclusively owned */
+    if (IsOwnedExclusive(Resource))
+    {
+        /* Decrement owner count and check if we're done */
+        ASSERT(Resource->OwnerThreads[0].OwnerCount > 0);
+        if (--Resource->OwnerThreads[0].OwnerCount)
+        {
+            /* Done, release lock! */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return;
+        }
 
+        /* Clear the owner */
+        Resource->OwnerThreads[0].OwnerThread = 0;
+
+        /* See if the resource isn't being owned anymore */
+        ASSERT(Resource->ActiveCount > 0);
+        if (!(--Resource->ActiveCount))
+        {
+            /* Check if there are shared waiters */
+            if (IsSharedWaiting(Resource))
+            {
+                /* Remove the exclusive flag */
+                Resource->Flag &= ~ResourceOwnedExclusive;
+
+                /* Give ownage to another thread */
+                Count = Resource->NumberOfSharedWaiters;
+                Resource->ActiveCount = (USHORT)Count;
+                Resource->NumberOfSharedWaiters = 0;
+
+                /* Release lock and let someone else have it */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                KeReleaseSemaphore(Resource->SharedWaiters, 0, Count, FALSE);
+                return;
+            }
+            else if (IsExclusiveWaiting(Resource))
+            {
+                /* Give exclusive access */
+                Resource->OwnerThreads[0].OwnerThread = 1;
+                Resource->OwnerThreads[0].OwnerCount = 1;
+                Resource->ActiveCount = 1;
+                Resource->NumberOfExclusiveWaiters--;
+
+                /* Release the lock and give it away */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                KeSetEventBoostPriority(Resource->ExclusiveWaiters,
+                                        (PKTHREAD*)
+                                        &Resource->OwnerThreads[0].OwnerThread);
+                return;
+            }
 
+            /* Remove the exclusive flag */
+            Resource->Flag &= ~ResourceOwnedExclusive;
+        }
+    }
+    else
+    {
+        /* Check if we are in the thread list */
+        if (Resource->OwnerThreads[1].OwnerThread == Thread)
+        {
+            /* Found it, get owner */
+            Owner = &Resource->OwnerThreads[1];
+        }
+        else if (Resource->OwnerThreads[0].OwnerThread == Thread)
+        {
+            /* Found it on the second list, get owner */
+            Owner = &Resource->OwnerThreads[0];
+        }
+        else
+        {
+            /* Not in the list, do a full table look up */
+            i = ((PKTHREAD)Thread)->ResourceIndex;
+            Owner = Resource->OwnerTable;
+            if (!Owner)
+            {
+                /* Nobody owns us, bugcheck! */
+                KEBUGCHECKEX(RESOURCE_NOT_OWNED,
+                             (ULONG_PTR)Resource,
+                             Thread,
+                             (ULONG_PTR)Resource->OwnerTable,
+                             (ULONG_PTR)2);
+            }
 
-#ifdef ExIsResourceAcquiredSharedLite
-#undef ExIsResourceAcquiredSharedLite
-#endif
+            /* Check if we're out of the size and don't match */
+            if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread))
+            {
+                /* Get the last entry */
+                Limit = &Owner[Owner->TableSize];
+                for (;;)
+                {
+                    /* Move to the next entry */
+                    Owner++;
+
+                    /* Check if we don't match */
+                    if (Owner >= Limit)
+                    {
+                        /* Nobody owns us, bugcheck! */
+                        KEBUGCHECKEX(RESOURCE_NOT_OWNED,
+                                     (ULONG_PTR)Resource,
+                                     Thread,
+                                     (ULONG_PTR)Resource->OwnerTable,
+                                     2);
+                    }
+
+                    /* Check for a match */
+                    if (Owner->OwnerThread == Thread) break;
+                }
+            }
+            else
+            {
+                /* Get the entry directly */
+                Owner = &Owner[i];
+            }
+        }
 
+        /* Sanity checks */
+        ASSERT(Owner->OwnerThread == Thread);
+        ASSERT(Owner->OwnerCount > 0);
 
-/*
- * @implemented
- */
+        /* Check if we are the last owner */
+        if (--Owner->OwnerCount)
+        {
+            /* Release lock */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return;
+        }
 
+        /* Clear owner */
+        Owner->OwnerThread = 0;
+
+        /* See if the resource isn't being owned anymore */
+        ASSERT(Resource->ActiveCount > 0);
+        if (!(--Resource->ActiveCount))
+        {
+            /* Check if there's an exclusive waiter */
+            if (IsExclusiveWaiting(Resource))
+            {
+                /* Give exclusive access */
+                Resource->Flag |= ResourceOwnedExclusive;
+                Resource->OwnerThreads[0].OwnerThread = 1;
+                Resource->OwnerThreads[0].OwnerCount = 1;
+                Resource->ActiveCount = 1;
+                Resource->NumberOfExclusiveWaiters--;
+
+                /* Release the lock and give it away */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                KeSetEventBoostPriority(Resource->ExclusiveWaiters,
+                                        (PKTHREAD*)
+                                        &Resource->OwnerThreads[0].OwnerThread);
+                return;
+            }
+        }
+    }
 
-//NTOSAPI
-//DDKAPI
-USHORT STDCALL
-ExIsResourceAcquiredSharedLite(
-  IN PERESOURCE  Resource)
-/*
- * FUNCTION: Returns whether the current thread has shared access to a given
- *           resource
- * ARGUMENTS:
- *      Resource = Points to the resource to be queried
- * RETURNS: The number of times the caller has acquired shared access to the
- *          given resource
- */
-{
-   ULONG i;
-   if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
-     {
-    return (USHORT)(Resource->OwnerThreads[0].OwnerCount);
-     }
-   if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
-     {
-    return (USHORT)(Resource->OwnerThreads[1].OwnerCount);
-     }
-   if (!Resource->OwnerThreads[1].TableSize)
-     {
-       return(0);
-     }
-   for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
-     {
-       if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
-         {
-         return (USHORT)Resource->OwnerTable[i].OwnerCount;
-         }
-     }
-   return(0);
+    /* Release lock */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    return;
 }
 
-/*
- * @implemented
- */
+/*++
+ * @name ExReleaseResourceForThreadLite
+ * @implemented NT4
+ *
+ *     The ExReleaseResourceForThreadLite routine routine releases
+ *     the input resource of the indicated thread.
+ *
+ * @param Resource
+ *        Pointer to the resource to be released.
+ *
+ * @param Thread
+ *        Identifies the thread that originally acquired the resource.
+  *
+ * @return None.
+ *
+ * @remarks Callers of ExReleaseResourceForThreadLite must be running at
+ *          IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
 VOID
-STDCALL
-ExReinitializeResourceLite (
-       PERESOURCE      Resource
-       )
+NTAPI
+ExReleaseResourceForThreadLite(PERESOURCE Resource,
+                               ERESOURCE_THREAD Thread)
 {
-   Resource->NumberOfSharedWaiters = 0;
-   Resource->NumberOfExclusiveWaiters = 0;
-   KeInitializeSpinLock(&Resource->SpinLock);
-   Resource->Flag=0;
-   KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
-                    FALSE);
-   KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
-   Resource->ActiveCount = 0;
-   if (Resource->OwnerTable)
-     {
-       ExFreePool(Resource->OwnerTable);
-     }
-   Resource->OwnerThreads[0].OwnerThread=0;
-   Resource->OwnerThreads[0].OwnerCount=0;
-   Resource->OwnerThreads[1].OwnerThread=0;
-   Resource->OwnerThreads[1].OwnerCount=0;
-}
+    ULONG i;
+    ULONG Count;
+    KIRQL OldIrql;
+    POWNER_ENTRY Owner;
+    ASSERT(Thread != 0);
+    DPRINT("ExReleaseResourceForThreadLite: %p\n", Resource);
+
+    /* Get the thread and lock the resource */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+    /* Sanity check */
+    ExpVerifyResource(Resource);
+
+    /* Check if it's exclusively owned */
+    if (IsOwnedExclusive(Resource))
+    {
+        /* Decrement owner count and check if we're done */
+        ASSERT(Resource->OwnerThreads[0].OwnerThread == Thread);
+        ASSERT(Resource->OwnerThreads[0].OwnerCount > 0);
+        if (--Resource->OwnerThreads[0].OwnerCount)
+        {
+            /* Done, release lock! */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return;
+        }
 
-/*
- * @implemented
- */
-VOID
-FASTCALL
-ExReleaseResourceLite (
-       PERESOURCE      Resource
-       )
-{
-  ExReleaseResourceForThreadLite(Resource,
-                                       ExGetCurrentResourceThread());
-}
+        /* Clear the owner */
+        Resource->OwnerThreads[0].OwnerThread = 0;
+
+        /* See if the resource isn't being owned anymore */
+        ASSERT(Resource->ActiveCount > 0);
+        if (!(--Resource->ActiveCount))
+        {
+            /* Check if there are shared waiters */
+            if (IsSharedWaiting(Resource))
+            {
+                /* Remove the exclusive flag */
+                Resource->Flag &= ~ResourceOwnedExclusive;
+
+                /* Give ownage to another thread */
+                Count = Resource->NumberOfSharedWaiters;
+                Resource->ActiveCount = (USHORT)Count;
+                Resource->NumberOfSharedWaiters = 0;
+
+                /* Release lock and let someone else have it */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                KeReleaseSemaphore(Resource->SharedWaiters, 0, Count, FALSE);
+                return;
+            }
+            else if (IsExclusiveWaiting(Resource))
+            {
+                /* Give exclusive access */
+                Resource->OwnerThreads[0].OwnerThread = 1;
+                Resource->OwnerThreads[0].OwnerCount = 1;
+                Resource->ActiveCount = 1;
+                Resource->NumberOfExclusiveWaiters--;
+
+                /* Release the lock and give it away */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                KeSetEventBoostPriority(Resource->ExclusiveWaiters,
+                                        (PKTHREAD*)
+                                        &Resource->OwnerThreads[0].OwnerThread);
+                return;
+            }
 
+            /* Remove the exclusive flag */
+            Resource->Flag &= ~ResourceOwnedExclusive;
+        }
+    }
+    else
+    {
+        /* Check if we are in the thread list */
+        if (Resource->OwnerThreads[0].OwnerThread == Thread)
+        {
+            /* Found it, get owner */
+            Owner = &Resource->OwnerThreads[0];
+        }
+        else if (Resource->OwnerThreads[1].OwnerThread == Thread)
+        {
+            /* Found it on the second list, get owner */
+            Owner = &Resource->OwnerThreads[1];
+        }
+        else
+        {
+            /* Assume no valid index */
+            i = 1;
+
+            /* If we got a valid pointer, try to get the resource index */
+            if (!((ULONG)Thread & 3)) i = ((PKTHREAD)Thread)->ResourceIndex;
+
+            /* Do a table lookup */
+            Owner = Resource->OwnerTable;
+            ASSERT(Owner != NULL);
+
+            /* Check if we're out of the size and don't match */
+            if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread))
+            {
+                /* Get the last entry */
+                for (;;)
+                {
+                    /* Move to the next entry */
+                    Owner++;
+
+                    /* Check for a match */
+                    if (Owner->OwnerThread == Thread) break;
+                }
+            }
+            else
+            {
+                /* Get the entry directly */
+                Owner = &Owner[i];
+            }
+        }
 
+        /* Sanity checks */
+        ASSERT(Owner->OwnerThread == Thread);
+        ASSERT(Owner->OwnerCount > 0);
 
-#ifdef ExReleaseResourceForThread
-#undef ExReleaseResourceForThread
-#endif
+        /* Check if we are the last owner */
+        if (!(--Owner->OwnerCount))
+        {
+            /* Release lock */
+            ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+            return;
+        }
 
+        /* Clear owner */
+        Owner->OwnerThread = 0;
+
+        /* See if the resource isn't being owned anymore */
+        ASSERT(Resource->ActiveCount > 0);
+        if (!(--Resource->ActiveCount))
+        {
+            /* Check if there's an exclusive waiter */
+            if (IsExclusiveWaiting(Resource))
+            {
+                /* Give exclusive access */
+                Resource->OwnerThreads[0].OwnerThread = 1;
+                Resource->OwnerThreads[0].OwnerCount = 1;
+                Resource->ActiveCount = 1;
+                Resource->NumberOfExclusiveWaiters--;
+
+                /* Release the lock and give it away */
+                ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+                KeSetEventBoostPriority(Resource->ExclusiveWaiters,
+                                        (PKTHREAD*)
+                                        &Resource->OwnerThreads[0].OwnerThread);
+                return;
+            }
+        }
+    }
 
-/*
- * @implemented
- */
-VOID
-STDCALL
-ExReleaseResourceForThread (
-       PERESOURCE              Resource,
-       ERESOURCE_THREAD        ResourceThreadId
-       )
-{
-  ExReleaseResourceForThreadLite(Resource,ResourceThreadId);
+    /* Release lock */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    return;
 }
 
-
-/*
- * @implemented
- */
+/*++
+ * @name ExSetResourceOwnerPointer
+ * @implemented NT4
+ *
+ *     The ExSetResourceOwnerPointer routine routine sets the owner thread
+ *     thread pointer for an executive resource.
+ *
+ * @param Resource
+ *        Pointer to the resource whose owner to change.
+ *
+ * @param OwnerPointer
+ *        Pointer to an owner thread pointer of type ERESOURCE_THREAD.
+  *
+ * @return None.
+ *
+ * @remarks ExSetResourceOwnerPointer, used in conjunction with
+ *          ExReleaseResourceForThreadLite, provides a means for one thread
+ *          (acting as an resource manager thread) to acquire and release
+ *          resources for use by another thread (acting as a resource user
+ *          thread).
+ *
+ *          After calling ExSetResourceOwnerPointer for a specific resource,
+ *          the only other routine that can be called for that resource is
+ *          ExReleaseResourceForThreadLite.
+ *
+ *          Callers of ExSetResourceOwnerPointer must be running at
+ *          IRQL <= DISPATCH_LEVEL.
+ *
+ *--*/
 VOID
-STDCALL
-ExReleaseResourceForThreadLite (
-       PERESOURCE              Resource,
-       ERESOURCE_THREAD        ResourceThreadId
-       )
-/*
- * FUNCTION: Releases a resource for the given thread
- * ARGUMENTS:
- *         Resource = Points to the release to release
- *         ResourceThreadId = Identifies the thread that originally acquired
- *                            the resource
- * NOTES: Must be running at IRQL < DISPATCH_LEVEL
- * BUG: We don't support starving exclusive waiters
- */
+NTAPI
+ExSetResourceOwnerPointer(IN PERESOURCE Resource,
+                          IN PVOID OwnerPointer)
 {
-   KIRQL oldIrql;
-
-   DPRINT("ExReleaseResourceForThreadLite(Resource 0x%p, ResourceThreadId 0x%p)\n",
-         Resource, ResourceThreadId);
-
-   ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
-
-   KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
-
-   if (Resource->Flag & ResourceOwnedExclusive)
-     {
-       DPRINT("Releasing from exclusive access\n");
-
-    Resource->OwnerThreads[0].OwnerCount--;
-    if (Resource->OwnerThreads[0].OwnerCount > 0)
-         {
-            KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-            DPRINT("ExReleaseResourceForThreadLite() finished\n");
-            return;
-         }
-
-       Resource->OwnerThreads[0].OwnerThread = 0;
-       Resource->ActiveCount--;
-       Resource->Flag &=(~ResourceOwnedExclusive);
-       ASSERT(Resource->ActiveCount == 0);
-       DPRINT("Resource->NumberOfExclusiveWaiters %d\n",
-              Resource->NumberOfExclusiveWaiters);
-       if (Resource->NumberOfExclusiveWaiters)
-         {
-            /* get resource to first exclusive waiter */
-            KeSetEvent(Resource->ExclusiveWaiters,
-                       IO_NO_INCREMENT,
-                       FALSE);
-            KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-            DPRINT("ExReleaseResourceForThreadLite() finished\n");
-            return;
-         }
-       DPRINT("Resource->NumberOfSharedWaiters %d\n",
-              Resource->NumberOfSharedWaiters);
-       if (Resource->NumberOfSharedWaiters)
-         {
-            DPRINT("Releasing semaphore\n");
-            KeReleaseSemaphore(Resource->SharedWaiters,
-                               IO_NO_INCREMENT,
-                               Resource->NumberOfSharedWaiters,
-                               FALSE);
-         }
-       KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-       DPRINT("ExReleaseResourceForThreadLite() finished\n");
-       return;
-     }
-
-   EiRemoveSharedOwner(Resource, ResourceThreadId);
-
-   if (Resource->ActiveCount == 0)
-     {
-       if (Resource->NumberOfExclusiveWaiters)
-         {
-            /* get resource to first exclusive waiter */
-            KeSetEvent(Resource->ExclusiveWaiters,
-                       IO_NO_INCREMENT,
-                       FALSE);
-         }
-     }
-
-   KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
-   DPRINT("ExReleaseResourceForThreadLite() finished\n");
-}
+    ERESOURCE_THREAD Thread;
+    KIRQL OldIrql;
+    POWNER_ENTRY Owner, ThisOwner;
 
+    /* Sanity check */
+    ASSERT((OwnerPointer != 0) && (((ULONG_PTR)OwnerPointer & 3) == 3));
 
-/*
- * @implemented
- */
-VOID
-STDCALL
-ExSetResourceOwnerPointer (
-       IN      PERESOURCE      Resource,
-       IN      PVOID           OwnerPointer
-       )
-{
-    PKTHREAD CurrentThread;
-    KIRQL OldIrql;
-    POWNER_ENTRY OwnerEntry;
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
 
-    CurrentThread = KeGetCurrentThread();
+    /* Sanity check */
+    ExpVerifyResource(Resource);
 
     /* Lock the resource */
-    KeAcquireSpinLock(&Resource->SpinLock, &OldIrql);
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
 
     /* Check if it's exclusive */
-    if (Resource->Flag & ResourceOwnedExclusive) {
-
+    if (IsOwnedExclusive(Resource))
+    {
         /* If it's exclusive, set the first entry no matter what */
+        ASSERT(Resource->OwnerThreads[0].OwnerThread == Thread);
+        ASSERT(Resource->OwnerThreads[0].OwnerCount > 0);
         Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer;
+    }
+    else
+    {
+        /* Set the thread in both entries */
+        ThisOwner = ExpFindEntryForThread(Resource,
+                                         (ERESOURCE_THREAD)OwnerPointer,
+                                         0);
+        Owner = ExpFindEntryForThread(Resource, Thread, 0);
+        if (!Owner)
+        {
+            /* Nobody owns it, crash */
+            KEBUGCHECKEX(RESOURCE_NOT_OWNED,
+                         (ULONG_PTR)Resource,
+                         Thread,
+                         (ULONG_PTR)Resource->OwnerTable,
+                         3);
+        }
 
-    } else {
-
-        /* Check both entries and see which one matches the current thread */
-        if (Resource->OwnerThreads[0].OwnerThread == (ULONG_PTR)CurrentThread) {
-
-            Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer;
-
-        } else if (Resource->OwnerThreads[1].OwnerThread == (ULONG_PTR)CurrentThread) {
-
-            Resource->OwnerThreads[1].OwnerThread = (ULONG_PTR)OwnerPointer;
-
-        } else { /* None of the entries match, so we need to do a lookup */
+        /* Set if we are the owner */
+        if (ThisOwner)
+        {
+            /* Update data */
+            ThisOwner->OwnerCount += Owner->OwnerCount;
+            Owner->OwnerCount = 0;
+            Owner->OwnerThread = 0;
+            ASSERT(Resource->ActiveCount >= 2);
+            Resource->ActiveCount--;
+        }
+    }
 
-            /* Get the first Entry */
-            OwnerEntry = Resource->OwnerTable;
+    /* Release the resource */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+}
 
-            /* Check if the Current Thread is in the Resource Table Entry */
-            if ((CurrentThread->ResourceIndex >= OwnerEntry->TableSize) ||
-                (OwnerEntry[CurrentThread->ResourceIndex].OwnerThread != (ULONG_PTR)CurrentThread)) {
+/*++
+ * @name ExTryToAcquireResourceExclusiveLite
+ * @implemented NT4
+ *
+ *     The ExTryToAcquireResourceExclusiveLite routine routine attemps to
+ *     acquire the given resource for exclusive access.
+ *
+ * @param Resource
+ *        Pointer to the resource to be acquired.
+ *
+ * @return TRUE if the given resource has been acquired for the caller.
+ *
+ * @remarks Callers of ExTryToAcquireResourceExclusiveLite must be running at
+ *          IRQL < DISPATCH_LEVEL.
+ *
+ *--*/
+BOOLEAN
+NTAPI
+ExTryToAcquireResourceExclusiveLite(PERESOURCE Resource)
+{
+    ERESOURCE_THREAD Thread;
+    KIRQL OldIrql;
+    BOOLEAN Acquired = FALSE;
+    DPRINT("ExTryToAcquireResourceExclusiveLite: %p\n", Resource);
+
+    /* Sanity check */
+    ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
+
+    /* Get the thread */
+    Thread = ExGetCurrentResourceThread();
+
+    /* Sanity check and validation */
+    ASSERT(KeIsExecutingDpc() == FALSE);
+    ExpVerifyResource(Resource);
+
+    /* Acquire the lock */
+    ExAcquireResourceLock(&Resource->SpinLock, &OldIrql);
+
+    /* Check if there is an owner */
+    if (!Resource->ActiveCount)
+    {
+        /* No owner, give exclusive access */
+        Resource->Flag |= ResourceOwnedExclusive;
+        Resource->OwnerThreads[0].OwnerThread = Thread;
+        Resource->OwnerThreads[0].OwnerCount = 1;
+        Resource->ActiveCount = 1;
+        Acquired = TRUE;
+    }
+    else if ((IsOwnedExclusive(Resource)) &&
+             (Resource->OwnerThreads[0].OwnerThread == Thread))
+    {
+        /* Do a recursive acquire */
+        Resource->OwnerThreads[0].OwnerCount++;
+        Acquired = TRUE;
+    }
 
-                /* Loop until we find the current thread in an entry */
-                for (;OwnerEntry->OwnerThread == (ULONG_PTR)CurrentThread;OwnerEntry++);
+    /* Release the resource */
+    ExReleaseResourceLock(&Resource->SpinLock, OldIrql);
+    return Acquired;
+}
 
-            } else {
+/*++
+ * @name ExEnterCriticalRegionAndAcquireResourceExclusive
+ * @implemented NT5.1
+ *
+ *     The ExEnterCriticalRegionAndAcquireResourceExclusive enters a critical
+ *     region and then exclusively acquires a resource.
+ *
+ * @param Resource
+ *        Pointer to the resource to acquire.
+ *
+ * @return Pointer to the Win32K thread pointer of the current thread.
+ *
+ * @remarks See ExAcquireResourceExclusiveLite.
+ *
+ *--*/
+PVOID
+NTAPI
+ExEnterCriticalRegionAndAcquireResourceExclusive(PERESOURCE Resource)
+{
+    /* Enter critical region */
+    KeEnterCriticalRegion();
 
-                /* It's in the current RTE, so set it */
-                OwnerEntry = &OwnerEntry[CurrentThread->ResourceIndex];
-            }
+    /* Acquire the resource */
+    ExAcquireResourceExclusiveLite(Resource, TRUE);
 
-            /* Now that we went to the right entry, set the Owner Pointer */
-            OwnerEntry->OwnerThread = (ULONG_PTR)OwnerPointer;
-        }
-    }
+    /* Return the Win32 Thread */
+    return KeGetCurrentThread()->Win32Thread;
+}
 
+/*++
+ * @name ExReleaseResourceAndLeaveCriticalRegion
+ * @implemented NT5.1
+ *
+ *     The ExReleaseResourceAndLeaveCriticalRegion release a resource and
+ *     then leaves a critical region.
+ *
+ * @param Resource
+ *        Pointer to the resource to release.
+ *
+ * @return None
+ *
+ * @remarks See ExReleaseResourceLite.
+ *
+ *--*/
+VOID
+FASTCALL
+ExReleaseResourceAndLeaveCriticalRegion(PERESOURCE Resource)
+{
     /* Release the resource */
-    KeReleaseSpinLock(&Resource->SpinLock, OldIrql);
+    ExReleaseResourceLite(Resource);
+
+    /* Leave critical region */
+    KeLeaveCriticalRegion();
 }
 
 /* EOF */
+
index 075fbbc..714b97c 100644 (file)
@@ -15,6 +15,17 @@ extern POBJECT_TYPE ExEventPairObjectType;
   ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE |           \
   EX_HANDLE_ENTRY_AUDITONCLOSE)))
 
+/* Note: we only use a spinlock on SMP. On UP, we cli/sti intead */
+#ifndef CONFIG_SMP
+#define ExAcquireResourceLock(l, i) \
+    UNREFERENCED_PARAMETER(*i); \
+    Ke386DisableInterrupts();
+#define ExReleaseResourceLock(l, i) Ke386EnableInterrupts();
+#else
+#define ExAcquireResourceLock(l, i) KeAcquireSpinLock(l, i);
+#define ExReleaseResourceLock(l, i) KeReleaseSpinLock(l, i);
+#endif
+
 /* INITIALIZATION FUNCTIONS *************************************************/
 
 VOID
@@ -77,6 +88,10 @@ VOID
 STDCALL
 ExpInitializeProfileImplementation(VOID);
 
+VOID
+NTAPI
+ExpResourceInitialization(VOID);
+
 /* Rundown Functions ********************************************************/
 
 VOID
index 4d36fc9..a7d96d4 100644 (file)
@@ -10,9 +10,9 @@
 #define CALLBACK_TAG        TAG('C','L','B','K')
 
 /* formerly located in ex/resource.c */
-#define TAG_OWNER_TABLE     TAG('R', 'O', 'W', 'N')
-#define TAG_EXCLUSIVE_LOCK  TAG('E', 'R', 'E', 'L')
-#define TAG_SHARED_SEM      TAG('E', 'R', 'S', 'S')
+#define TAG_RESOURCE_TABLE      TAG('R', 'e', 'T', 'a')
+#define TAG_RESOURCE_EVENT      TAG('R', 'e', 'T', 'a')
+#define TAG_RESOURCE_SEMAPHORE  TAG('R', 'e', 'T', 'a')
 
 /* formerly located in fs/notify.c */
 #define FSRTL_NOTIFY_TAG TAG('N','O','T','I')
index e3cde5f..12987c7 100644 (file)
@@ -1003,20 +1003,28 @@ Language=English
 WORKER_THREAD_RETURNED_AT_BAD_IRQL
 .
 
-MessageId=0xE4
+MessageId=0xE2
 Severity=Success
 Facility=System
-SymbolicName=WORKER_INVALID
+SymbolicName=MANUALLY_INITIATED_CRASH
 Language=English
-WORKER_INVALID
+MANUALLY_INITIATED_CRASH
 .
 
-MessageId=0xE2
+MessageId=0xE3
 Severity=Success
 Facility=System
-SymbolicName=MANUALLY_INITIATED_CRASH
+SymbolicName=RESOURCE_NOT_OWNED
 Language=English
-MANUALLY_INITIATED_CRASH
+RESOURCE_NOT_OWNED
+.
+
+MessageId=0xE4
+Severity=Success
+Facility=System
+SymbolicName=WORKER_INVALID
+Language=English
+WORKER_INVALID
 .
 
 MessageId=0xFA
@@ -1085,4 +1093,4 @@ Language=English
 ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY
 .
 
-; EOF
\ No newline at end of file
+; EOF
index 8f5f16f..6cc7c8d 100644 (file)
@@ -6601,7 +6601,7 @@ ExIsResourceAcquiredLite(
   IN PERESOURCE  Resource);
 
 NTOSAPI
-USHORT
+ULONG
 DDKAPI
 ExIsResourceAcquiredSharedLite(
   IN PERESOURCE  Resource);
@@ -6648,7 +6648,7 @@ ExRegisterCallback(
   IN PVOID  CallbackContext);
 
 NTOSAPI
-VOID
+NTSTATUS
 DDKAPI
 ExReinitializeResourceLite(
   IN PERESOURCE  Resource);