ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

resource.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ex/resource.c
00005  * PURPOSE:         Executive Resource Implementation
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  */
00008 
00009 /* INCLUDES *****************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* Macros for reading resource flags */
00016 #define IsExclusiveWaiting(r)   (r->NumberOfExclusiveWaiters > 0)
00017 #define IsSharedWaiting(r)      (r->NumberOfSharedWaiters > 0)
00018 #define IsOwnedExclusive(r)     (r->Flag & ResourceOwnedExclusive)
00019 #define IsBoostAllowed(r)       (!(r->Flag & ResourceHasDisabledPriorityBoost))
00020 
00021 #if (!(defined(CONFIG_SMP)) && !(DBG))
00022 
00023 FORCEINLINE
00024 VOID
00025 ExAcquireResourceLock(IN PERESOURCE Resource,
00026                       IN PKLOCK_QUEUE_HANDLE LockHandle)
00027 {
00028     UNREFERENCED_PARAMETER(Resource);
00029     UNREFERENCED_PARAMETER(LockHandle);
00030 
00031     /* Simply disable interrupts */
00032     _disable();
00033 }
00034 
00035 FORCEINLINE
00036 VOID
00037 ExReleaseResourceLock(IN PERESOURCE Resource,
00038                       IN PKLOCK_QUEUE_HANDLE LockHandle)
00039 {
00040     UNREFERENCED_PARAMETER(Resource);
00041     UNREFERENCED_PARAMETER(LockHandle);
00042 
00043     /* Simply enable interrupts */
00044     _enable();
00045 }
00046 
00047 #else
00048 
00049 FORCEINLINE
00050 VOID
00051 ExAcquireResourceLock(IN PERESOURCE Resource,
00052                       IN PKLOCK_QUEUE_HANDLE LockHandle)
00053 {
00054     /* Acquire the lock */
00055     KeAcquireInStackQueuedSpinLock(&Resource->SpinLock, LockHandle);
00056 }
00057 
00058 FORCEINLINE
00059 VOID
00060 ExReleaseResourceLock(IN PERESOURCE Resource,
00061                       IN PKLOCK_QUEUE_HANDLE LockHandle)
00062 {
00063     UNREFERENCED_PARAMETER(Resource);
00064 
00065     /* Release the lock */
00066     KeReleaseInStackQueuedSpinLock(LockHandle);
00067 }
00068 #endif
00069 
00070 /* DATA***********************************************************************/
00071 
00072 LARGE_INTEGER ExShortTime = {{-100000, -1}};
00073 LARGE_INTEGER ExpTimeout;
00074 ULONG ExpResourceTimeoutCount = 90 * 3600 / 2;
00075 KSPIN_LOCK ExpResourceSpinLock;
00076 LIST_ENTRY ExpSystemResourcesList;
00077 BOOLEAN ExResourceStrict = TRUE;
00078 
00079 /* PRIVATE FUNCTIONS *********************************************************/
00080 
00081 #if DBG
00082 /*++
00083  * @name ExpVerifyResource
00084  *
00085  *     The ExpVerifyResource routine verifies the correctness of an ERESOURCE
00086  *
00087  * @param Resource
00088  *        Pointer to the resource being verified.
00089  *
00090  * @return None.
00091  *
00092  * @remarks Only present on DBG builds.
00093  *
00094  *--*/
00095 VOID
00096 NTAPI
00097 ExpVerifyResource(IN PERESOURCE Resource)
00098 {
00099     /* Verify the resource data */
00100     ASSERT((((ULONG_PTR)Resource) & (sizeof(ULONG_PTR) - 1)) == 0);
00101     ASSERT(!Resource->SharedWaiters ||
00102             Resource->SharedWaiters->Header.Type == SemaphoreObject);
00103     ASSERT(!Resource->SharedWaiters ||
00104             Resource->SharedWaiters->Header.Size == (sizeof(KSEMAPHORE) / sizeof(ULONG)));
00105     ASSERT(!Resource->ExclusiveWaiters ||
00106             Resource->ExclusiveWaiters->Header.Type == SynchronizationEvent);
00107     ASSERT(!Resource->ExclusiveWaiters ||
00108             Resource->ExclusiveWaiters->Header.Size == (sizeof(KEVENT) / sizeof(ULONG)));
00109 }
00110 
00111 /*++
00112  * @name ExpCheckForApcsDisabled
00113  *
00114  *     The ExpCheckForApcsDisabled routine checks if Kernel APCs are still
00115  *     enabled when they should be disabled, and optionally breakpoints.
00116  *
00117  * @param Irql
00118  *        Specifies the IRQL during the acquire attempt.
00119  *
00120  * @param Resource
00121  *        Pointer to the resource being checked.
00122  *
00123  * @param Thread
00124  *        Pointer to the thread being checked.
00125  *
00126  * @return None.
00127  *
00128  * @remarks Only present on DBG builds. Depends on ExResourceStrict value.
00129  *
00130  *--*/
00131 VOID
00132 NTAPI
00133 ExpCheckForApcsDisabled(IN KIRQL Irql,
00134                         IN PERESOURCE Resource,
00135                         IN PKTHREAD Thread)
00136 {
00137     /* Check if we should care and check if we should break */
00138     if ((ExResourceStrict) &&
00139         (Irql < APC_LEVEL) &&
00140         !(((PETHREAD)Thread)->SystemThread) &&
00141         !(Thread->CombinedApcDisable))
00142     {
00143         /* Bad! */
00144         DPRINT1("EX: resource: APCs still enabled before resource %p acquire "
00145                 "!!!\n", Resource);
00146         DbgBreakPoint();
00147     }
00148 }
00149 #else
00150 #define ExpVerifyResource(r)
00151 #define ExpCheckForApcsDisabled(b,r,t)
00152 #endif
00153 
00154 /*++
00155  * @name ExpResourceInitialization
00156  *
00157  *     The ExpResourceInitialization routine initializes resources for use.
00158  *
00159  * @param None.
00160  *
00161  * @return None.
00162  *
00163  * @remarks This routine should only be called once, during system startup.
00164  *
00165  *--*/
00166 VOID
00167 NTAPI
00168 INIT_FUNCTION
00169 ExpResourceInitialization(VOID)
00170 {
00171     /* Setup the timeout */
00172     ExpTimeout.QuadPart = Int32x32To64(4, -10000000);
00173     InitializeListHead(&ExpSystemResourcesList);
00174     KeInitializeSpinLock(&ExpResourceSpinLock);
00175 }
00176 
00177 /*++
00178  * @name ExpAllocateExclusiveWaiterEvent
00179  *
00180  *     The ExpAllocateExclusiveWaiterEvent routine creates the event that will
00181  *     be used by exclusive waiters on the resource.
00182  *
00183  * @param Resource
00184  *        Pointer to the resource.
00185  *
00186  * @param LockHandle
00187  *        Pointer to in-stack queued spinlock.
00188  *
00189  * @return None.
00190  *
00191  * @remarks The pointer to the event must be atomically set.
00192  *
00193  *--*/
00194 VOID
00195 NTAPI
00196 ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource,
00197                                 IN PKLOCK_QUEUE_HANDLE LockHandle)
00198 {
00199     PKEVENT Event;
00200 
00201     /* Release the lock */
00202     ExReleaseResourceLock(Resource, LockHandle);
00203 
00204     /* Loop as long as we keep running out of memory */
00205     do
00206     {
00207         /* Allocate the event */
00208         Event = ExAllocatePoolWithTag(NonPagedPool,
00209                                       sizeof(KEVENT),
00210                                       TAG_RESOURCE_EVENT);
00211         if (Event)
00212         {
00213             /* Initialize it */
00214             KeInitializeEvent(Event, SynchronizationEvent, FALSE);
00215 
00216             /* Set it */
00217             if (InterlockedCompareExchangePointer((PVOID*)&Resource->ExclusiveWaiters,
00218                                                   Event,
00219                                                   NULL))
00220             {
00221                 /* Someone already set it, free our event */
00222                 DPRINT1("WARNING: Handling race condition\n");
00223                 ExFreePoolWithTag(Event, TAG_RESOURCE_EVENT);
00224             }
00225 
00226             break;
00227         }
00228 
00229         /* Wait a bit before trying again */
00230         KeDelayExecutionThread(KernelMode, FALSE, &ExShortTime);
00231     } while (TRUE);
00232 
00233     /* Re-acquire the lock */
00234     ExAcquireResourceLock(Resource, LockHandle);
00235 }
00236 
00237 /*++
00238  * @name ExpAllocateSharedWaiterSemaphore
00239  *
00240  *     The ExpAllocateSharedWaiterSemaphore routine creates the semaphore that
00241  *     will be used by shared waiters on the resource.
00242  *
00243  * @param Resource
00244  *        Pointer to the resource.
00245  *
00246  * @param LockHandle
00247  *        Pointer to in-stack queued spinlock.
00248  *
00249  * @return None.
00250  *
00251  * @remarks The pointer to the semaphore must be atomically set.
00252  *
00253  *--*/
00254 VOID
00255 NTAPI
00256 ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource,
00257                                  IN PKLOCK_QUEUE_HANDLE LockHandle)
00258 {
00259     PKSEMAPHORE Semaphore;
00260 
00261     /* Release the lock */
00262     ExReleaseResourceLock(Resource, LockHandle);
00263 
00264     /* Loop as long as we keep running out of memory */
00265     do
00266     {
00267         /* Allocate the semaphore */
00268         Semaphore = ExAllocatePoolWithTag(NonPagedPool,
00269                                           sizeof(KSEMAPHORE),
00270                                           TAG_RESOURCE_SEMAPHORE);
00271         if (Semaphore)
00272         {
00273             /* Initialize it */
00274             KeInitializeSemaphore(Semaphore, 0, MAXLONG);
00275 
00276             /* Set it */
00277             if (InterlockedCompareExchangePointer((PVOID*)&Resource->SharedWaiters,
00278                                                   Semaphore,
00279                                                   NULL))
00280             {
00281                 /* Someone already set it, free our semaphore */
00282                 DPRINT1("WARNING: Handling race condition\n");
00283                 ExFreePoolWithTag(Semaphore, TAG_RESOURCE_SEMAPHORE);
00284             }
00285 
00286             break;
00287         }
00288 
00289         /* Wait a bit before trying again */
00290         KeDelayExecutionThread(KernelMode, FALSE, &ExShortTime);
00291     } while (TRUE);
00292 
00293     /* Re-acquire the lock */
00294     ExAcquireResourceLock(Resource, LockHandle);
00295 }
00296 
00297 /*++
00298  * @name ExpExpandResourceOwnerTable
00299  *
00300  *     The ExpExpandResourceOwnerTable routine expands the owner table of the
00301  *     specified resource.
00302  *
00303  * @param Resource
00304  *        Pointer to the resource.
00305  *
00306  * @param LockHandle
00307  *        Pointer to in-stack queued spinlock.
00308  *
00309  * @return None.
00310  *
00311  * @remarks None.
00312  *
00313  *--*/
00314 VOID
00315 NTAPI
00316 ExpExpandResourceOwnerTable(IN PERESOURCE Resource,
00317                             IN PKLOCK_QUEUE_HANDLE LockHandle)
00318 {
00319     POWNER_ENTRY Owner, Table;
00320     KIRQL OldIrql;
00321     ULONG NewSize, OldSize;
00322 
00323     /* Get the owner table */
00324     Owner = Resource->OwnerTable;
00325     if (!Owner)
00326     {
00327         /* Start with the default size of 3 */
00328         OldSize = 0;
00329         NewSize = 3;
00330     }
00331     else
00332     {
00333         /* Add 4 more entries */
00334         OldSize = Owner->TableSize;
00335         NewSize = OldSize + 4;
00336     }
00337 
00338     /* Release the lock */
00339     ExReleaseResourceLock(Resource, LockHandle);
00340 
00341     /* Allocate memory for the table */
00342     Table = ExAllocatePoolWithTag(NonPagedPool,
00343                                   NewSize * sizeof(OWNER_ENTRY),
00344                                   TAG_RESOURCE_TABLE);
00345 
00346     /* Zero the table */
00347     RtlZeroMemory(Table + OldSize,
00348                   (NewSize - OldSize) * sizeof(OWNER_ENTRY));
00349 
00350     /* Lock the resource */
00351     ExAcquireResourceLock(Resource, LockHandle);
00352 
00353     /* Make sure nothing has changed */
00354     if ((Owner != Resource->OwnerTable) ||
00355         ((Owner) && (OldSize != Owner->TableSize)))
00356     {
00357         /* Resource changed while we weren't holding the lock; bail out */
00358         ExReleaseResourceLock(Resource, LockHandle);
00359         ExFreePoolWithTag(Table, TAG_RESOURCE_TABLE);
00360     }
00361     else
00362     {
00363         /* Copy the table */
00364         RtlCopyMemory(Table, Owner, OldSize * sizeof(OWNER_ENTRY));
00365 
00366         /* Acquire dispatcher lock to prevent thread boosting */
00367         OldIrql = KiAcquireDispatcherLock();
00368 
00369         /* Set the new table data */
00370         Table->TableSize = NewSize;
00371         Resource->OwnerTable = Table;
00372 
00373         /* Release dispatcher lock */
00374         KiReleaseDispatcherLock(OldIrql);
00375 
00376         /* Sanity check */
00377         ExpVerifyResource(Resource);
00378 
00379         /* Release lock */
00380         ExReleaseResourceLock(Resource, LockHandle);
00381 
00382         /* Free the old table */
00383         if (Owner) ExFreePoolWithTag(Owner, TAG_RESOURCE_TABLE);
00384 
00385         /* Set the resource index */
00386         if (!OldSize) OldSize = 1;
00387     }
00388 
00389     /* Set the resource index */
00390     KeGetCurrentThread()->ResourceIndex = (UCHAR)OldSize;
00391 
00392     /* Lock the resource again */
00393     ExAcquireResourceLock(Resource, LockHandle);
00394 }
00395 
00396 /*++
00397  * @name ExpFindFreeEntry
00398  *
00399  *     The ExpFindFreeEntry routine locates an empty owner entry in the
00400  *     specified resource. If none was found, then the owner table is
00401  *     expanded.
00402  *
00403  * @param Resource
00404  *        Pointer to the resource.
00405  *
00406  * @param LockHandle
00407  *        Pointer to in-stack queued spinlock.
00408  *
00409  * @return Pointer to an empty OWNER_ENTRY structure.
00410  *
00411  * @remarks None.
00412  *
00413  *--*/
00414 POWNER_ENTRY
00415 FASTCALL
00416 ExpFindFreeEntry(IN PERESOURCE Resource,
00417                  IN PKLOCK_QUEUE_HANDLE LockHandle)
00418 {
00419     POWNER_ENTRY Owner, Limit;
00420 
00421     /* Sanity check */
00422     ASSERT(LockHandle != 0);
00423     ASSERT(Resource->OwnerEntry.OwnerThread != 0);
00424 
00425     /* Get the current table pointer */
00426     Owner = Resource->OwnerTable;
00427     if (Owner)
00428     {
00429         /* Set the limit, move to the next owner and loop owner entries */
00430         Limit = &Owner[Owner->TableSize];
00431         Owner++;
00432         while (Owner->OwnerThread)
00433         {
00434             /* Move to the next one */
00435             Owner++;
00436             
00437             /* Check if the entry is free */
00438             if (Owner == Limit) goto Expand;
00439         }
00440         
00441         /* Update the resource entry */
00442         KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner - Resource->OwnerTable);
00443     }
00444     else
00445     {
00446 Expand:
00447         /* No free entry, expand the table */
00448         ExpExpandResourceOwnerTable(Resource, LockHandle);
00449         Owner = NULL;
00450     }
00451 
00452     /* Return the entry found */
00453     return Owner;
00454 }
00455 
00456 /*++
00457  * @name ExpFindEntryForThread
00458  *
00459  *     The ExpFindEntryForThread routine locates the owner entry associated with
00460  *     the specified thread in the given resource. If none was found, then the
00461  *     owner table is expanded.
00462  *
00463  * @param Resource
00464  *        Pointer to the resource.
00465  *
00466  * @param Thread
00467  *        Pointer to the thread to find.
00468  *
00469  * @param LockHandle
00470  *        Pointer to in-stack queued spinlock.
00471  *
00472  * @return Pointer to an empty OWNER_ENTRY structure.
00473  *
00474  * @remarks None.
00475  *
00476  *--*/
00477 POWNER_ENTRY
00478 FASTCALL
00479 ExpFindEntryForThread(IN PERESOURCE Resource,
00480                       IN ERESOURCE_THREAD Thread,
00481                       IN PKLOCK_QUEUE_HANDLE LockHandle,
00482                       IN BOOLEAN FirstEntryInelligible)
00483 {
00484     POWNER_ENTRY FreeEntry, Owner, Limit;
00485 
00486     /* Start by looking in the static array */
00487     Owner = &Resource->OwnerEntry;
00488     if (Owner->OwnerThread == Thread) return Owner;
00489 
00490     /* Check if this is a free entry */
00491     if ((FirstEntryInelligible) || (Owner->OwnerThread))
00492     {
00493         /* No free entry */
00494         FreeEntry = NULL;
00495     }
00496     else
00497     {
00498         /* Use the first entry as our free entry */
00499         FreeEntry = Owner;
00500     }
00501 
00502     /* Get the current table pointer */
00503     Owner = Resource->OwnerTable;
00504     if (Owner)
00505     {
00506         /* Set the limit, move to the next owner and loop owner entries */
00507         Limit = &Owner[Owner->TableSize];
00508         Owner++;
00509         while (Owner->OwnerThread != Thread)
00510         {
00511             /* Check if we don't have a free entry */
00512             if (!FreeEntry)
00513             {
00514                 /* Check if this entry is free */
00515                 if (!Owner->OwnerThread)
00516                 {
00517                     /* Save it as our free entry */
00518                     FreeEntry = Owner;
00519                 }
00520             }
00521 
00522             /* Move to the next one */
00523             Owner++;
00524             
00525             /* Check if the entry is free */
00526             if (Owner == Limit) goto Expand;
00527         }
00528         
00529         /* Update the resource entry */
00530         KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner - Resource->OwnerTable);
00531         return Owner;
00532     }    
00533     else
00534     {
00535 Expand:
00536         /* Check if it's OK to do an expansion */
00537         if (!LockHandle) return NULL;
00538         
00539         /* If we found a free entry by now, return it */
00540         if (FreeEntry)
00541         {
00542             /* Set the resource index */
00543             KeGetCurrentThread()->ResourceIndex = (UCHAR)(FreeEntry - Resource->OwnerTable);
00544             return FreeEntry;
00545         }
00546         
00547         /* No free entry, expand the table */
00548         ExpExpandResourceOwnerTable(Resource, LockHandle);
00549         return NULL;
00550     }
00551 }
00552 
00553 /*++
00554  * @name ExpBoostOwnerThread
00555  *
00556  *     The ExpBoostOwnerThread routine increases the priority of a waiting
00557  *     thread in an attempt to fight a possible deadlock.
00558  *
00559  * @param Thread
00560  *        Pointer to the current thread.
00561  *
00562  * @param OwnerThread
00563  *        Pointer to thread that owns the resource.
00564  *
00565  * @return None.
00566  *
00567  * @remarks None.
00568  *
00569  *--*/
00570 VOID
00571 FASTCALL
00572 ExpBoostOwnerThread(IN PKTHREAD Thread,
00573                     IN PKTHREAD OwnerThread)
00574 {
00575     /* Make sure the owner thread is a pointer, not an ID */
00576     if (!((ULONG_PTR)OwnerThread & 0x3))
00577     {
00578         /* Check if we can actually boost it */
00579         if ((OwnerThread->Priority < Thread->Priority) &&
00580             (OwnerThread->Priority < 14))
00581         {
00582             /* Acquire the thread lock */
00583             KiAcquireThreadLock(Thread);
00584 
00585             /* Set the new priority */
00586             OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority;
00587 
00588             /* Update quantum */
00589             OwnerThread->Quantum = OwnerThread->QuantumReset;
00590 
00591             /* Update the kernel state */
00592             KiSetPriorityThread(OwnerThread, 14);
00593 
00594             /* Release the thread lock */
00595             KiReleaseThreadLock(Thread);
00596         }
00597     }
00598 }
00599 
00600 /*++
00601  * @name ExpWaitForResource
00602  *
00603  *     The ExpWaitForResource routine performs a wait on the specified resource.
00604  *
00605  * @param Resource
00606  *        Pointer to the resource to wait on.
00607  *
00608  * @param OwnerThread
00609  *        Pointer to object (exclusive event or shared semaphore) to wait on.
00610  *
00611  * @return None.
00612  *
00613  * @remarks None.
00614  *
00615  *--*/
00616 VOID
00617 FASTCALL
00618 ExpWaitForResource(IN PERESOURCE Resource,
00619                    IN PVOID Object)
00620 {
00621     ULONG i;
00622     ULONG Size;
00623     POWNER_ENTRY Owner;
00624     ULONG WaitCount = 0;
00625     NTSTATUS Status;
00626     LARGE_INTEGER Timeout;
00627     PKTHREAD Thread, OwnerThread;
00628 #if DBG
00629     KLOCK_QUEUE_HANDLE LockHandle;
00630 #endif
00631 
00632     /* Increase contention count and use a 5 second timeout */
00633     Resource->ContentionCount++;
00634     Timeout.QuadPart = 500 * -10000;
00635     for (;;)
00636     {
00637         /* Wait for ownership */
00638         Status = KeWaitForSingleObject(Object,
00639                                        WrResource,
00640                                        KernelMode,
00641                                        FALSE,
00642                                        &Timeout);
00643         if (Status != STATUS_TIMEOUT) break;
00644 
00645         /* Increase wait count */
00646         WaitCount++;
00647         Timeout = ExpTimeout;
00648 
00649         /* Check if we've exceeded the limit */
00650         if (WaitCount > ExpResourceTimeoutCount)
00651         {
00652             /* Reset wait count */
00653             WaitCount = 0;
00654 #if DBG
00655             /* Lock the resource */
00656             ExAcquireResourceLock(Resource, &LockHandle);
00657 
00658             /* Dump debug information */
00659             DPRINT1("Resource @ %lx\n", Resource);
00660             DPRINT1(" ActiveEntries = %04lx  Flags = %s%s%s\n",
00661                     Resource->ActiveEntries,
00662                     IsOwnedExclusive(Resource) ? "IsOwnedExclusive " : "",
00663                     IsSharedWaiting(Resource) ? "SharedWaiter "     : "",
00664                     IsExclusiveWaiting(Resource) ? "ExclusiveWaiter "  : "");
00665             DPRINT1(" NumberOfExclusiveWaiters = %04lx\n",
00666                     Resource->NumberOfExclusiveWaiters);
00667             DPRINT1("   Thread = %08lx, Count = %02x\n",
00668                     Resource->OwnerEntry.OwnerThread,
00669                     Resource->OwnerEntry.OwnerCount);
00670 
00671             /* Dump out the table too */
00672             Owner = Resource->OwnerTable;
00673             if (Owner)
00674             {
00675                 /* Loop every entry */
00676                 Size = Owner->TableSize;
00677                 for (i = 1; i < Size; i++)
00678                 {
00679                     /* Print the data */
00680                     Owner++;
00681                     DPRINT1("   Thread = %08lx, Count = %02x\n",
00682                             Owner->OwnerThread,
00683                             Owner->OwnerCount);
00684                 }
00685             }
00686 
00687             /* Break */
00688             DbgBreakPoint();
00689             DPRINT1("EX - Rewaiting\n");
00690             ExReleaseResourceLock(Resource, &LockHandle);
00691 #endif
00692         }
00693 
00694         /* Check if we can boost */
00695         if (IsBoostAllowed(Resource))
00696         {
00697             /* Get the current kernel thread and lock the dispatcher */
00698             Thread = KeGetCurrentThread();
00699             Thread->WaitIrql = KiAcquireDispatcherLock();
00700             Thread->WaitNext = TRUE;
00701 
00702             /* Get the owner thread and boost it */
00703             OwnerThread = (PKTHREAD)Resource->OwnerEntry.OwnerThread;
00704             if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
00705 
00706             /* If it's a shared resource */
00707             if (!IsOwnedExclusive(Resource))
00708             {
00709                 /* Get the table */
00710                 Owner = Resource->OwnerTable;
00711                 if (Owner)
00712                 {
00713                     /* Loop every entry */
00714                     Size = Owner->TableSize;
00715                     for (i = 1; i < Size; i++)
00716                     {
00717                         /* Move to next entry */
00718                         Owner++;
00719 
00720                         /* Get the thread */
00721                         OwnerThread = (PKTHREAD)Owner->OwnerThread;
00722 
00723                         /* Boost it */
00724                         if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
00725                     }
00726                 }
00727             }
00728         }
00729     }
00730 }
00731 
00732 /* FUNCTIONS *****************************************************************/
00733 
00734 /*++
00735  * @name ExAcquireResourceExclusiveLite
00736  * @implemented NT4
00737  *
00738  *     The ExAcquireResourceExclusiveLite routine acquires the given resource
00739  *     for exclusive access by the calling thread.
00740  *
00741  * @param Resource
00742  *        Pointer to the resource to acquire.
00743  *
00744  * @param Wait
00745  *        Specifies the routine's behavior whenever the resource cannot be
00746  *        acquired immediately.
00747  *
00748  * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
00749  *         and exclusive access cannot be granted immediately.
00750  *
00751  * @remarks The caller can release the resource by calling either
00752  *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
00753  *
00754  *          Normal kernel APC delivery must be disabled before calling this
00755  *          routine. Disable normal kernel APC delivery by calling
00756  *          KeEnterCriticalRegion. Delivery must remain disabled until the
00757  *          resource is released, at which point it can be reenabled by calling
00758  *          KeLeaveCriticalRegion.
00759  *
00760  *          For better performance, call ExTryToAcquireResourceExclusiveLite,
00761  *          rather than calling ExAcquireResourceExclusiveLite with Wait set
00762  *          to FALSE.
00763  *
00764  *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
00765  *          DISPATCH_LEVEL.
00766  *
00767  *--*/
00768 BOOLEAN
00769 NTAPI
00770 ExAcquireResourceExclusiveLite(IN PERESOURCE Resource,
00771                                IN BOOLEAN Wait)
00772 {
00773     KLOCK_QUEUE_HANDLE LockHandle;
00774     ERESOURCE_THREAD Thread;
00775     BOOLEAN Success;
00776 
00777     /* Sanity check */
00778     ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
00779 
00780     /* Get the thread */
00781     Thread = ExGetCurrentResourceThread();
00782 
00783     /* Sanity check and validation */
00784     ASSERT(KeIsExecutingDpc() == FALSE);
00785     ExpVerifyResource(Resource);
00786 
00787     /* Acquire the lock */
00788     ExAcquireResourceLock(Resource, &LockHandle);
00789     ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread);
00790 
00791     /* Check if there is a shared owner or exclusive owner */
00792 TryAcquire:
00793     if (Resource->ActiveEntries)
00794     {
00795         /* Check if it's exclusively owned, and we own it */   
00796         if ((IsOwnedExclusive(Resource)) &&
00797             (Resource->OwnerEntry.OwnerThread == Thread))
00798         {
00799             /* Increase the owning count */
00800             Resource->OwnerEntry.OwnerCount++;
00801             Success = TRUE;
00802         }
00803         else
00804         {
00805             /*
00806              * If the caller doesn't want us to wait, we can't acquire the
00807              * resource because someone else then us owns it. If we can wait,
00808              * then we'll wait.
00809              */
00810             if (!Wait)
00811             {
00812                 Success = FALSE;
00813             }
00814             else
00815             {
00816                 /* Check if it has exclusive waiters */
00817                 if (!Resource->ExclusiveWaiters)
00818                 {
00819                     /* It doesn't, allocate the event and try acquiring again */
00820                     ExpAllocateExclusiveWaiterEvent(Resource, &LockHandle);
00821                     goto TryAcquire;
00822                 }
00823 
00824                 /* Has exclusive waiters, wait on it */
00825                 Resource->NumberOfExclusiveWaiters++;
00826                 ExReleaseResourceLock(Resource, &LockHandle);
00827                 ExpWaitForResource(Resource, Resource->ExclusiveWaiters);
00828 
00829                 /* Set owner and return success */
00830                 Resource->OwnerEntry.OwnerThread = ExGetCurrentResourceThread();
00831                 return TRUE;
00832             }
00833         }
00834     }
00835     else
00836     {
00837         /* Nobody owns it, so let's! */
00838         ASSERT(Resource->ActiveEntries == 0);
00839         ASSERT(Resource->ActiveCount == 0);
00840         Resource->Flag |= ResourceOwnedExclusive;
00841         Resource->ActiveEntries = 1;
00842         Resource->ActiveCount = 1;
00843         Resource->OwnerEntry.OwnerThread = Thread;
00844         Resource->OwnerEntry.OwnerCount = 1;
00845         Success = TRUE;
00846     }
00847 
00848     /* Release the lock and return */
00849     ExReleaseResourceLock(Resource, &LockHandle);
00850     return Success;
00851 }
00852 
00853 /*++
00854  * @name ExAcquireResourceSharedLite
00855  * @implemented NT4
00856  *
00857  *     The ExAcquireResourceSharedLite routine acquires the given resource
00858  *     for shared access by the calling thread.
00859  *
00860  * @param Resource
00861  *        Pointer to the resource to acquire.
00862  *
00863  * @param Wait
00864  *        Specifies the routine's behavior whenever the resource cannot be
00865  *        acquired immediately.
00866  *
00867  * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
00868  *         and exclusive access cannot be granted immediately.
00869  *
00870  * @remarks The caller can release the resource by calling either
00871  *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
00872  *
00873  *          Normal kernel APC delivery must be disabled before calling this
00874  *          routine. Disable normal kernel APC delivery by calling
00875  *          KeEnterCriticalRegion. Delivery must remain disabled until the
00876  *          resource is released, at which point it can be reenabled by calling
00877  *          KeLeaveCriticalRegion.
00878  *
00879  *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
00880  *          DISPATCH_LEVEL.
00881  *
00882  *--*/
00883 BOOLEAN
00884 NTAPI
00885 ExAcquireResourceSharedLite(IN PERESOURCE Resource,
00886                             IN BOOLEAN Wait)
00887 {
00888     KLOCK_QUEUE_HANDLE LockHandle;
00889     ERESOURCE_THREAD Thread;
00890     POWNER_ENTRY Owner = NULL;
00891     BOOLEAN FirstEntryBusy;
00892 
00893     /* Get the thread */
00894     Thread = ExGetCurrentResourceThread();
00895 
00896     /* Sanity check and validation */
00897     ASSERT(KeIsExecutingDpc() == FALSE);
00898     ExpVerifyResource(Resource);
00899 
00900     /* Acquire the lock */
00901     ExAcquireResourceLock(Resource, &LockHandle);
00902     ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread);
00903 
00904     /* Check how many active entries we've got */
00905     while (Resource->ActiveEntries != 0)
00906     {
00907         /* Check if it's exclusively owned */
00908         if (IsOwnedExclusive(Resource))
00909         {
00910             /* Check if we own it */
00911             if (Resource->OwnerEntry.OwnerThread == Thread)
00912             {
00913                 /* Increase the owning count */
00914                 Resource->OwnerEntry.OwnerCount++;
00915                 
00916                 /* Release the lock and return */
00917                 ExReleaseResourceLock(Resource, &LockHandle);
00918                 return TRUE;
00919             }
00920             
00921             /* Find a free entry */
00922             Owner = ExpFindFreeEntry(Resource, &LockHandle);
00923             if (!Owner) continue;
00924         }
00925         else
00926         {
00927             /* Resource is shared, find who owns it */
00928             FirstEntryBusy = IsExclusiveWaiting(Resource);
00929             Owner = ExpFindEntryForThread(Resource,
00930                                           Thread,
00931                                           &LockHandle,
00932                                           FirstEntryBusy);
00933             if (!Owner) continue;
00934             
00935             /* Is it us? */
00936             if (Owner->OwnerThread == Thread)
00937             {
00938                 /* Increase acquire count and return */
00939                 Owner->OwnerCount++;
00940                 ASSERT(Owner->OwnerCount != 0);
00941                 
00942                 /* Release the lock and return */
00943                 ExReleaseResourceLock(Resource, &LockHandle);
00944                 return TRUE;
00945             }
00946             
00947             /* Try to find if there are exclusive waiters */
00948             if (!FirstEntryBusy)
00949             {
00950                 /* There are none, so acquire it */
00951                 Owner->OwnerThread = Thread;
00952                 Owner->OwnerCount = 1;
00953                 
00954                 /* Check how many active entries we had */
00955                 if (Resource->ActiveEntries == 0)
00956                 {
00957                     /* Set initial counts */
00958                     ASSERT(Resource->ActiveCount == 0);
00959                     Resource->ActiveEntries = 1;
00960                     Resource->ActiveCount = 1;
00961                 }
00962                 else
00963                 {
00964                     /* Increase active entries */
00965                     ASSERT(Resource->ActiveCount == 1);
00966                     Resource->ActiveEntries++;   
00967                 }
00968                 
00969                 /* Release the lock and return */
00970                 ExReleaseResourceLock(Resource, &LockHandle);
00971                 return TRUE;
00972             }
00973         }
00974         
00975         /* If we got here, then we need to wait. Are we allowed? */
00976         if (!Wait)
00977         {
00978             /* Release the lock and return */
00979             ExReleaseResourceLock(Resource, &LockHandle);
00980             return FALSE;
00981         }
00982         
00983         /* Check if we have a shared waiters semaphore */
00984         if (!Resource->SharedWaiters)
00985         {
00986             /* Allocate it and try another acquire */
00987             ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle);
00988         }
00989         else
00990         {
00991             /* We have shared waiters, wait for it */
00992             break;
00993         }
00994     }
00995     
00996     /* Did we get here because we don't have active entries? */
00997     if (Resource->ActiveEntries == 0)
00998     {
00999         /* Acquire it */
01000         ASSERT(Resource->ActiveEntries == 0);
01001         ASSERT(Resource->ActiveCount == 0);
01002         Resource->ActiveEntries = 1;
01003         Resource->ActiveCount = 1;
01004         Resource->OwnerEntry.OwnerThread = Thread;
01005         Resource->OwnerEntry.OwnerCount = 1;
01006         
01007         /* Release the lock and return */
01008         ExReleaseResourceLock(Resource, &LockHandle);
01009         return TRUE;
01010     }
01011 
01012     /* Now wait for the resource */
01013     Owner->OwnerThread = Thread;
01014     Owner->OwnerCount = 1;
01015     Resource->NumberOfSharedWaiters++;
01016 
01017     /* Release the lock and return */
01018     ExReleaseResourceLock(Resource, &LockHandle);
01019     ExpWaitForResource(Resource, Resource->SharedWaiters);
01020     return TRUE;
01021 }
01022 
01023 /*++
01024  * @name ExAcquireSharedStarveExclusive
01025  * @implemented NT4
01026  *
01027  *     The ExAcquireSharedStarveExclusive routine acquires the given resource
01028  *     shared access without waiting for any pending attempts to acquire
01029  *     exclusive access to the same resource.
01030  *
01031  * @param Resource
01032  *        Pointer to the resource to acquire.
01033  *
01034  * @param Wait
01035  *        Specifies the routine's behavior whenever the resource cannot be
01036  *        acquired immediately.
01037  *
01038  * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
01039  *         and exclusive access cannot be granted immediately.
01040  *
01041  * @remarks The caller can release the resource by calling either
01042  *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
01043  *
01044  *          Normal kernel APC delivery must be disabled before calling this
01045  *          routine. Disable normal kernel APC delivery by calling
01046  *          KeEnterCriticalRegion. Delivery must remain disabled until the
01047  *          resource is released, at which point it can be reenabled by calling
01048  *          KeLeaveCriticalRegion.
01049  *
01050  *          Callers of ExAcquireSharedStarveExclusive usually need quick access
01051  *          to a shared resource in order to save an exclusive accessor from
01052  *          doing redundant work. For example, a file system might call this
01053  *          routine to modify a cached resource, such as a BCB pinned in the
01054  *          cache, before the Cache Manager can acquire exclusive access to the
01055  *          resource and write the cache out to disk.
01056  *
01057  *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
01058  *          DISPATCH_LEVEL.
01059  *
01060  *--*/
01061 BOOLEAN
01062 NTAPI
01063 ExAcquireSharedStarveExclusive(IN PERESOURCE Resource,
01064                                IN BOOLEAN Wait)
01065 {
01066     KLOCK_QUEUE_HANDLE LockHandle;
01067     ERESOURCE_THREAD Thread;
01068     POWNER_ENTRY Owner;
01069 
01070     /* Get the thread */
01071     Thread = ExGetCurrentResourceThread();
01072 
01073     /* Sanity check and validation */
01074     ASSERT(KeIsExecutingDpc() == FALSE);
01075     ExpVerifyResource(Resource);
01076 
01077     /* Acquire the lock */
01078     ExAcquireResourceLock(Resource, &LockHandle);
01079 
01080     /* See if anyone owns it */
01081 TryAcquire:
01082     if (Resource->ActiveEntries == 0)
01083     {
01084         /* Nobody owns it, so let's take control */
01085         ASSERT(Resource->ActiveEntries == 0);
01086         ASSERT(Resource->ActiveCount == 0);
01087         Resource->ActiveCount = 1;
01088         Resource->ActiveEntries = 1;
01089         Resource->OwnerEntry.OwnerThread = Thread;
01090         Resource->OwnerEntry.OwnerCount = 1;
01091         
01092         /* Release the lock and return */
01093         ExReleaseResourceLock(Resource, &LockHandle);
01094         return TRUE;
01095     }
01096 
01097     /* Check if it's exclusively owned */
01098     if (IsOwnedExclusive(Resource))
01099     {
01100         /* Check if we own it */
01101         if (Resource->OwnerEntry.OwnerThread == Thread)
01102         {
01103             /* Increase the owning count */
01104             Resource->OwnerEntry.OwnerCount++;
01105 
01106             /* Release the lock and return */
01107             ExReleaseResourceLock(Resource, &LockHandle);
01108             return TRUE;
01109         }
01110 
01111         /* Find a free entry */
01112         Owner = ExpFindFreeEntry(Resource, &LockHandle);
01113         if (!Owner) goto TryAcquire;
01114     }
01115     else
01116     {
01117         /* Resource is shared, find who owns it */
01118         Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, FALSE);
01119         if (!Owner) goto TryAcquire;
01120 
01121         /* Is it us? */
01122         if (Owner->OwnerThread == Thread)
01123         {
01124             /* Increase acquire count and return */
01125             Owner->OwnerCount++;
01126             ASSERT(Owner->OwnerCount != 0);
01127 
01128             /* Release the lock and return */
01129             ExReleaseResourceLock(Resource, &LockHandle);
01130             return TRUE;
01131         }
01132 
01133         /* Acquire it */
01134         Owner->OwnerThread = Thread;
01135         Owner->OwnerCount = 1;
01136 
01137         /* Check how many active entries we had */
01138         if (Resource->ActiveEntries == 0)
01139         {
01140             /* Set initial counts */
01141             ASSERT(Resource->ActiveCount == 0);
01142             Resource->ActiveEntries = 1;
01143             Resource->ActiveCount = 1;
01144         }
01145         else
01146         {
01147             /* Increase active entries */
01148             ASSERT(Resource->ActiveCount == 1);
01149             Resource->ActiveEntries++;   
01150         }
01151 
01152         /* Release the lock and return */
01153         ExReleaseResourceLock(Resource, &LockHandle);
01154         return TRUE;
01155     }
01156 
01157     /* If we got here, then we need to wait. Are we allowed? */
01158     if (!Wait)
01159     {
01160         /* Release the lock and return */
01161         ExReleaseResourceLock(Resource, &LockHandle);
01162         return FALSE;
01163     }
01164 
01165     /* Check if we have a shared waiters semaphore */
01166     if (!Resource->SharedWaiters)
01167     {
01168         /* Allocate it and try another acquire */
01169         ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle);
01170         goto TryAcquire;
01171     }
01172 
01173     /* Now wait for the resource */
01174     Owner->OwnerThread = Thread;
01175     Owner->OwnerCount = 1;
01176     Resource->NumberOfSharedWaiters++;
01177 
01178     /* Release the lock and return */
01179     ExReleaseResourceLock(Resource, &LockHandle);
01180     ExpWaitForResource(Resource, Resource->SharedWaiters);
01181     return TRUE;
01182 }
01183 
01184 /*++
01185  * @name ExAcquireSharedWaitForExclusive
01186  * @implemented NT4
01187  *
01188  *     The ExAcquireSharedWaitForExclusive routine acquires the given resource
01189  *     for shared access if shared access can be granted and there are no
01190  *     exclusive waiters.
01191  *
01192  * @param Resource
01193  *        Pointer to the resource to acquire.
01194  *
01195  * @param Wait
01196  *        Specifies the routine's behavior whenever the resource cannot be
01197  *        acquired immediately.
01198  *
01199  * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
01200  *         and exclusive access cannot be granted immediately.
01201  *
01202  * @remarks The caller can release the resource by calling either
01203  *          ExReleaseResourceLite or ExReleaseResourceForThreadLite.
01204  *
01205  *          Normal kernel APC delivery must be disabled before calling this
01206  *          routine. Disable normal kernel APC delivery by calling
01207  *          KeEnterCriticalRegion. Delivery must remain disabled until the
01208  *          resource is released, at which point it can be reenabled by calling
01209  *          KeLeaveCriticalRegion.
01210  *
01211  *          Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
01212  *          DISPATCH_LEVEL.
01213  *
01214  *--*/
01215 BOOLEAN
01216 NTAPI
01217 ExAcquireSharedWaitForExclusive(IN PERESOURCE Resource,
01218                                 IN BOOLEAN Wait)
01219 {
01220     KLOCK_QUEUE_HANDLE LockHandle;
01221     ERESOURCE_THREAD Thread;
01222     POWNER_ENTRY Owner;
01223 
01224     /* Get the thread */
01225     Thread = ExGetCurrentResourceThread();
01226 
01227     /* Sanity check and validation */
01228     ASSERT(KeIsExecutingDpc() == FALSE);
01229     ExpVerifyResource(Resource);
01230 
01231     /* Acquire the lock */
01232     ExAcquireResourceLock(Resource, &LockHandle);
01233 
01234     /* See if nobody owns us */
01235 TryAcquire:
01236     if (!Resource->ActiveEntries)
01237     {
01238         /* Nobody owns it, so let's take control */
01239         ASSERT(Resource->ActiveEntries == 0);
01240         ASSERT(Resource->ActiveCount == 0);
01241         Resource->ActiveCount = 1;
01242         Resource->ActiveEntries = 1;
01243         Resource->OwnerEntry.OwnerThread = Thread;
01244         Resource->OwnerEntry.OwnerCount = 1;
01245 
01246         /* Release the lock and return */
01247         ExReleaseResourceLock(Resource, &LockHandle);
01248         return TRUE;
01249     }
01250 
01251     /* Check if it's exclusively owned */
01252     if (IsOwnedExclusive(Resource))
01253     {
01254         /* Check if we own it */
01255         if (Resource->OwnerEntry.OwnerThread == Thread)
01256         {
01257             /* Increase the owning count */
01258             Resource->OwnerEntry.OwnerCount++;
01259 
01260             /* Release the lock and return */
01261             ExReleaseResourceLock(Resource, &LockHandle);
01262             return TRUE;
01263         }
01264 
01265         /* Find a free entry */
01266         Owner = ExpFindFreeEntry(Resource, &LockHandle);
01267         if (!Owner) goto TryAcquire;
01268     }
01269     else
01270     {
01271         /* Try to find if there are exclusive waiters */
01272         if (IsExclusiveWaiting(Resource))
01273         {
01274             /* We have to wait for the exclusive waiter to be done */
01275             if (!Wait)
01276             {
01277                 /* So bail out if we're not allowed */
01278                 ExReleaseResourceLock(Resource, &LockHandle);
01279                 return FALSE;
01280             }
01281 
01282             /* Check if we have a shared waiters semaphore */
01283             if (!Resource->SharedWaiters)
01284             {
01285                 /* Allocate one and try again */
01286                 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle);
01287                 goto TryAcquire;
01288             }
01289 
01290             /* Now wait for the resource */
01291             Resource->NumberOfSharedWaiters++;
01292             ExReleaseResourceLock(Resource, &LockHandle);
01293             ExpWaitForResource(Resource, Resource->SharedWaiters);
01294 
01295             /* Get the lock back */
01296             ExAcquireResourceLock(Resource, &LockHandle);
01297 
01298             /* Find who owns it now */
01299             while (!(Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, TRUE)));
01300 
01301             /* Sanity checks */
01302             ASSERT(IsOwnedExclusive(Resource) == FALSE);
01303             ASSERT(Resource->ActiveEntries > 0);
01304             ASSERT(Owner->OwnerThread != Thread);
01305 
01306             /* Take control */
01307             Owner->OwnerThread = Thread;
01308             Owner->OwnerCount = 1;
01309 
01310             /* Release the lock and return */
01311             ExReleaseResourceLock(Resource, &LockHandle);
01312             return TRUE;
01313         }
01314         else
01315         {
01316             /* Resource is shared, find who owns it */
01317             Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, FALSE);
01318             if (!Owner) goto TryAcquire;
01319 
01320             /* Is it us? */
01321             if (Owner->OwnerThread == Thread)
01322             {
01323                 /* Increase acquire count and return */
01324                 Owner->OwnerCount++;
01325                 ASSERT(Owner->OwnerCount != 0);
01326 
01327                 /* Release the lock and return */
01328                 ExReleaseResourceLock(Resource, &LockHandle);
01329                 return TRUE;
01330             }
01331 
01332             /* No exclusive waiters, so acquire it */
01333             Owner->OwnerThread = Thread;
01334             Owner->OwnerCount = 1;
01335 
01336             /* Check how many active entries we had */
01337             if (Resource->ActiveEntries == 0)
01338             {
01339                 /* Set initial counts */
01340                 ASSERT(Resource->ActiveCount == 0);
01341                 Resource->ActiveEntries = 1;
01342                 Resource->ActiveCount = 1;
01343             }
01344             else
01345             {
01346                 /* Increase active entries */
01347                 ASSERT(Resource->ActiveCount == 1);
01348                 Resource->ActiveEntries++;   
01349             }
01350             
01351             /* Release the lock and return */
01352             ExReleaseResourceLock(Resource, &LockHandle);
01353             return TRUE;
01354         }
01355     }
01356 
01357     /* We have to wait for the exclusive waiter to be done */
01358     if (!Wait)
01359     {
01360         /* So bail out if we're not allowed */
01361         ExReleaseResourceLock(Resource, &LockHandle);
01362         return FALSE;
01363     }
01364 
01365     /* Check if we have a shared waiters semaphore */
01366     if (!Resource->SharedWaiters)
01367     {
01368         /* Allocate one and try again */
01369         ExpAllocateSharedWaiterSemaphore(Resource,&LockHandle);
01370         goto TryAcquire;
01371     }
01372 
01373     /* Take control */
01374     Owner->OwnerThread = Thread;
01375     Owner->OwnerCount = 1;
01376     Resource->NumberOfSharedWaiters++;
01377 
01378     /* Release the lock and return */
01379     ExReleaseResourceLock(Resource, &LockHandle);
01380     ExpWaitForResource(Resource, Resource->SharedWaiters);
01381     return TRUE;
01382 }
01383 
01384 /*++
01385  * @name ExConvertExclusiveToSharedLite
01386  * @implemented NT4
01387  *
01388  *     The ExConvertExclusiveToSharedLite routine converts an exclusively
01389  *     acquired resource into a resource that can be acquired shared.
01390  *
01391  * @param Resource
01392  *        Pointer to the resource to convert.
01393  *
01394  * @return None.
01395  *
01396  * @remarks Callers of ExConvertExclusiveToSharedLite must be running at IRQL <
01397  *          DISPATCH_LEVEL.
01398  *
01399  *--*/
01400 VOID
01401 NTAPI
01402 ExConvertExclusiveToSharedLite(IN PERESOURCE Resource)
01403 {
01404     ULONG OldWaiters;
01405     KLOCK_QUEUE_HANDLE LockHandle;
01406 
01407     /* Sanity checks */
01408     ASSERT(KeIsExecutingDpc() == FALSE);
01409     ExpVerifyResource(Resource);
01410     ASSERT(IsOwnedExclusive(Resource));
01411     ASSERT(Resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)PsGetCurrentThread());
01412     
01413     /* Lock the resource */
01414     ExAcquireResourceLock(Resource, &LockHandle);
01415 
01416     /* Erase the exclusive flag */
01417     Resource->Flag &= ~ResourceOwnedExclusive;
01418 
01419     /* Check if we have shared waiters */
01420     if (IsSharedWaiting(Resource))
01421     {
01422         /* Make the waiters active owners */
01423         OldWaiters = Resource->NumberOfSharedWaiters;
01424         Resource->ActiveEntries += OldWaiters;
01425         Resource->NumberOfSharedWaiters = 0;
01426 
01427         /* Release lock and wake the waiters */
01428         ExReleaseResourceLock(Resource, &LockHandle);
01429         KeReleaseSemaphore(Resource->SharedWaiters, 0, OldWaiters, FALSE);
01430     }
01431     else
01432     {
01433         /* Release lock */
01434         ExReleaseResourceLock(Resource, &LockHandle);
01435     }
01436 }
01437 
01438 /*++
01439  * @name ExDeleteResourceLite
01440  * @implemented NT4
01441  *
01442  *     The ExConvertExclusiveToSharedLite routine deletes a given resource
01443  *     from the system’s resource list.
01444  *
01445  * @param Resource
01446  *        Pointer to the resource to delete.
01447  *
01448  * @return STATUS_SUCCESS if the resource was deleted.
01449  *
01450  * @remarks Callers of ExDeleteResourceLite must be running at IRQL <
01451  *          DISPATCH_LEVEL.
01452  *
01453  *--*/
01454 NTSTATUS
01455 NTAPI
01456 ExDeleteResourceLite(IN PERESOURCE Resource)
01457 {
01458     KLOCK_QUEUE_HANDLE LockHandle;
01459 
01460     /* Sanity checks */
01461     ASSERT(IsSharedWaiting(Resource) == FALSE);
01462     ASSERT(IsExclusiveWaiting(Resource) == FALSE);
01463     ASSERT(KeIsExecutingDpc() == FALSE);
01464     ExpVerifyResource(Resource);
01465 
01466     /* Lock the resource */
01467     KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock, &LockHandle);
01468 
01469     /* Remove the resource */
01470     RemoveEntryList(&Resource->SystemResourcesList);
01471 
01472     /* Release the lock */
01473     KeReleaseInStackQueuedSpinLock(&LockHandle);
01474 
01475     /* Free every  structure */
01476     if (Resource->OwnerTable) ExFreePoolWithTag(Resource->OwnerTable, TAG_RESOURCE_TABLE);
01477     if (Resource->SharedWaiters) ExFreePoolWithTag(Resource->SharedWaiters, TAG_RESOURCE_SEMAPHORE);
01478     if (Resource->ExclusiveWaiters) ExFreePoolWithTag(Resource->ExclusiveWaiters, TAG_RESOURCE_EVENT);
01479 
01480     /* Return success */
01481     return STATUS_SUCCESS;
01482 }
01483 
01484 /*++
01485  * @name ExDisableResourceBoostLite
01486  * @implemented NT4
01487  *
01488  *     The ExDisableResourceBoostLite routine disables thread boosting for
01489  *     the given resource.
01490  *
01491  * @param Resource
01492  *        Pointer to the resource whose thread boosting will be disabled.
01493  *
01494  * @return None.
01495  *
01496  * @remarks None.
01497  *
01498  *--*/
01499 VOID
01500 NTAPI
01501 ExDisableResourceBoostLite(IN PERESOURCE Resource)
01502 {
01503     KLOCK_QUEUE_HANDLE LockHandle;
01504 
01505     /* Sanity check */
01506     ExpVerifyResource(Resource);
01507 
01508     /* Lock the resource */
01509     ExAcquireResourceLock(Resource, &LockHandle);
01510 
01511     /* Remove the flag */
01512     Resource->Flag |= ResourceHasDisabledPriorityBoost;
01513 
01514     /* Release the lock */
01515     ExReleaseResourceLock(Resource, &LockHandle);
01516 }
01517 
01518 /*++
01519  * @name ExGetExclusiveWaiterCount
01520  * @implemented NT4
01521  *
01522  *     The ExGetExclusiveWaiterCount routine returns the number of exclusive
01523  *     waiters for the given resource.
01524  *
01525  * @param Resource
01526  *        Pointer to the resource to check.
01527  *
01528  * @return The number of exclusive waiters.
01529  *
01530  * @remarks None.
01531  *
01532  *--*/
01533 ULONG
01534 NTAPI
01535 ExGetExclusiveWaiterCount(IN PERESOURCE Resource)
01536 {
01537     /* Return the count */
01538     return Resource->NumberOfExclusiveWaiters;
01539 }
01540 
01541 /*++
01542  * @name ExGetSharedWaiterCount
01543  * @implemented NT4
01544  *
01545  *     The ExGetSharedWaiterCount routine returns the number of shared
01546  *     waiters for the given resource.
01547  *
01548  * @param Resource
01549  *        Pointer to the resource to check.
01550  *
01551  * @return The number of shared waiters.
01552  *
01553  * @remarks None.
01554  *
01555  *--*/
01556 ULONG
01557 NTAPI
01558 ExGetSharedWaiterCount(IN PERESOURCE Resource)
01559 {
01560     /* Return the count */
01561     return Resource->NumberOfSharedWaiters;
01562 }
01563 
01564 /*++
01565  * @name ExInitializeResourceLite
01566  * @implemented NT4
01567  *
01568  *     The ExInitializeResourceLite routine initializes a resource variable.
01569  *
01570  * @param Resource
01571  *        Pointer to the resource to check.
01572  *
01573  * @return STATUS_SUCCESS.
01574  *
01575  * @remarks The storage for ERESOURCE must not be allocated from paged pool.
01576  *
01577  *          The storage must be 8-byte aligned.
01578  *
01579  *--*/
01580 NTSTATUS
01581 NTAPI
01582 ExInitializeResourceLite(IN PERESOURCE Resource)
01583 {
01584     KLOCK_QUEUE_HANDLE LockHandle;
01585 
01586     /* Clear the structure */
01587     RtlZeroMemory(Resource, sizeof(ERESOURCE));
01588 
01589     /* Initialize the lock */
01590     KeInitializeSpinLock(&Resource->SpinLock);
01591 
01592     /* Add it into the system list */
01593     KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock, &LockHandle);
01594     InsertTailList(&ExpSystemResourcesList, &Resource->SystemResourcesList);
01595     KeReleaseInStackQueuedSpinLock(&LockHandle);
01596 
01597     /* Return success */
01598     return STATUS_SUCCESS;
01599 }
01600 
01601 /*++
01602  * @name ExIsResourceAcquiredExclusiveLite
01603  * @implemented NT4
01604  *
01605  *     The ExIsResourceAcquiredExclusiveLite routine returns whether the
01606  *     current thread has exclusive access to a given resource.
01607  *
01608  * @param Resource
01609  *        Pointer to the resource to check.
01610  *
01611  * @return TRUE if the caller already has exclusive access to the given resource.
01612  *
01613  * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
01614  *          IRQL <= DISPATCH_LEVEL.
01615  *
01616  *--*/
01617 BOOLEAN
01618 NTAPI
01619 ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
01620 {
01621     BOOLEAN IsAcquired = FALSE;
01622 
01623     /* Sanity check */
01624     ExpVerifyResource(Resource);
01625 
01626     /* Check if it's exclusively acquired */
01627     if ((IsOwnedExclusive(Resource)) &&
01628         (Resource->OwnerEntry.OwnerThread == ExGetCurrentResourceThread()))
01629     {
01630         /* It is acquired */
01631         IsAcquired = TRUE;
01632     }
01633 
01634     /* Return if it's acquired */
01635     return IsAcquired;
01636 }
01637 
01638 /*++
01639  * @name ExIsResourceAcquiredSharedLite
01640  * @implemented NT4
01641  *
01642  *     The ExIsResourceAcquiredSharedLite routine returns whether the
01643  *     current thread has has access (either shared or exclusive) to a
01644  *     given resource.
01645  *
01646  * @param Resource
01647  *        Pointer to the resource to check.
01648  *
01649  * @return Number of times the caller has acquired the given resource for
01650  *         shared or exclusive access.
01651  *
01652  * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
01653  *          IRQL <= DISPATCH_LEVEL.
01654  *
01655  *--*/
01656 ULONG
01657 NTAPI
01658 ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
01659 {
01660     ERESOURCE_THREAD Thread;
01661     ULONG i, Size;
01662     ULONG Count = 0;
01663     KLOCK_QUEUE_HANDLE LockHandle;
01664     POWNER_ENTRY Owner;
01665 
01666     /* Sanity check */
01667     ExpVerifyResource(Resource);
01668 
01669     /* Check if nobody owns us */
01670     if (!Resource->ActiveEntries) return 0;
01671 
01672     /* Get the thread */
01673     Thread = ExGetCurrentResourceThread();
01674 
01675     /* Check if we are in the thread list */
01676     if (Resource->OwnerEntry.OwnerThread == Thread)
01677     {
01678         /* Found it, return count */
01679         Count = Resource->OwnerEntry.OwnerCount;
01680     }
01681     else
01682     {
01683         /* We can't own an exclusive resource at this point */
01684         if (IsOwnedExclusive(Resource)) return 0;
01685 
01686         /* Lock the resource */
01687         ExAcquireResourceLock(Resource, &LockHandle);
01688         
01689         /* Not in the list, do a full table look up */
01690         Owner = Resource->OwnerTable;
01691         if (Owner)
01692         {
01693             /* Get the resource index */
01694             i = ((PKTHREAD)Thread)->ResourceIndex;
01695             Size = Owner->TableSize;
01696             
01697             /* Check if the index is valid and check if we don't match */
01698             if ((i >= Size) || (Owner[i].OwnerThread != Thread))
01699             {
01700                 /* Sh*t! We need to do a full search */
01701                 for (i = 1; i < Size; i++)
01702                 {
01703                     /* Move to next owner */
01704                     Owner++;
01705                     
01706                     /* Try to find a match */
01707                     if (Owner->OwnerThread == Thread)
01708                     {
01709                         /* Finally! */
01710                         Count = Owner->OwnerCount;
01711                         break;
01712                     }
01713                 }
01714             }
01715             else
01716             {
01717                 /* We found the match directlry */
01718                 Count = Owner[i].OwnerCount;
01719             }
01720         }
01721         
01722         /* Release the lock */
01723         ExReleaseResourceLock(Resource, &LockHandle);
01724     }
01725 
01726     /* Return count */
01727     return Count;
01728 }
01729 
01730 /*++
01731  * @name ExReinitializeResourceLite
01732  * @implemented NT4
01733  *
01734  *     The ExReinitializeResourceLite routine routine reinitializes
01735  *     an existing resource variable.
01736  *
01737  * @param Resource
01738  *        Pointer to the resource to be reinitialized.
01739  *
01740  * @return STATUS_SUCCESS.
01741  *
01742  * @remarks With a single call to ExReinitializeResource, a driver writer can
01743  *          replace three calls: one to ExDeleteResourceLite, another to
01744  *          ExAllocatePool, and a third to ExInitializeResourceLite. As
01745  *          contention for a resource variable increases, memory is dynamically
01746  *          allocated and attached to the resource in order to track this
01747  *          contention. As an optimization, ExReinitializeResourceLite retains
01748  *          and zeroes this previously allocated memory.
01749  *
01750  *          Callers of ExReinitializeResourceLite must be running at
01751  *          IRQL <= DISPATCH_LEVEL.
01752  *
01753  *--*/
01754 NTSTATUS
01755 NTAPI
01756 ExReinitializeResourceLite(IN PERESOURCE Resource)
01757 {
01758     PKEVENT Event;
01759     PKSEMAPHORE Semaphore;
01760     ULONG i, Size;
01761     POWNER_ENTRY Owner;
01762 
01763     /* Get the owner table */
01764     Owner = Resource->OwnerTable;
01765     if (Owner)
01766     {
01767         /* Get the size and loop it */
01768         Size = Owner->TableSize;
01769         for (i = 0; i < Size; i++)
01770         {
01771             /* Zero the table */
01772             Owner[i].OwnerThread = 0;
01773             Owner[i].OwnerCount = 0;
01774         }
01775     }
01776 
01777     /* Zero the flags and count */
01778     Resource->Flag = 0;
01779     Resource->ActiveCount = 0;
01780     Resource->ActiveEntries = 0;
01781 
01782     /* Reset the semaphore */
01783     Semaphore = Resource->SharedWaiters;
01784     if (Semaphore) KeInitializeSemaphore(Semaphore, 0, MAXLONG);
01785 
01786     /* Reset the event */
01787     Event = Resource->ExclusiveWaiters;
01788     if (Event) KeInitializeEvent(Event, SynchronizationEvent, FALSE);
01789 
01790     /* Clear the resource data */
01791     Resource->OwnerEntry.OwnerThread = 0;
01792     Resource->OwnerEntry.OwnerCount = 0;
01793     Resource->ContentionCount = 0;
01794     Resource->NumberOfSharedWaiters = 0;
01795     Resource->NumberOfExclusiveWaiters = 0;
01796     return STATUS_SUCCESS;
01797 }
01798 
01799 /*++
01800  * @name ExReleaseResourceLite
01801  * @implemented NT4
01802  *
01803  *     The ExReleaseResourceLite routine routine releases
01804  *     a specified executive resource owned by the current thread.
01805  *
01806  * @param Resource
01807  *        Pointer to the resource to be released.
01808  *
01809  * @return None.
01810  *
01811  * @remarks Callers of ExReleaseResourceLite must be running at
01812  *          IRQL <= DISPATCH_LEVEL.
01813  *
01814  *--*/
01815 VOID
01816 FASTCALL
01817 ExReleaseResourceLite(IN PERESOURCE Resource)
01818 {
01819     /* Just call the For-Thread function */
01820     ExReleaseResourceForThreadLite(Resource, (ERESOURCE_THREAD)PsGetCurrentThread());
01821 }
01822 
01823 /*++
01824  * @name ExReleaseResourceForThreadLite
01825  * @implemented NT4
01826  *
01827  *     The ExReleaseResourceForThreadLite routine routine releases
01828  *     the input resource of the indicated thread.
01829  *
01830  * @param Resource
01831  *        Pointer to the resource to be released.
01832  *
01833  * @param Thread
01834  *        Identifies the thread that originally acquired the resource.
01835   *
01836  * @return None.
01837  *
01838  * @remarks Callers of ExReleaseResourceForThreadLite must be running at
01839  *          IRQL <= DISPATCH_LEVEL.
01840  *
01841  *--*/
01842 VOID
01843 NTAPI
01844 ExReleaseResourceForThreadLite(IN PERESOURCE Resource,
01845                                IN ERESOURCE_THREAD Thread)
01846 {
01847     ULONG i;
01848     ULONG Count;
01849     KLOCK_QUEUE_HANDLE LockHandle;
01850     POWNER_ENTRY Owner, Limit;
01851     ASSERT(Thread != 0);
01852 
01853     /* Get the thread and lock the resource */
01854     ExAcquireResourceLock(Resource, &LockHandle);
01855 
01856     /* Sanity checks */
01857     ExpVerifyResource(Resource);
01858     ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread);
01859 
01860     /* Check if it's exclusively owned */
01861     if (IsOwnedExclusive(Resource))
01862     {
01863         /* Decrement owner count and check if we're done */
01864         ASSERT(Resource->OwnerEntry.OwnerThread == Thread);
01865         if (--Resource->OwnerEntry.OwnerCount)
01866         {
01867             /* Done, release lock! */
01868             ExReleaseResourceLock(Resource, &LockHandle);
01869             return;
01870         }
01871 
01872         /* Clear the owner */
01873         Resource->OwnerEntry.OwnerThread = 0;
01874 
01875         /* Decrement the number of active entries */
01876         ASSERT(Resource->ActiveEntries == 1);
01877         Resource->ActiveEntries--;
01878         
01879         /* Check if there are shared waiters */
01880         if (IsSharedWaiting(Resource))
01881         {
01882             /* Remove the exclusive flag */
01883             Resource->Flag &= ~ResourceOwnedExclusive;
01884             
01885             /* Give ownage to another thread */
01886             Count = Resource->NumberOfSharedWaiters;
01887             Resource->ActiveEntries = Count;
01888             Resource->NumberOfSharedWaiters = 0;
01889             
01890             /* Release lock and let someone else have it */
01891             ASSERT(Resource->ActiveCount == 1);
01892             ExReleaseResourceLock(Resource, &LockHandle);
01893             KeReleaseSemaphore(Resource->SharedWaiters, 0, Count, FALSE);
01894             return;
01895         }
01896         else if (IsExclusiveWaiting(Resource))
01897         {
01898             /* Give exclusive access */
01899             Resource->OwnerEntry.OwnerThread = 1;
01900             Resource->OwnerEntry.OwnerCount = 1;
01901             Resource->ActiveEntries = 1;
01902             Resource->NumberOfExclusiveWaiters--;
01903             
01904             /* Release the lock and give it away */
01905             ASSERT(Resource->ActiveCount == 1);
01906             ExReleaseResourceLock(Resource, &LockHandle);
01907             KeSetEventBoostPriority(Resource->ExclusiveWaiters,
01908                                     (PKTHREAD*)&Resource->OwnerEntry.OwnerThread);
01909             return;
01910         }
01911         
01912         /* Remove the exclusive flag */
01913         Resource->Flag &= ~ResourceOwnedExclusive;
01914         Resource->ActiveCount = 0;
01915     }
01916     else
01917     {
01918         /* Check if we are in the thread list */
01919         if (Resource->OwnerEntry.OwnerThread == Thread)
01920         {
01921             /* Found it, get owner */
01922             Owner = &Resource->OwnerEntry;
01923         }
01924         else
01925         {
01926             /* Assume no valid index */
01927             i = 1;
01928 
01929             /* If we got a valid pointer, try to get the resource index */
01930             if (!((ULONG)Thread & 3)) i = ((PKTHREAD)Thread)->ResourceIndex;
01931 
01932             /* Do a table lookup */
01933             Owner = Resource->OwnerTable;
01934             ASSERT(Owner != NULL);
01935 
01936             /* Check if we're out of the size and don't match */
01937             if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread))
01938             {
01939                 /* Get the last entry */
01940                 Limit = &Owner[Owner->TableSize];
01941                 for (;;)
01942                 {
01943                     /* Move to the next entry */
01944                     Owner++;
01945 
01946                     /* Make sure we're not out of bounds */
01947                     if (Owner >= Limit)
01948                     {
01949                         /* Bugcheck, nobody owns us */
01950                         KeBugCheckEx(RESOURCE_NOT_OWNED,
01951                                      (ULONG_PTR)Resource,
01952                                      (ULONG_PTR)Thread,
01953                                      (ULONG_PTR)Resource->OwnerTable,
01954                                      (ULONG_PTR)3);
01955                     }
01956 
01957                     /* Check for a match */
01958                     if (Owner->OwnerThread == Thread) break;
01959                 }
01960             }
01961             else
01962             {
01963                 /* Get the entry directly */
01964                 Owner = &Owner[i];
01965             }
01966         }
01967 
01968         /* Sanity checks */
01969         ASSERT(Owner->OwnerThread == Thread);
01970         ASSERT(Owner->OwnerCount > 0);
01971 
01972         /* Check if we are the last owner */
01973         if (--Owner->OwnerCount)
01974         {
01975             /* There are other owners, release lock */
01976             ExReleaseResourceLock(Resource, &LockHandle);
01977             return;
01978         }
01979 
01980         /* Clear owner */
01981         Owner->OwnerThread = 0;
01982 
01983         /* See if the resource isn't being owned anymore */
01984         ASSERT(Resource->ActiveEntries > 0);
01985         if (!(--Resource->ActiveEntries))
01986         {
01987             /* Check if there's an exclusive waiter */
01988             if (IsExclusiveWaiting(Resource))
01989             {
01990                 /* Give exclusive access */
01991                 Resource->Flag |= ResourceOwnedExclusive;
01992                 Resource->OwnerEntry.OwnerThread = 1;
01993                 Resource->OwnerEntry.OwnerCount = 1;
01994                 Resource->ActiveEntries = 1;
01995                 Resource->NumberOfExclusiveWaiters--;
01996 
01997                 /* Release the lock and give it away */
01998                 ASSERT(Resource->ActiveCount == 1);
01999                 ExReleaseResourceLock(Resource, &LockHandle);
02000                 KeSetEventBoostPriority(Resource->ExclusiveWaiters,
02001                                         (PKTHREAD*)&Resource->OwnerEntry.OwnerThread);
02002                 return;
02003             }
02004             
02005             /* Clear the active count */
02006             Resource->ActiveCount = 0;
02007         }
02008     }
02009 
02010     /* Release lock */
02011     ExReleaseResourceLock(Resource, &LockHandle);
02012 }
02013 
02014 /*++
02015  * @name ExSetResourceOwnerPointer
02016  * @implemented NT4
02017  *
02018  *     The ExSetResourceOwnerPointer routine routine sets the owner thread
02019  *     thread pointer for an executive resource.
02020  *
02021  * @param Resource
02022  *        Pointer to the resource whose owner to change.
02023  *
02024  * @param OwnerPointer
02025  *        Pointer to an owner thread pointer of type ERESOURCE_THREAD.
02026   *
02027  * @return None.
02028  *
02029  * @remarks ExSetResourceOwnerPointer, used in conjunction with
02030  *          ExReleaseResourceForThreadLite, provides a means for one thread
02031  *          (acting as an resource manager thread) to acquire and release
02032  *          resources for use by another thread (acting as a resource user
02033  *          thread).
02034  *
02035  *          After calling ExSetResourceOwnerPointer for a specific resource,
02036  *          the only other routine that can be called for that resource is
02037  *          ExReleaseResourceForThreadLite.
02038  *
02039  *          Callers of ExSetResourceOwnerPointer must be running at
02040  *          IRQL <= DISPATCH_LEVEL.
02041  *
02042  *--*/
02043 VOID
02044 NTAPI
02045 ExSetResourceOwnerPointer(IN PERESOURCE Resource,
02046                           IN PVOID OwnerPointer)
02047 {
02048     ERESOURCE_THREAD Thread;
02049     KLOCK_QUEUE_HANDLE LockHandle;
02050     POWNER_ENTRY Owner, ThisOwner;
02051 
02052     /* Sanity check */
02053     ASSERT((OwnerPointer != 0) && (((ULONG_PTR)OwnerPointer & 3) == 3));
02054 
02055     /* Get the thread */
02056     Thread = ExGetCurrentResourceThread();
02057 
02058     /* Sanity check */
02059     ExpVerifyResource(Resource);
02060 
02061     /* Lock the resource */
02062     ExAcquireResourceLock(Resource, &LockHandle);
02063 
02064     /* Check if it's exclusive */
02065     if (IsOwnedExclusive(Resource))
02066     {
02067         /* If it's exclusive, set the first entry no matter what */
02068         ASSERT(Resource->OwnerEntry.OwnerThread == Thread);
02069         ASSERT(Resource->OwnerEntry.OwnerCount > 0);
02070         Resource->OwnerEntry.OwnerThread = (ULONG_PTR)OwnerPointer;
02071     }
02072     else
02073     {
02074         /* Set the thread in both entries */
02075         ThisOwner = ExpFindEntryForThread(Resource,
02076                                           (ERESOURCE_THREAD)OwnerPointer,
02077                                           0,
02078                                           FALSE);
02079         Owner = ExpFindEntryForThread(Resource, Thread, 0, FALSE);
02080         if (!Owner)
02081         {
02082             /* Nobody owns it, crash */
02083             KeBugCheckEx(RESOURCE_NOT_OWNED,
02084                          (ULONG_PTR)Resource,
02085                          Thread,
02086                          (ULONG_PTR)Resource->OwnerTable,
02087                          3);
02088         }
02089 
02090         /* Set if we are the owner */
02091         if (ThisOwner)
02092         {
02093             /* Update data */
02094             ThisOwner->OwnerCount += Owner->OwnerCount;
02095             Owner->OwnerCount = 0;
02096             Owner->OwnerThread = 0;
02097             ASSERT(Resource->ActiveEntries >= 2);
02098             Resource->ActiveEntries--;
02099         }
02100         else
02101         {
02102             /* Update the owner entry instead */
02103             Owner->OwnerThread = (ERESOURCE_THREAD)OwnerPointer;
02104         }
02105     }
02106 
02107     /* Release the resource */
02108     ExReleaseResourceLock(Resource, &LockHandle);
02109 }
02110 
02111 /*++
02112  * @name ExTryToAcquireResourceExclusiveLite
02113  * @implemented NT4
02114  *
02115  *     The ExTryToAcquireResourceExclusiveLite routine routine attemps to
02116  *     acquire the given resource for exclusive access.
02117  *
02118  * @param Resource
02119  *        Pointer to the resource to be acquired.
02120  *
02121  * @return TRUE if the given resource has been acquired for the caller.
02122  *
02123  * @remarks Callers of ExTryToAcquireResourceExclusiveLite must be running at
02124  *          IRQL < DISPATCH_LEVEL.
02125  *
02126  *--*/
02127 BOOLEAN
02128 NTAPI
02129 ExTryToAcquireResourceExclusiveLite(IN PERESOURCE Resource)
02130 {
02131     ERESOURCE_THREAD Thread;
02132     KLOCK_QUEUE_HANDLE LockHandle;
02133     BOOLEAN Acquired = FALSE;
02134 
02135     /* Sanity check */
02136     ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
02137 
02138     /* Get the thread */
02139     Thread = ExGetCurrentResourceThread();
02140 
02141     /* Sanity check and validation */
02142     ASSERT(KeIsExecutingDpc() == FALSE);
02143     ExpVerifyResource(Resource);
02144 
02145     /* Acquire the lock */
02146     ExAcquireResourceLock(Resource, &LockHandle);
02147 
02148     /* Check if there is an owner */
02149     if (!Resource->ActiveCount)
02150     {
02151         /* No owner, give exclusive access */
02152         Resource->Flag |= ResourceOwnedExclusive;
02153         Resource->OwnerEntry.OwnerThread = Thread;
02154         Resource->OwnerEntry.OwnerCount = 1;
02155         Resource->ActiveCount = 1;
02156         Resource->ActiveEntries = 1;
02157         Acquired = TRUE;
02158     }
02159     else if ((IsOwnedExclusive(Resource)) &&
02160              (Resource->OwnerEntry.OwnerThread == Thread))
02161     {
02162         /* Do a recursive acquire */
02163         Resource->OwnerEntry.OwnerCount++;
02164         Acquired = TRUE;
02165     }
02166 
02167     /* Release the resource */
02168     ExReleaseResourceLock(Resource, &LockHandle);
02169     return Acquired;
02170 }
02171 
02172 /*++
02173  * @name ExEnterCriticalRegionAndAcquireResourceExclusive
02174  * @implemented NT5.1
02175  *
02176  *     The ExEnterCriticalRegionAndAcquireResourceExclusive enters a critical
02177  *     region and then exclusively acquires a resource.
02178  *
02179  * @param Resource
02180  *        Pointer to the resource to acquire.
02181  *
02182  * @return Pointer to the Win32K thread pointer of the current thread.
02183  *
02184  * @remarks See ExAcquireResourceExclusiveLite.
02185  *
02186  *--*/
02187 PVOID
02188 NTAPI
02189 ExEnterCriticalRegionAndAcquireResourceExclusive(IN PERESOURCE Resource)
02190 {
02191     /* Enter critical region */
02192     KeEnterCriticalRegion();
02193 
02194     /* Acquire the resource */
02195     ExAcquireResourceExclusiveLite(Resource, TRUE);
02196 
02197     /* Return the Win32 Thread */
02198     return KeGetCurrentThread()->Win32Thread;
02199 }
02200 
02201 /*++
02202  * @name ExEnterCriticalRegionAndAcquireResourceShared
02203  * @implemented NT5.2
02204  *
02205  *     The ExEnterCriticalRegionAndAcquireResourceShared routine
02206  *     enters a critical region and then acquires a resource shared.
02207  *
02208  * @param Resource
02209  *        Pointer to the resource to acquire.
02210  *
02211  * @return Pointer to the Win32K thread pointer of the current thread.
02212  *
02213  * @remarks See ExAcquireResourceSharedLite.
02214  *
02215  *--*/
02216 PVOID
02217 NTAPI
02218 ExEnterCriticalRegionAndAcquireResourceShared(IN PERESOURCE Resource)
02219 {
02220     /* Enter critical region */
02221     KeEnterCriticalRegion();
02222 
02223     /* Acquire the resource */
02224     ExAcquireResourceSharedLite(Resource, TRUE);
02225 
02226     /* Return the Win32 Thread */
02227     return KeGetCurrentThread()->Win32Thread;
02228 }
02229 
02230 /*++
02231  * @name ExEnterCriticalRegionAndAcquireSharedWaitForExclusive
02232  * @implemented NT5.2
02233  *
02234  *     The ExEnterCriticalRegionAndAcquireSharedWaitForExclusive routine
02235  *     enters a critical region and then acquires a resource shared if
02236  *     shared access can be granted and there are no exclusive waiters.
02237  *     It then acquires the resource exclusively.
02238  *
02239  * @param Resource
02240  *        Pointer to the resource to acquire.
02241  *
02242  * @return Pointer to the Win32K thread pointer of the current thread.
02243  *
02244  * @remarks See ExAcquireSharedWaitForExclusive.
02245  *
02246  *--*/
02247 PVOID
02248 NTAPI
02249 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(IN PERESOURCE Resource)
02250 {
02251     /* Enter critical region */
02252     KeEnterCriticalRegion();
02253 
02254     /* Acquire the resource */
02255     ExAcquireSharedWaitForExclusive(Resource, TRUE);
02256 
02257     /* Return the Win32 Thread */
02258     return KeGetCurrentThread()->Win32Thread;
02259 }
02260 
02261 /*++
02262  * @name ExReleaseResourceAndLeaveCriticalRegion
02263  * @implemented NT5.1
02264  *
02265  *     The ExReleaseResourceAndLeaveCriticalRegion release a resource and
02266  *     then leaves a critical region.
02267  *
02268  * @param Resource
02269  *        Pointer to the resource to release.
02270  *
02271  * @return None
02272  *
02273  * @remarks See ExReleaseResourceLite.
02274  *
02275  *--*/
02276 VOID
02277 FASTCALL
02278 ExReleaseResourceAndLeaveCriticalRegion(IN PERESOURCE Resource)
02279 {
02280     /* Release the resource */
02281     ExReleaseResourceLite(Resource);
02282 
02283     /* Leave critical region */
02284     KeLeaveCriticalRegion();
02285 }

Generated on Sun May 27 2012 04:22:20 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.