Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenresource.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
1.7.6.1
|