Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

resource.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1994 Microsoft Corporation 00004 00005 Module Name: 00006 00007 resource.c 00008 00009 Abstract: 00010 00011 This module implements the executive functions to acquire and release 00012 a shared resource. 00013 00014 N.B. These routines, in some cases, use "fast locks" to guarantee 00015 mutual exclusion. On MP and debug systems, fast locks are 00016 implemented as spinlocks (in UP debug systems raise/lower IRQL 00017 used). For UP non-debug systems, fast locks are implemented by 00018 DISABLING INTERRUPTS. 00019 00020 Author: 00021 00022 Gary D. Kimura [GaryKi] 25-Jun-1989 00023 00024 David N. Cutler (davec) 20-Mar-1994 00025 Substantially rewritten to make fastlock optimizations portable 00026 across all platforms and to improve the algorithms used to be 00027 perfectly synchronized. 00028 00029 Environment: 00030 00031 Kernel mode only. 00032 00033 Revision History: 00034 00035 --*/ 00036 00037 //#define DBG 1 00038 //#define _COLLECT_RESOURCE_DATA_ 1 00039 00040 #include "exp.h" 00041 #pragma hdrstop 00042 #include "nturtl.h" 00043 00044 // 00045 // Define local macros to test resource state. 00046 // 00047 00048 #define IsExclusiveWaiting(a) ((a)->NumberOfExclusiveWaiters != 0) 00049 #define IsSharedWaiting(a) ((a)->NumberOfSharedWaiters != 0) 00050 #define IsOwnedExclusive(a) (((a)->Flag & ResourceOwnedExclusive) != 0) 00051 #define IsBoostAllowed(a) (((a)->Flag & DisablePriorityBoost) == 0) 00052 00053 // 00054 // Define priority boost flags. 00055 // 00056 00057 #define DisablePriorityBoost 0x08 00058 00059 // 00060 // Define resource assertion macro. 00061 // 00062 00063 #if DBG 00064 00065 VOID 00066 ExpAssertResource( 00067 IN PERESOURCE Resource 00068 ); 00069 00070 #define ASSERT_RESOURCE(_Resource) ExpAssertResource(_Resource) 00071 00072 #else 00073 00074 #define ASSERT_RESOURCE(_Resource) 00075 00076 #endif 00077 00078 00079 00080 // 00081 // Define private function prototypes. 00082 // 00083 00084 VOID 00085 FASTCALL 00086 ExpWaitForResource ( 00087 IN PERESOURCE Resource, 00088 IN PVOID Object 00089 ); 00090 00091 POWNER_ENTRY 00092 FASTCALL 00093 ExpFindCurrentThread( 00094 IN PERESOURCE Resource, 00095 IN ERESOURCE_THREAD CurrentThread 00096 ); 00097 00098 // 00099 // Resource wait time out value. 00100 // 00101 00102 LARGE_INTEGER ExpTimeout; 00103 00104 // 00105 // Consecutive time outs before message. 00106 // 00107 00108 ULONG ExpResourceTimeoutCount = 648000; 00109 00110 // 00111 // Global spinlock to guard access to resource lists. 00112 // 00113 00114 KSPIN_LOCK ExpResourceSpinLock; 00115 00116 // 00117 // Resource list used to record all resource in the system. 00118 // 00119 00120 LIST_ENTRY ExpSystemResourcesList; 00121 00122 // 00123 // Define executive resource performance data. 00124 // 00125 00126 #if defined(_COLLECT_RESOURCE_DATA_) 00127 00128 #define ExpIncrementCounter(Member) ExpResourcePerformanceData.Member += 1 00129 00130 RESOURCE_PERFORMANCE_DATA ExpResourcePerformanceData; 00131 00132 #else 00133 00134 #define ExpIncrementCounter(Member) 00135 00136 #endif 00137 00138 // 00139 // Put code in the appropriate sections. 00140 // 00141 00142 #ifdef ALLOC_PRAGMA 00143 00144 #pragma alloc_text(INIT, ExpResourceInitialization) 00145 #pragma alloc_text(PAGELK, ExQuerySystemLockInformation) 00146 00147 #endif 00148 00149 BOOLEAN 00150 ExpResourceInitialization( 00151 VOID 00152 ) 00153 00154 /*++ 00155 00156 Routine Description: 00157 00158 This function initializes global data during system initialization. 00159 00160 Arguments: 00161 00162 None. 00163 00164 Return Value: 00165 00166 BOOLEAN - TRUE 00167 00168 --*/ 00169 00170 { 00171 00172 ULONG Index; 00173 00174 // 00175 // Initialize resource timeout value, the system resource listhead, 00176 // and the resource spinlock. 00177 // 00178 00179 ExpTimeout.QuadPart = Int32x32To64(4 * 1000, -10000); 00180 InitializeListHead(&ExpSystemResourcesList); 00181 KeInitializeSpinLock(&ExpResourceSpinLock); 00182 00183 // 00184 // Initialize resource performance data. 00185 // 00186 00187 #if defined(_COLLECT_RESOURCE_DATA_) 00188 00189 ExpResourcePerformanceData.ActiveResourceCount = 0; 00190 ExpResourcePerformanceData.TotalResourceCount = 0; 00191 ExpResourcePerformanceData.ExclusiveAcquire = 0; 00192 ExpResourcePerformanceData.SharedFirstLevel = 0; 00193 ExpResourcePerformanceData.SharedSecondLevel = 0; 00194 ExpResourcePerformanceData.StarveFirstLevel = 0; 00195 ExpResourcePerformanceData.StarveSecondLevel = 0; 00196 ExpResourcePerformanceData.WaitForExclusive = 0; 00197 ExpResourcePerformanceData.OwnerTableExpands = 0; 00198 ExpResourcePerformanceData.MaximumTableExpand = 0; 00199 for (Index = 0; Index < RESOURCE_HASH_TABLE_SIZE; Index += 1) { 00200 InitializeListHead(&ExpResourcePerformanceData.HashTable[Index]); 00201 } 00202 00203 #endif 00204 00205 return TRUE; 00206 } 00207 00208 NTSTATUS 00209 ExInitializeResourceLite( 00210 IN PERESOURCE Resource 00211 ) 00212 00213 /*++ 00214 00215 Routine Description: 00216 00217 This routine initializes the specified resource. 00218 00219 Arguments: 00220 00221 Resource - Supplies a pointer to the resource to initialize. 00222 00223 Return Value: 00224 00225 STATUS_SUCCESS. 00226 00227 --*/ 00228 00229 { 00230 00231 PVOID CallersCaller; 00232 00233 ASSERT(MmDeterminePoolType(Resource) == NonPagedPool); 00234 00235 // 00236 // Initialize the specified resource. 00237 // 00238 // N.B. All fields are initialized to zero (NULL pointers) except 00239 // the list entry and spinlock. 00240 // 00241 00242 RtlZeroMemory(Resource, sizeof(ERESOURCE)); 00243 KeInitializeSpinLock(&Resource->SpinLock); 00244 00245 #if i386 && !FPO 00246 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) { 00247 Resource->CreatorBackTraceIndex = RtlLogStackBackTrace(); 00248 } 00249 else { 00250 Resource->CreatorBackTraceIndex = 0; 00251 } 00252 #endif // i386 && !FPO 00253 ExInterlockedInsertTailList(&ExpSystemResourcesList, 00254 &Resource->SystemResourcesList, 00255 &ExpResourceSpinLock); 00256 00257 // 00258 // Initialize performance data entry for the resource. 00259 // 00260 00261 #if defined(_COLLECT_RESOURCE_DATA_) 00262 00263 RtlGetCallersAddress(&Resource->Address, &CallersCaller); 00264 ExpResourcePerformanceData.TotalResourceCount += 1; 00265 ExpResourcePerformanceData.ActiveResourceCount += 1; 00266 00267 #endif 00268 00269 return STATUS_SUCCESS; 00270 } 00271 00272 NTSTATUS 00273 ExReinitializeResourceLite( 00274 IN PERESOURCE Resource 00275 ) 00276 00277 /*++ 00278 00279 Routine Description: 00280 00281 This routine reinitializes the specified resource. 00282 00283 Arguments: 00284 00285 Resource - Supplies a pointer to the resource to initialize. 00286 00287 Return Value: 00288 00289 STATUS_SUCCESS. 00290 00291 --*/ 00292 00293 { 00294 00295 PKEVENT Event; 00296 ULONG Index; 00297 POWNER_ENTRY OwnerTable; 00298 PKSEMAPHORE Semaphore; 00299 ULONG TableSize; 00300 00301 ASSERT(MmDeterminePoolType(Resource) == NonPagedPool); 00302 00303 // 00304 // If the resource has an owner table, then zero the owner table. 00305 // 00306 00307 OwnerTable = Resource->OwnerTable; 00308 if (OwnerTable != NULL) { 00309 TableSize = OwnerTable->TableSize; 00310 for (Index = 1; Index < TableSize; Index += 1) { 00311 OwnerTable[Index].OwnerThread = 0; 00312 OwnerTable[Index].OwnerCount = 0; 00313 } 00314 } 00315 00316 // 00317 // Set the active count and flags to zero. 00318 // 00319 00320 Resource->ActiveCount = 0; 00321 Resource->Flag = 0; 00322 00323 // 00324 // If the resource has a shared waiter semaphore, then reinitialize 00325 // it. 00326 // 00327 00328 Semaphore = Resource->SharedWaiters; 00329 if (Semaphore != NULL) { 00330 KeInitializeSemaphore(Semaphore, 0, MAXLONG); 00331 } 00332 00333 // 00334 // If the resource has a exclusive waiter event, then reinitialize 00335 // it. 00336 // 00337 00338 Event = Resource->ExclusiveWaiters; 00339 if (Event != NULL) { 00340 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 00341 } 00342 00343 // 00344 // Initialize the builtin owner table. 00345 // 00346 00347 Resource->OwnerThreads[0].OwnerThread = 0; 00348 Resource->OwnerThreads[0].OwnerCount = 0; 00349 Resource->OwnerThreads[1].OwnerThread = 0; 00350 Resource->OwnerThreads[1].OwnerCount = 0; 00351 00352 // 00353 // Set the contention count, number of shared waiters, and number 00354 // of exclusive waiters to zero. 00355 // 00356 00357 Resource->ContentionCount = 0; 00358 Resource->NumberOfSharedWaiters = 0; 00359 Resource->NumberOfExclusiveWaiters = 0; 00360 00361 // 00362 // Reinitialize the resource spinlock. 00363 // 00364 00365 KeInitializeSpinLock(&Resource->SpinLock); 00366 return STATUS_SUCCESS; 00367 } 00368 00369 VOID 00370 ExDisableResourceBoostLite( 00371 IN PERESOURCE Resource 00372 ) 00373 00374 /*++ 00375 00376 Routine Description: 00377 00378 This routine disables priority inversion boosting for the specified 00379 resource. 00380 00381 Arguments: 00382 00383 Resource - Supplies a pointer to the resource for which priority 00384 boosting is disabled. 00385 00386 Return Value: 00387 00388 None. 00389 00390 --*/ 00391 00392 { 00393 00394 KIRQL OldIrql; 00395 00396 // 00397 // Disable priority boosts for the specified resource. 00398 // 00399 00400 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 00401 00402 ASSERT_RESOURCE(Resource); 00403 00404 Resource->Flag |= DisablePriorityBoost; 00405 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00406 } 00407 00408 BOOLEAN 00409 FASTCALL 00410 ExpAcquireResourceExclusiveLite( 00411 IN PERESOURCE Resource, 00412 IN KIRQL OldIrql 00413 ) 00414 00415 /*++ 00416 00417 Routine Description: 00418 00419 This routine acquires the specified resource for exclusive access. 00420 00421 N.B. This routine uses fast locking. 00422 00423 N.B. This routine is called with the fast lock for the resource 00424 held. 00425 00426 Arguments: 00427 00428 Resource - Supplies a pointer to the resource that is acquired 00429 for exclusive access. 00430 00431 OldIrql - Supplies the previous IRQL. 00432 00433 Return Value: 00434 00435 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise. 00436 00437 --*/ 00438 00439 { 00440 00441 PKEVENT Event; 00442 00443 // 00444 // If the exclusive wait event has not yet been allocated, then the 00445 // long path code must be taken. 00446 // 00447 00448 if (Resource->ExclusiveWaiters == NULL) { 00449 00450 // 00451 // Allocate an exclusive wait event. 00452 // 00453 // N.B. This path is not optimal, but is only ever executed once 00454 // per resource. 00455 // 00456 00457 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00458 ExAcquireSpinLock(&Resource->SpinLock, &OldIrql); 00459 if (Resource->ExclusiveWaiters == NULL) { 00460 Event = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 00461 sizeof(KEVENT), 00462 'vEeR'); 00463 00464 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 00465 Resource->ExclusiveWaiters = Event; 00466 } 00467 00468 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00469 return ExAcquireResourceExclusiveLite(Resource, TRUE); 00470 } 00471 00472 // 00473 // Wait for exclusive access to the resource to be granted and set the 00474 // owner thread. 00475 // 00476 00477 Resource->NumberOfExclusiveWaiters += 1; 00478 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00479 ExpWaitForResource(Resource, Resource->ExclusiveWaiters); 00480 00481 // 00482 // N.B. It is "safe" to store the owner thread without obtaining any 00483 // locks since the thread has already been granted exclusive 00484 // ownership. 00485 // 00486 00487 Resource->OwnerThreads[0].OwnerThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 00488 return TRUE; 00489 } 00490 00491 BOOLEAN 00492 ExAcquireResourceExclusiveLite( 00493 IN PERESOURCE Resource, 00494 IN BOOLEAN Wait 00495 ) 00496 00497 /*++ 00498 00499 Routine Description: 00500 00501 The routine acquires the specified resource for exclusive access. 00502 00503 N.B. This routine uses fast locking. 00504 00505 Arguments: 00506 00507 Resource - Supplies a pointer to the resource that is acquired 00508 for exclusive access. 00509 00510 Wait - A boolean value that specifies whether to wait for the 00511 resource to become available if access cannot be granted 00512 immediately. 00513 00514 Return Value: 00515 00516 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise. 00517 00518 --*/ 00519 00520 { 00521 00522 ERESOURCE_THREAD CurrentThread; 00523 PKEVENT Event; 00524 KIRQL OldIrql = 0; 00525 BOOLEAN Result; 00526 00527 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0); 00528 00529 // 00530 // Acquire exclusive access to the specified resource. 00531 // 00532 00533 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 00534 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 00535 00536 ASSERT(KeIsExecutingDpc() == FALSE); 00537 ASSERT_RESOURCE(Resource); 00538 00539 // 00540 // If the active count of the resource is zero, then there is neither 00541 // an exclusive owner nor a shared owner and access to the resource can 00542 // be immediately granted. Otherwise, there is either a shared owner or 00543 // an exclusive owner. 00544 // 00545 00546 ExpIncrementCounter(ExclusiveAcquire); 00547 if (Resource->ActiveCount != 0) { 00548 00549 // 00550 // The resource is either owned exclusive or shared. 00551 // 00552 // If the resource is owned exclusive and the current thread is the 00553 // owner, then increment the recursion count. 00554 // 00555 00556 if (IsOwnedExclusive(Resource) && 00557 (Resource->OwnerThreads[0].OwnerThread == CurrentThread)) { 00558 Resource->OwnerThreads[0].OwnerCount += 1; 00559 Result = TRUE; 00560 00561 } else { 00562 00563 // 00564 // The resource is either owned exclusive by some other thread, 00565 // or owned shared. 00566 // 00567 // If wait is not specified, then return that the resource was 00568 // not acquired. Otherwise, wait for exclusive access to the 00569 // resource to be granted. 00570 // 00571 00572 if (Wait == FALSE) { 00573 Result = FALSE; 00574 00575 } else { 00576 return ExpAcquireResourceExclusiveLite(Resource, OldIrql); 00577 } 00578 } 00579 00580 } else { 00581 00582 // 00583 // The resource is not owned. 00584 // 00585 00586 Resource->Flag |= ResourceOwnedExclusive; 00587 Resource->OwnerThreads[0].OwnerThread = CurrentThread; 00588 Resource->OwnerThreads[0].OwnerCount = 1; 00589 Resource->ActiveCount = 1; 00590 Result = TRUE; 00591 } 00592 00593 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00594 return Result; 00595 } 00596 00597 BOOLEAN 00598 ExTryToAcquireResourceExclusiveLite( 00599 IN PERESOURCE Resource 00600 ) 00601 00602 /*++ 00603 00604 Routine Description: 00605 00606 The routine attempts to acquire the specified resource for exclusive 00607 access. 00608 00609 N.B. This routine uses fast locking. 00610 00611 Arguments: 00612 00613 Resource - Supplies a pointer to the resource that is acquired 00614 for exclusive access. 00615 00616 Return Value: 00617 00618 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise. 00619 00620 --*/ 00621 00622 { 00623 00624 ERESOURCE_THREAD CurrentThread; 00625 KIRQL OldIrql; 00626 BOOLEAN Result; 00627 00628 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0); 00629 00630 // 00631 // Attempt to acquire exclusive access to the specified resource. 00632 // 00633 00634 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 00635 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 00636 00637 ASSERT(KeIsExecutingDpc() == FALSE); 00638 ASSERT_RESOURCE(Resource); 00639 00640 // 00641 // If the active count of the resource is zero, then there is neither 00642 // an exclusive owner nor a shared owner and access to the resource can 00643 // be immediately granted. Otherwise, if the resource is owned exclusive 00644 // and the current thread is the owner, then access to the resource can 00645 // be immediately granted. Otherwise, access cannot be granted. 00646 // 00647 00648 Result = FALSE; 00649 if (Resource->ActiveCount == 0) { 00650 ExpIncrementCounter(ExclusiveAcquire); 00651 Resource->Flag |= ResourceOwnedExclusive; 00652 Resource->OwnerThreads[0].OwnerThread = CurrentThread; 00653 Resource->OwnerThreads[0].OwnerCount = 1; 00654 Resource->ActiveCount = 1; 00655 Result = TRUE; 00656 00657 } else if (IsOwnedExclusive(Resource) && 00658 (Resource->OwnerThreads[0].OwnerThread == CurrentThread)) { 00659 ExpIncrementCounter(ExclusiveAcquire); 00660 Resource->OwnerThreads[0].OwnerCount += 1; 00661 Result = TRUE; 00662 } 00663 00664 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00665 return Result; 00666 } 00667 00668 #if defined(NT_UP) && !DBG 00669 00670 BOOLEAN 00671 ExpAcquireResourceSharedLite( 00672 IN PERESOURCE Resource, 00673 IN BOOLEAN Wait 00674 ); 00675 00676 BOOLEAN 00677 ExAcquireResourceSharedLite( 00678 IN PERESOURCE Resource, 00679 IN BOOLEAN Wait 00680 ) 00681 00682 /*++ 00683 00684 Routine Description: 00685 00686 The routine acquires the specified resource for shared access. 00687 00688 N.B. This routine uses fast locking. 00689 00690 Arguments: 00691 00692 Resource - Supplies a pointer to the resource that is acquired 00693 for shared access. 00694 00695 Wait - A boolean value that specifies whether to wait for the 00696 resource to become available if access cannot be granted 00697 immediately. 00698 00699 Return Value: 00700 00701 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 00702 00703 --*/ 00704 00705 { 00706 00707 ERESOURCE_THREAD CurrentThread; 00708 KIRQL OldIrql; 00709 00710 // 00711 // Acquire exclusive access to the specified resource. 00712 // 00713 00714 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 00715 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 00716 00717 // 00718 // If the active count of the resource is zero, then there is neither 00719 // an exclusive owner nor a shared owner and access to the resource can 00720 // be immediately granted. 00721 // 00722 00723 if (Resource->ActiveCount == 0) { 00724 Resource->OwnerThreads[1].OwnerThread = CurrentThread; 00725 Resource->OwnerThreads[1].OwnerCount = 1; 00726 Resource->ActiveCount = 1; 00727 ExpIncrementCounter(SharedFirstLevel); 00728 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00729 return TRUE; 00730 } 00731 00732 // 00733 // The resource is either owned exclusive or shared. 00734 // 00735 // If the resource is owned exclusive and the current thread is the 00736 // owner, then treat the shared request as an exclusive request and 00737 // increment the recursion count. Otherwise, it is owned shared. 00738 // 00739 00740 if (IsOwnedExclusive(Resource) && 00741 (Resource->OwnerThreads[0].OwnerThread == CurrentThread)) { 00742 Resource->OwnerThreads[0].OwnerCount += 1; 00743 ExpIncrementCounter(SharedFirstLevel); 00744 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00745 return TRUE; 00746 } 00747 00748 // 00749 // The fast path could not be used - release the fast lock and take 00750 // the long way. 00751 // 00752 00753 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00754 return ExpAcquireResourceSharedLite(Resource, Wait); 00755 } 00756 00757 #define ExAcquireResourceSharedLite ExpAcquireResourceSharedLite 00758 00759 #endif 00760 00761 BOOLEAN 00762 ExAcquireResourceSharedLite( 00763 IN PERESOURCE Resource, 00764 IN BOOLEAN Wait 00765 ) 00766 00767 /*++ 00768 00769 Routine Description: 00770 00771 The routine acquires the specified resource for shared access. 00772 00773 Arguments: 00774 00775 Resource - Supplies a pointer to the resource that is acquired 00776 for shared access. 00777 00778 Wait - A boolean value that specifies whether to wait for the 00779 resource to become available if access cannot be granted 00780 immediately. 00781 00782 Return Value: 00783 00784 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 00785 00786 --*/ 00787 00788 { 00789 00790 ERESOURCE_THREAD CurrentThread; 00791 KIRQL OldIrql; 00792 POWNER_ENTRY OwnerEntry; 00793 PKSEMAPHORE Semaphore; 00794 00795 // 00796 // Acquire exclusive access to the specified resource. 00797 // 00798 00799 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 00800 ExAcquireSpinLock(&Resource->SpinLock, &OldIrql); 00801 00802 ASSERT(KeIsExecutingDpc() == FALSE); 00803 ASSERT_RESOURCE(Resource); 00804 00805 ExpIncrementCounter(SharedSecondLevel); 00806 00807 // 00808 // If the active count of the resource is zero, then there is neither 00809 // an exclusive owner nor a shared owner and access to the resource can 00810 // be immediately granted. 00811 // 00812 00813 if (Resource->ActiveCount == 0) { 00814 Resource->OwnerThreads[1].OwnerThread = CurrentThread; 00815 Resource->OwnerThreads[1].OwnerCount = 1; 00816 Resource->ActiveCount = 1; 00817 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00818 return TRUE; 00819 } 00820 00821 // 00822 // The resource is either owned exclusive or shared. 00823 // 00824 // If the resource is owned exclusive and the current thread is the 00825 // owner, then treat the shared request as an exclusive request and 00826 // increment the recursion count. Otherwise, it is owned shared. 00827 // 00828 00829 if (IsOwnedExclusive(Resource)) { 00830 if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 00831 Resource->OwnerThreads[0].OwnerCount += 1; 00832 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00833 return TRUE; 00834 } 00835 00836 // 00837 // Find an empty entry in the thread array. 00838 // 00839 00840 OwnerEntry = ExpFindCurrentThread(Resource, 0); 00841 00842 } else { 00843 00844 // 00845 // The resource is owned shared. 00846 // 00847 // If the current thread already has acquired the resource for 00848 // shared access, then increment the recursion count. Otherwise 00849 // grant shared access if there are no exclusive waiters. 00850 // 00851 00852 OwnerEntry = ExpFindCurrentThread(Resource, CurrentThread); 00853 if (OwnerEntry->OwnerThread == CurrentThread) { 00854 OwnerEntry->OwnerCount += 1; 00855 00856 ASSERT(OwnerEntry->OwnerCount != 0); 00857 00858 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00859 return TRUE; 00860 } 00861 00862 // 00863 // If there are no exclusive waiters, then grant shared access 00864 // to the resource. Otherwise, wait for the resource to become 00865 // available. 00866 // 00867 00868 if (IsExclusiveWaiting(Resource) == FALSE) { 00869 OwnerEntry->OwnerThread = CurrentThread; 00870 OwnerEntry->OwnerCount = 1; 00871 Resource->ActiveCount += 1; 00872 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00873 return TRUE; 00874 } 00875 } 00876 00877 // 00878 // The resource is either owned exclusive by some other thread, or 00879 // owned shared by some other threads, but there is an exclusive 00880 // waiter and the current thread does not already have shared access 00881 // to the resource. 00882 // 00883 // If wait is not specified, then return that the resource was 00884 // not acquired. 00885 // 00886 00887 if (Wait == FALSE) { 00888 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00889 return FALSE; 00890 } 00891 00892 // 00893 // If the shared wait semaphore has not yet been allocated, then allocate 00894 // and initialize it. 00895 // 00896 00897 if (Resource->SharedWaiters == NULL) { 00898 Semaphore = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 00899 sizeof(KSEMAPHORE), 00900 'eSeR'); 00901 00902 KeInitializeSemaphore(Semaphore, 0, MAXLONG); 00903 Resource->SharedWaiters = Semaphore; 00904 } 00905 00906 // 00907 // Wait for shared access to the resource to be granted and increment 00908 // the recursion count. 00909 // 00910 00911 OwnerEntry->OwnerThread = CurrentThread; 00912 OwnerEntry->OwnerCount = 1; 00913 Resource->NumberOfSharedWaiters += 1; 00914 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 00915 ExpWaitForResource(Resource, Resource->SharedWaiters); 00916 return TRUE; 00917 } 00918 00919 #if defined(NT_UP) && !DBG 00920 00921 BOOLEAN 00922 ExpAcquireSharedStarveExclusive( 00923 IN PERESOURCE Resource, 00924 IN BOOLEAN Wait 00925 ); 00926 00927 BOOLEAN 00928 ExAcquireSharedStarveExclusive( 00929 IN PERESOURCE Resource, 00930 IN BOOLEAN Wait 00931 ) 00932 00933 /*++ 00934 00935 Routine Description: 00936 00937 This routine acquires the specified resource for shared access and 00938 does not wait for any pending exclusive owners. 00939 00940 N.B. This routine uses fast locking. 00941 00942 Arguments: 00943 00944 Resource - Supplies a pointer to the resource that is acquired 00945 for shared access. 00946 00947 Wait - A boolean value that specifies whether to wait for the 00948 resource to become available if access cannot be granted 00949 immediately. 00950 00951 Return Value: 00952 00953 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 00954 00955 --*/ 00956 00957 { 00958 00959 ERESOURCE_THREAD CurrentThread; 00960 KIRQL OldIrql; 00961 00962 // 00963 // Acquire exclusive access to the specified resource. 00964 // 00965 00966 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 00967 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 00968 00969 // 00970 // If the active count of the resource is zero, then there is neither 00971 // an exclusive owner nor a shared owner and access to the resource can 00972 // be immediately granted. 00973 // 00974 00975 if (Resource->ActiveCount == 0) { 00976 Resource->OwnerThreads[1].OwnerThread = CurrentThread; 00977 Resource->OwnerThreads[1].OwnerCount = 1; 00978 Resource->ActiveCount = 1; 00979 ExpIncrementCounter(StarveFirstLevel); 00980 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00981 return TRUE; 00982 } 00983 00984 // 00985 // The resource is either owned exclusive or shared. 00986 // 00987 // If the resource is owned exclusive and the current thread is the 00988 // owner, then treat the shared request as an exclusive request and 00989 // increment the recursion count. Otherwise, it is owned shared. 00990 // 00991 00992 if (IsOwnedExclusive(Resource) && 00993 (Resource->OwnerThreads[0].OwnerThread == CurrentThread)) { 00994 Resource->OwnerThreads[0].OwnerCount += 1; 00995 ExpIncrementCounter(StarveFirstLevel); 00996 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 00997 return TRUE; 00998 } 00999 01000 // 01001 // The fast path could not be taken - release the fast lock and take 01002 // the long way. 01003 // 01004 01005 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01006 return ExpAcquireSharedStarveExclusive(Resource, Wait); 01007 } 01008 01009 #define ExAcquireSharedStarveExclusive ExpAcquireSharedStarveExclusive 01010 01011 #endif 01012 01013 BOOLEAN 01014 ExAcquireSharedStarveExclusive( 01015 IN PERESOURCE Resource, 01016 IN BOOLEAN Wait 01017 ) 01018 /*++ 01019 01020 Routine Description: 01021 01022 This routine acquires the specified resource for shared access and 01023 does not wait for any pending exclusive owners. 01024 01025 Arguments: 01026 01027 Resource - Supplies a pointer to the resource that is acquired 01028 for shared access. 01029 01030 Wait - A boolean value that specifies whether to wait for the 01031 resource to become available if access cannot be granted 01032 immediately. 01033 01034 Return Value: 01035 01036 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 01037 01038 --*/ 01039 01040 { 01041 01042 ERESOURCE_THREAD CurrentThread; 01043 KIRQL OldIrql; 01044 POWNER_ENTRY OwnerEntry; 01045 PKSEMAPHORE Semaphore; 01046 01047 // 01048 // Acquire exclusive access to the specified resource. 01049 // 01050 01051 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 01052 ExAcquireSpinLock(&Resource->SpinLock, &OldIrql); 01053 01054 ASSERT(KeIsExecutingDpc() == FALSE); 01055 ASSERT_RESOURCE(Resource); 01056 01057 ExpIncrementCounter(StarveSecondLevel); 01058 01059 // 01060 // If the active count of the resource is zero, then there is neither 01061 // an exclusive owner nor a shared owner and access to the resource can 01062 // be immediately granted. 01063 // 01064 01065 if (Resource->ActiveCount == 0) { 01066 Resource->OwnerThreads[1].OwnerThread = CurrentThread; 01067 Resource->OwnerThreads[1].OwnerCount = 1; 01068 Resource->ActiveCount = 1; 01069 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01070 return TRUE; 01071 } 01072 01073 // 01074 // The resource is either owned exclusive or shared. 01075 // 01076 // If the resource is owned exclusive and the current thread is the 01077 // owner, then treat the shared request as an exclusive request and 01078 // increment the recursion count. Otherwise, it is owned shared. 01079 // 01080 01081 if (IsOwnedExclusive(Resource)) { 01082 if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 01083 Resource->OwnerThreads[0].OwnerCount += 1; 01084 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01085 return TRUE; 01086 } 01087 01088 // 01089 // Find an empty entry in the thread array. 01090 // 01091 01092 OwnerEntry = ExpFindCurrentThread(Resource, 0); 01093 01094 } else { 01095 01096 // 01097 // The resource is owned shared. 01098 // 01099 // If the current thread already has acquired the resource for 01100 // shared access, then increment the recursion count. Otherwise 01101 // grant shared access to the current thread 01102 // 01103 01104 OwnerEntry = ExpFindCurrentThread(Resource, CurrentThread); 01105 if (OwnerEntry->OwnerThread == CurrentThread) { 01106 OwnerEntry->OwnerCount += 1; 01107 01108 ASSERT(OwnerEntry->OwnerCount != 0); 01109 01110 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01111 return TRUE; 01112 } 01113 01114 // 01115 // Grant the current thread shared access to the resource. 01116 // 01117 01118 OwnerEntry->OwnerThread = CurrentThread; 01119 OwnerEntry->OwnerCount = 1; 01120 Resource->ActiveCount += 1; 01121 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01122 return TRUE; 01123 } 01124 01125 // 01126 // The resource is owned exclusive by some other thread. 01127 // 01128 // If wait is not specified, then return that the resource was 01129 // not acquired. 01130 // 01131 01132 if (Wait == FALSE) { 01133 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01134 return FALSE; 01135 } 01136 01137 // 01138 // If the shared wait semaphore has not yet been allocated, then allocate 01139 // and initialize it. 01140 // 01141 01142 if (Resource->SharedWaiters == NULL) { 01143 Semaphore = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 01144 sizeof(KSEMAPHORE), 01145 'eSeR'); 01146 01147 KeInitializeSemaphore(Semaphore, 0, MAXLONG); 01148 Resource->SharedWaiters = Semaphore; 01149 } 01150 01151 // 01152 // Wait for shared access to the resource to be granted and increment 01153 // the recursion count. 01154 // 01155 01156 OwnerEntry->OwnerThread = CurrentThread; 01157 OwnerEntry->OwnerCount = 1; 01158 Resource->NumberOfSharedWaiters += 1; 01159 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01160 ExpWaitForResource(Resource, Resource->SharedWaiters); 01161 return TRUE; 01162 } 01163 01164 BOOLEAN 01165 ExAcquireSharedWaitForExclusive( 01166 IN PERESOURCE Resource, 01167 IN BOOLEAN Wait 01168 ) 01169 /*++ 01170 01171 Routine Description: 01172 01173 This routine acquires the specified resource for shared access, but 01174 waits for any pending exclusive owners. 01175 01176 Arguments: 01177 01178 Resource - Supplies a pointer to the resource that is acquired 01179 for shared access. 01180 01181 Wait - A boolean value that specifies whether to wait for the 01182 resource to become available if access cannot be granted 01183 immediately. 01184 01185 Return Value: 01186 01187 BOOLEAN - TRUE if the resource is acquired and FALSE otherwise 01188 01189 --*/ 01190 01191 { 01192 01193 ERESOURCE_THREAD CurrentThread; 01194 KIRQL OldIrql; 01195 POWNER_ENTRY OwnerEntry; 01196 PKSEMAPHORE Semaphore; 01197 01198 // 01199 // Acquire exclusive access to the specified resource. 01200 // 01201 01202 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 01203 ExAcquireSpinLock(&Resource->SpinLock, &OldIrql); 01204 01205 ASSERT(KeIsExecutingDpc() == FALSE); 01206 ASSERT_RESOURCE(Resource); 01207 01208 ExpIncrementCounter(WaitForExclusive); 01209 01210 // 01211 // If the active count of the resource is zero, then there is neither 01212 // an exclusive owner nor a shared owner and access to the resource can 01213 // be immediately granted. 01214 // 01215 01216 if (Resource->ActiveCount == 0) { 01217 Resource->OwnerThreads[1].OwnerThread = CurrentThread; 01218 Resource->OwnerThreads[1].OwnerCount = 1; 01219 Resource->ActiveCount = 1; 01220 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01221 return TRUE; 01222 } 01223 01224 // 01225 // The resource is either owned exclusive or shared. 01226 // 01227 // If the resource is owned exclusive and the current thread is the 01228 // owner, then treat the shared request as an exclusive request and 01229 // increment the recursion count. Otherwise, it is owned shared. 01230 // 01231 01232 if (IsOwnedExclusive(Resource)) { 01233 if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 01234 Resource->OwnerThreads[0].OwnerCount += 1; 01235 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01236 return TRUE; 01237 } 01238 01239 // 01240 // Find an empty entry in the thread array. 01241 // 01242 01243 OwnerEntry = ExpFindCurrentThread(Resource, 0); 01244 01245 } else { 01246 01247 // 01248 // The resource is owned shared. 01249 // 01250 // If there is an exclusive waiter, then wait for the exclusive 01251 // waiter to gain access to the resource, then acquire the resource 01252 // shared without regard to exclusive waiters. Otherwise, if the 01253 // current thread already has acquired the resource for shared access, 01254 // then increment the recursion count. Otherwise grant shared access 01255 // to the current thread 01256 // 01257 01258 if (IsExclusiveWaiting(Resource)) { 01259 01260 // 01261 // The resource is shared, but there is an exclusive waiter. 01262 // 01263 // If wait is not specified, then return that the resource was 01264 // not acquired. 01265 // 01266 01267 if (Wait == FALSE) { 01268 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01269 return FALSE; 01270 } 01271 01272 // 01273 // If the shared wait semaphore has not yet been allocated, then 01274 // allocate and initialize it. 01275 // 01276 01277 if (Resource->SharedWaiters == NULL) { 01278 Semaphore = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 01279 sizeof(KSEMAPHORE), 01280 'eSeR'); 01281 01282 KeInitializeSemaphore(Semaphore, 0, MAXLONG); 01283 Resource->SharedWaiters = Semaphore; 01284 } 01285 01286 // 01287 // Increment the number of shared waiters and wait for shared 01288 // access to the resource to be granted to some other set of 01289 // threads, and then acquire the resource shared without regard 01290 // to exclusive access. 01291 // 01292 // N.B. The resource is left in a state such that the calling 01293 // thread does not have a reference in the owner table 01294 // for the requested access even though the active count 01295 // is incremented when control is returned. However, the 01296 // resource is owned shared at this point, so an owner 01297 // entry can simply be allocated and the owner count set 01298 // to one. 01299 // 01300 01301 Resource->NumberOfSharedWaiters += 1; 01302 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01303 ExpWaitForResource(Resource, Resource->SharedWaiters); 01304 01305 // 01306 // Reacquire the resource spin lock, allocate an owner entry, 01307 // and initialize the owner count to one. The active count 01308 // was already incremented when shared access was granted. 01309 // 01310 01311 ExAcquireSpinLock(&Resource->SpinLock, &OldIrql); 01312 01313 ASSERT(IsOwnedExclusive(Resource) == FALSE); 01314 ASSERT(Resource->ActiveCount > 0); 01315 01316 OwnerEntry = ExpFindCurrentThread(Resource, CurrentThread); 01317 01318 ASSERT(OwnerEntry->OwnerThread != CurrentThread); 01319 01320 OwnerEntry->OwnerThread = CurrentThread; 01321 OwnerEntry->OwnerCount = 1; 01322 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01323 return TRUE; 01324 01325 } else { 01326 OwnerEntry = ExpFindCurrentThread(Resource, CurrentThread); 01327 if (OwnerEntry->OwnerThread == CurrentThread) { 01328 OwnerEntry->OwnerCount += 1; 01329 01330 ASSERT(OwnerEntry->OwnerCount != 0); 01331 01332 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01333 return TRUE; 01334 } 01335 01336 // 01337 // Grant the current thread shared access to the resource. 01338 // 01339 01340 OwnerEntry->OwnerThread = CurrentThread; 01341 OwnerEntry->OwnerCount = 1; 01342 Resource->ActiveCount += 1; 01343 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01344 return TRUE; 01345 } 01346 } 01347 01348 // 01349 // The resource is owned exclusive by some other thread. 01350 // 01351 // If wait is not specified, then return that the resource was 01352 // not acquired. 01353 // 01354 01355 if (Wait == FALSE) { 01356 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01357 return FALSE; 01358 } 01359 01360 // 01361 // If the shared wait semaphore has not yet been allocated, then allocate 01362 // and initialize it. 01363 // 01364 01365 if (Resource->SharedWaiters == NULL) { 01366 Semaphore = ExAllocatePoolWithTag(NonPagedPoolMustSucceed, 01367 sizeof(KSEMAPHORE), 01368 'eSeR'); 01369 01370 KeInitializeSemaphore(Semaphore, 0, MAXLONG); 01371 Resource->SharedWaiters = Semaphore; 01372 } 01373 01374 // 01375 // Wait for shared access to the resource to be granted and increment 01376 // the recursion count. 01377 // 01378 01379 OwnerEntry->OwnerThread = CurrentThread; 01380 OwnerEntry->OwnerCount = 1; 01381 Resource->NumberOfSharedWaiters += 1; 01382 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 01383 ExpWaitForResource(Resource, Resource->SharedWaiters); 01384 return TRUE; 01385 } 01386 01387 VOID 01388 FASTCALL 01389 ExReleaseResourceLite( 01390 IN PERESOURCE Resource 01391 ) 01392 01393 /*++ 01394 01395 Routine Description: 01396 01397 This routine releases the specified resource for the current thread 01398 and decrements the recursion count. If the count reaches zero, then 01399 the resource may also be released. 01400 01401 N.B. This routine uses fast locking. 01402 01403 Arguments: 01404 01405 Resource - Supplies a pointer to the resource to release. 01406 01407 Return Value: 01408 01409 None. 01410 01411 --*/ 01412 01413 { 01414 01415 ERESOURCE_THREAD CurrentThread; 01416 ULONG Index; 01417 ULONG Number; 01418 KIRQL OldIrql; 01419 POWNER_ENTRY OwnerEntry, OwnerEnd; 01420 01421 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 01422 01423 // 01424 // Acquire exclusive access to the specified resource. 01425 // 01426 01427 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 01428 01429 ASSERT_RESOURCE(Resource); 01430 01431 // 01432 // If the resource is exclusively owned, then release exclusive 01433 // ownership. Otherwise, release shared ownership. 01434 // 01435 // N.B. The two release paths are split since this is such a high 01436 // frequency function. 01437 // 01438 01439 if (IsOwnedExclusive(Resource)) { 01440 01441 // if (Resource->OwnerThreads[0].OwnerThread != CurrentThread) { 01442 // KeBugCheckEx(RESOURCE_NOT_OWNED, 01443 // (ULONG_PTR)Resource, 01444 // (ULONG_PTR)CurrentThread, 01445 // (ULONG_PTR)Resource->OwnerTable, 01446 // 0x1); 01447 // } 01448 01449 // 01450 // Decrement the recursion count and check if ownership can be 01451 // released. 01452 // 01453 01454 ASSERT(Resource->OwnerThreads[0].OwnerCount > 0); 01455 01456 if (--Resource->OwnerThreads[0].OwnerCount != 0) { 01457 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01458 return; 01459 } 01460 01461 // 01462 // Clear the owner thread. 01463 // 01464 01465 Resource->OwnerThreads[0].OwnerThread = 0; 01466 01467 // 01468 // The thread recursion count reached zero so decrement the resource 01469 // active count. If the active count reaches zero, then the resource 01470 // is no longer owned and an attempt should be made to grant access to 01471 // another thread. 01472 // 01473 01474 ASSERT(Resource->ActiveCount > 0); 01475 01476 if (--Resource->ActiveCount == 0) { 01477 01478 // 01479 // If there are shared waiters, then grant shared access to the 01480 // resource. Otherwise, grant exclusive ownership if there are 01481 // exclusive waiters. 01482 // 01483 01484 if (IsSharedWaiting(Resource)) { 01485 Resource->Flag &= ~ResourceOwnedExclusive; 01486 Number = Resource->NumberOfSharedWaiters; 01487 Resource->ActiveCount = (SHORT)Number; 01488 Resource->NumberOfSharedWaiters = 0; 01489 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01490 KeReleaseSemaphore(Resource->SharedWaiters, 0, Number, FALSE); 01491 return; 01492 01493 } else if (IsExclusiveWaiting(Resource)) { 01494 Resource->OwnerThreads[0].OwnerThread = 1; 01495 Resource->OwnerThreads[0].OwnerCount = 1; 01496 Resource->ActiveCount = 1; 01497 Resource->NumberOfExclusiveWaiters -= 1; 01498 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01499 KeSetEventBoostPriority(Resource->ExclusiveWaiters, 01500 (PRKTHREAD *)&Resource->OwnerThreads[0].OwnerThread); 01501 return; 01502 } 01503 01504 Resource->Flag &= ~ResourceOwnedExclusive; 01505 } 01506 01507 } else { 01508 if (Resource->OwnerThreads[1].OwnerThread == CurrentThread) { 01509 OwnerEntry = &Resource->OwnerThreads[1]; 01510 01511 } else if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 01512 OwnerEntry = &Resource->OwnerThreads[0]; 01513 01514 } else { 01515 Index = ((PKTHREAD)(CurrentThread))->ResourceIndex; 01516 OwnerEntry = Resource->OwnerTable; 01517 01518 if (OwnerEntry == NULL) { 01519 KeBugCheckEx(RESOURCE_NOT_OWNED, 01520 (ULONG_PTR)Resource, 01521 (ULONG_PTR)CurrentThread, 01522 (ULONG_PTR)Resource->OwnerTable, 01523 0x2); 01524 } 01525 01526 // 01527 // If the resource hint is not within range or the resource 01528 // table entry does match the current thread, then search 01529 // the owner table for a match. 01530 // 01531 01532 if ((Index >= OwnerEntry->TableSize) || 01533 (OwnerEntry[Index].OwnerThread != CurrentThread)) { 01534 OwnerEnd = &OwnerEntry[OwnerEntry->TableSize]; 01535 while (1) { 01536 OwnerEntry += 1; 01537 if (OwnerEntry >= OwnerEnd) { 01538 KeBugCheckEx(RESOURCE_NOT_OWNED, 01539 (ULONG_PTR)Resource, 01540 (ULONG_PTR)CurrentThread, 01541 (ULONG_PTR)Resource->OwnerTable, 01542 0x3); 01543 } 01544 if (OwnerEntry->OwnerThread == CurrentThread) { 01545 break; 01546 } 01547 }; 01548 } else { 01549 OwnerEntry = &OwnerEntry[Index]; 01550 } 01551 } 01552 01553 // 01554 // Decrement the recursion count and check if ownership can be 01555 // released. 01556 // 01557 01558 ASSERT(OwnerEntry->OwnerThread == CurrentThread); 01559 ASSERT(OwnerEntry->OwnerCount > 0); 01560 01561 if (--OwnerEntry->OwnerCount != 0) { 01562 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01563 return; 01564 } 01565 01566 // 01567 // Clear the owner thread. 01568 // 01569 01570 OwnerEntry->OwnerThread = 0; 01571 01572 // 01573 // The thread recursion count reached zero so decrement the resource 01574 // active count. If the active count reaches zero, then the resource 01575 // is no longer owned and an attempt should be made to grant access to 01576 // another thread. 01577 // 01578 01579 ASSERT(Resource->ActiveCount > 0); 01580 01581 if (--Resource->ActiveCount == 0) { 01582 01583 // 01584 // If there are exclusive waiters, then grant exclusive access 01585 // to the resource. 01586 // 01587 01588 if (IsExclusiveWaiting(Resource)) { 01589 Resource->Flag |= ResourceOwnedExclusive; 01590 Resource->OwnerThreads[0].OwnerThread = 1; 01591 Resource->OwnerThreads[0].OwnerCount = 1; 01592 Resource->ActiveCount = 1; 01593 Resource->NumberOfExclusiveWaiters -= 1; 01594 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01595 KeSetEventBoostPriority(Resource->ExclusiveWaiters, 01596 (PRKTHREAD *)&Resource->OwnerThreads[0].OwnerThread); 01597 return; 01598 } 01599 } 01600 } 01601 01602 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01603 return; 01604 } 01605 01606 VOID 01607 ExReleaseResourceForThreadLite( 01608 IN PERESOURCE Resource, 01609 IN ERESOURCE_THREAD CurrentThread 01610 ) 01611 01612 /*++ 01613 01614 Routine Description: 01615 01616 This routine release the specified resource for the specified thread 01617 and decrements the recursion count. If the count reaches zero, then 01618 the resource may also be released. 01619 01620 N.B. This routine uses fast locking. 01621 01622 Arguments: 01623 01624 Resource - Supplies a pointer to the resource to release. 01625 01626 Thread - Supplies the thread that originally acquired the resource. 01627 01628 Return Value: 01629 01630 None. 01631 01632 --*/ 01633 01634 { 01635 01636 ULONG Index; 01637 ULONG Number; 01638 KIRQL OldIrql; 01639 POWNER_ENTRY OwnerEntry; 01640 01641 ASSERT(CurrentThread != 0); 01642 01643 // 01644 // Acquire exclusive access to the specified resource. 01645 // 01646 01647 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 01648 01649 ASSERT_RESOURCE(Resource); 01650 01651 // 01652 // If the resource is exclusively owned, then release exclusive 01653 // ownership. Otherwise, release shared ownership. 01654 // 01655 // N.B. The two release paths are split since this is such a high 01656 // frequency function. 01657 // 01658 01659 if (IsOwnedExclusive(Resource)) { 01660 01661 ASSERT(Resource->OwnerThreads[0].OwnerThread == CurrentThread); 01662 01663 // 01664 // Decrement the recursion count and check if ownership can be 01665 // released. 01666 // 01667 01668 ASSERT(Resource->OwnerThreads[0].OwnerCount > 0); 01669 01670 if (--Resource->OwnerThreads[0].OwnerCount != 0) { 01671 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01672 return; 01673 } 01674 01675 // 01676 // Clear the owner thread. 01677 // 01678 01679 Resource->OwnerThreads[0].OwnerThread = 0; 01680 01681 // 01682 // The thread recursion count reached zero so decrement the resource 01683 // active count. If the active count reaches zero, then the resource 01684 // is no longer owned and an attempt should be made to grant access to 01685 // another thread. 01686 // 01687 01688 ASSERT(Resource->ActiveCount > 0); 01689 01690 if (--Resource->ActiveCount == 0) { 01691 01692 // 01693 // If there are shared waiters, then grant shared access to the 01694 // resource. Otherwise, grant exclusive ownership if there are 01695 // exclusive waiters. 01696 // 01697 01698 if (IsSharedWaiting(Resource)) { 01699 Resource->Flag &= ~ResourceOwnedExclusive; 01700 Number = Resource->NumberOfSharedWaiters; 01701 Resource->ActiveCount = (SHORT)Number; 01702 Resource->NumberOfSharedWaiters = 0; 01703 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01704 KeReleaseSemaphore(Resource->SharedWaiters, 0, Number, FALSE); 01705 return; 01706 01707 } else if (IsExclusiveWaiting(Resource)) { 01708 Resource->OwnerThreads[0].OwnerThread = 1; 01709 Resource->OwnerThreads[0].OwnerCount = 1; 01710 Resource->ActiveCount = 1; 01711 Resource->NumberOfExclusiveWaiters -= 1; 01712 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01713 KeSetEventBoostPriority(Resource->ExclusiveWaiters, 01714 (PRKTHREAD *)&Resource->OwnerThreads[0].OwnerThread); 01715 return; 01716 } 01717 01718 Resource->Flag &= ~ResourceOwnedExclusive; 01719 } 01720 01721 } else { 01722 if (Resource->OwnerThreads[1].OwnerThread == CurrentThread) { 01723 OwnerEntry = &Resource->OwnerThreads[1]; 01724 01725 } else if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 01726 OwnerEntry = &Resource->OwnerThreads[0]; 01727 01728 } else { 01729 01730 // 01731 // If the specified current thread is an owner address (low 01732 // bits are nonzero), then set the hint index to the first 01733 // entry. Otherwise, set the hint index from the owner thread. 01734 // 01735 01736 Index = 1; 01737 if (((ULONG)CurrentThread & 3) == 0) { 01738 Index = ((PKTHREAD)(CurrentThread))->ResourceIndex; 01739 } 01740 01741 OwnerEntry = Resource->OwnerTable; 01742 01743 ASSERT(OwnerEntry != NULL); 01744 01745 // 01746 // If the resource hint is not within range or the resource 01747 // table entry does match the current thread, then search 01748 // the owner table for a match. 01749 // 01750 01751 if ((Index >= OwnerEntry->TableSize) || 01752 (OwnerEntry[Index].OwnerThread != CurrentThread)) { 01753 do { 01754 OwnerEntry += 1; 01755 if (OwnerEntry->OwnerThread == CurrentThread) { 01756 break; 01757 } 01758 01759 } while (TRUE); 01760 01761 } else { 01762 OwnerEntry = &OwnerEntry[Index]; 01763 } 01764 } 01765 01766 // 01767 // Decrement the recursion count and check if ownership can be 01768 // released. 01769 // 01770 01771 ASSERT(OwnerEntry->OwnerThread == CurrentThread); 01772 ASSERT(OwnerEntry->OwnerCount > 0); 01773 01774 if (--OwnerEntry->OwnerCount != 0) { 01775 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01776 return; 01777 } 01778 01779 // 01780 // Clear the owner thread. 01781 // 01782 01783 OwnerEntry->OwnerThread = 0; 01784 01785 // 01786 // The thread recursion count reached zero so decrement the resource 01787 // active count. If the active count reaches zero, then the resource 01788 // is no longer owned and an attempt should be made to grant access to 01789 // another thread. 01790 // 01791 01792 ASSERT(Resource->ActiveCount > 0); 01793 01794 if (--Resource->ActiveCount == 0) { 01795 01796 // 01797 // If there are exclusive waiters, then grant exclusive access 01798 // to the resource. 01799 // 01800 01801 if (IsExclusiveWaiting(Resource)) { 01802 Resource->Flag |= ResourceOwnedExclusive; 01803 Resource->OwnerThreads[0].OwnerThread = 1; 01804 Resource->OwnerThreads[0].OwnerCount = 1; 01805 Resource->ActiveCount = 1; 01806 Resource->NumberOfExclusiveWaiters -= 1; 01807 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01808 KeSetEventBoostPriority(Resource->ExclusiveWaiters, 01809 (PRKTHREAD *)&Resource->OwnerThreads[0].OwnerThread); 01810 return; 01811 } 01812 } 01813 } 01814 01815 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01816 return; 01817 } 01818 01819 VOID 01820 ExSetResourceOwnerPointer( 01821 IN PERESOURCE Resource, 01822 IN PVOID OwnerPointer 01823 ) 01824 01825 /*++ 01826 01827 Routine Description: 01828 01829 This routine locates the owner entry for the current thread and stores 01830 the specified owner address as the owner thread. Subsequent to calling 01831 this routine, the only routine which may be called for this resource is 01832 ExReleaseResourceForThread, supplying the owner address as the "thread". 01833 01834 Owner addresses must obey the following rules: 01835 01836 They must be a unique pointer to a structure allocated in system space, 01837 and they must point to a structure which remains allocated until after 01838 the call to ExReleaseResourceForThread. This is to eliminate aliasing 01839 with a thread or other owner address. 01840 01841 The low order two bits of the owner address must be set by the caller, 01842 so that other routines in the resource package can distinguish owner 01843 address from thread addresses. 01844 01845 N.B. This routine uses fast locking. 01846 01847 Arguments: 01848 01849 Resource - Supplies a pointer to the resource to release. 01850 01851 OwnerPointer - Supplies a pointer to an allocated structure with the low 01852 order two bits set. 01853 01854 Return Value: 01855 01856 None. 01857 01858 --*/ 01859 01860 { 01861 01862 ERESOURCE_THREAD CurrentThread; 01863 ULONG Index; 01864 KIRQL OldIrql; 01865 POWNER_ENTRY OwnerEntry; 01866 01867 ASSERT((OwnerPointer != 0) && (((ULONG_PTR)OwnerPointer & 3) == 3)); 01868 01869 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 01870 01871 // 01872 // Acquire exclusive access to the specified resource. 01873 // 01874 01875 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 01876 01877 ASSERT_RESOURCE(Resource); 01878 01879 // 01880 // If the resource is exclusively owned, then it is the first owner entry. 01881 // 01882 01883 if (IsOwnedExclusive(Resource)) { 01884 01885 ASSERT(Resource->OwnerThreads[0].OwnerThread == CurrentThread); 01886 01887 // 01888 // Set the owner address. 01889 // 01890 01891 ASSERT(Resource->OwnerThreads[0].OwnerCount > 0); 01892 01893 Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer; 01894 01895 // 01896 // For shared access we have to search for the current thread to set 01897 // the owner address. 01898 // 01899 01900 } else { 01901 if (Resource->OwnerThreads[1].OwnerThread == CurrentThread) { 01902 Resource->OwnerThreads[1].OwnerThread = (ULONG_PTR)OwnerPointer; 01903 01904 } else if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 01905 Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer; 01906 01907 } else { 01908 Index = ((PKTHREAD)(CurrentThread))->ResourceIndex; 01909 OwnerEntry = Resource->OwnerTable; 01910 01911 ASSERT(OwnerEntry != NULL); 01912 01913 // 01914 // If the resource hint is not within range or the resource 01915 // table entry does match the current thread, then search 01916 // the owner table for a match. 01917 // 01918 01919 if ((Index >= OwnerEntry->TableSize) || 01920 (OwnerEntry[Index].OwnerThread != CurrentThread)) { 01921 do { 01922 OwnerEntry += 1; 01923 if (OwnerEntry->OwnerThread == CurrentThread) { 01924 break; 01925 } 01926 01927 } while (TRUE); 01928 01929 } else { 01930 OwnerEntry = &OwnerEntry[Index]; 01931 } 01932 01933 OwnerEntry->OwnerThread = (ULONG_PTR)OwnerPointer; 01934 } 01935 } 01936 01937 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01938 return; 01939 } 01940 01941 VOID 01942 ExConvertExclusiveToSharedLite( 01943 IN PERESOURCE Resource 01944 ) 01945 01946 /*++ 01947 01948 Routine Description: 01949 01950 This routine converts the specified resource from acquired for exclusive 01951 access to acquired for shared access. 01952 01953 N.B. This routine uses fast locking. 01954 01955 Arguments: 01956 01957 Resource - Supplies a pointer to the resource to acquire for shared access. it 01958 01959 Return Value: 01960 01961 None. 01962 01963 --*/ 01964 01965 { 01966 01967 ULONG Number; 01968 KIRQL OldIrql; 01969 01970 // 01971 // Acquire exclusive access to the specified resource. 01972 // 01973 01974 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 01975 01976 ASSERT(KeIsExecutingDpc() == FALSE); 01977 ASSERT_RESOURCE(Resource); 01978 ASSERT(IsOwnedExclusive(Resource)); 01979 ASSERT(Resource->OwnerThreads[0].OwnerThread == (ERESOURCE_THREAD)PsGetCurrentThread()); 01980 01981 // 01982 // Convert the granted access from exclusive to shared. 01983 // 01984 01985 Resource->Flag &= ~ResourceOwnedExclusive; 01986 01987 // 01988 // If there are any shared waiters, then grant them shared access. 01989 // 01990 01991 if (IsSharedWaiting(Resource)) { 01992 Number = Resource->NumberOfSharedWaiters; 01993 Resource->ActiveCount += (SHORT)Number; 01994 Resource->NumberOfSharedWaiters = 0; 01995 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 01996 KeReleaseSemaphore(Resource->SharedWaiters, 0, Number, FALSE); 01997 return; 01998 } 01999 02000 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 02001 return; 02002 } 02003 02004 NTSTATUS 02005 ExDeleteResourceLite( 02006 IN PERESOURCE Resource 02007 ) 02008 02009 /*++ 02010 02011 Routine Description: 02012 02013 This routine deallocates any pool allocated to support the specified 02014 resource. 02015 02016 02017 Arguments: 02018 02019 Resource - Supplies a pointer to the resource whose allocated pool 02020 is freed. 02021 02022 Return Value: 02023 02024 STATUS_SUCCESS. 02025 02026 --*/ 02027 02028 { 02029 02030 PRESOURCE_HASH_ENTRY HashEntry; 02031 ULONG Hash; 02032 PRESOURCE_HASH_ENTRY MatchEntry; 02033 PLIST_ENTRY NextEntry; 02034 KIRQL OldIrql; 02035 02036 ASSERT(IsSharedWaiting(Resource) == FALSE); 02037 ASSERT(IsExclusiveWaiting(Resource) == FALSE); 02038 02039 // 02040 // Acquire the executive resource spinlock and remove the resource from 02041 // the system resource list. 02042 // 02043 02044 ExAcquireSpinLock(&ExpResourceSpinLock, &OldIrql); 02045 02046 ASSERT(KeIsExecutingDpc() == FALSE); 02047 ASSERT_RESOURCE(Resource); 02048 02049 RemoveEntryList(&Resource->SystemResourcesList); 02050 02051 #if defined(_COLLECT_RESOURCE_DATA_) 02052 02053 // 02054 // Lookup resource initialization address in resource hash table. If 02055 // the address does not exist in the table, then create a new entry. 02056 // 02057 02058 Hash = (ULONG)Resource->Address; 02059 Hash = ((Hash > 24) ^ (Hash > 16) ^ (Hash > 8) ^ (Hash)) & (RESOURCE_HASH_TABLE_SIZE - 1); 02060 MatchEntry = NULL; 02061 NextEntry = ExpResourcePerformanceData.HashTable[Hash].Flink; 02062 while (NextEntry != &ExpResourcePerformanceData.HashTable[Hash]) { 02063 HashEntry = CONTAINING_RECORD(NextEntry, 02064 RESOURCE_HASH_ENTRY, 02065 ListEntry); 02066 02067 if (HashEntry->Address == Resource->Address) { 02068 MatchEntry = HashEntry; 02069 break; 02070 } 02071 02072 NextEntry = NextEntry->Flink; 02073 } 02074 02075 // 02076 // If a matching initialization address was found, then update the call 02077 // site statistics. Otherwise, allocate a new hash entry and initialize 02078 // call site statistics. 02079 // 02080 02081 if (MatchEntry != NULL) { 02082 MatchEntry->ContentionCount += Resource->ContentionCount; 02083 MatchEntry->Number += 1; 02084 02085 } else { 02086 MatchEntry = ExAllocatePoolWithTag(NonPagedPool, 02087 sizeof(RESOURCE_HASH_ENTRY), 02088 'vEpR'); 02089 02090 if (MatchEntry != NULL) { 02091 MatchEntry->Address = Resource->Address; 02092 MatchEntry->ContentionCount = Resource->ContentionCount; 02093 MatchEntry->Number = 1; 02094 InsertTailList(&ExpResourcePerformanceData.HashTable[Hash], 02095 &MatchEntry->ListEntry); 02096 } 02097 } 02098 02099 ExpResourcePerformanceData.ActiveResourceCount -= 1; 02100 02101 #endif 02102 02103 ExReleaseSpinLock(&ExpResourceSpinLock, OldIrql); 02104 02105 // 02106 // If an owner table was allocated, then free it to pool. 02107 // 02108 02109 if (Resource->OwnerTable != NULL) { 02110 ExFreePool(Resource->OwnerTable); 02111 } 02112 02113 // 02114 // If a semaphore was allocated, then free it to pool. 02115 // 02116 02117 if (Resource->SharedWaiters) { 02118 ExFreePool(Resource->SharedWaiters); 02119 } 02120 02121 // 02122 // If an event was allocated, then free it to pool. 02123 // 02124 02125 if (Resource->ExclusiveWaiters) { 02126 ExFreePool(Resource->ExclusiveWaiters); 02127 } 02128 02129 return STATUS_SUCCESS; 02130 } 02131 02132 ULONG 02133 ExGetExclusiveWaiterCount( 02134 IN PERESOURCE Resource 02135 ) 02136 02137 /*++ 02138 02139 Routine Description: 02140 02141 This routine returns the exclusive waiter count. 02142 02143 02144 Arguments: 02145 02146 Resource - Supplies a pointer to and executive resource. 02147 02148 Return Value: 02149 02150 The current number of exclusive waiters is returned as the function 02151 value. 02152 02153 --*/ 02154 02155 { 02156 return Resource->NumberOfExclusiveWaiters; 02157 } 02158 02159 ULONG 02160 ExGetSharedWaiterCount( 02161 IN PERESOURCE Resource 02162 ) 02163 02164 /*++ 02165 02166 Routine Description: 02167 02168 This routine returns the shared waiter count. 02169 02170 02171 Arguments: 02172 02173 Resource - Supplies a pointer to and executive resource. 02174 02175 Return Value: 02176 02177 The current number of shared waiters is returned as the function 02178 value. 02179 02180 --*/ 02181 02182 { 02183 return Resource->NumberOfSharedWaiters; 02184 } 02185 02186 BOOLEAN 02187 ExIsResourceAcquiredExclusiveLite( 02188 IN PERESOURCE Resource 02189 ) 02190 02191 /*++ 02192 02193 Routine Description: 02194 02195 This routine determines if a resource is acquired exclusive by the 02196 calling thread. 02197 02198 Arguments: 02199 02200 Resource - Supplies a pointer the resource to query. 02201 02202 Return Value: 02203 02204 If the current thread has acquired the resource exclusive, a value of 02205 TRUE is returned. Otherwise, a value of FALSE is returned. 02206 02207 --*/ 02208 02209 { 02210 02211 ERESOURCE_THREAD CurrentThread; 02212 KIRQL OldIrql; 02213 BOOLEAN Result; 02214 02215 // 02216 // Acquire exclusive access to the specified resource. 02217 // 02218 02219 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 02220 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 02221 02222 ASSERT_RESOURCE(Resource); 02223 02224 // 02225 // If the resource is owned exclusive and the current thread is the 02226 // owner, then set the return value of TRUE. Otherwise, set the return 02227 // value to FALSE. 02228 // 02229 02230 Result = FALSE; 02231 if ((IsOwnedExclusive(Resource)) && 02232 (Resource->OwnerThreads[0].OwnerThread == CurrentThread)) { 02233 Result = TRUE; 02234 } 02235 02236 // 02237 // Release exclusive access to the specified resource. 02238 // 02239 02240 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 02241 return Result; 02242 } 02243 02244 ULONG 02245 ExIsResourceAcquiredSharedLite( 02246 IN PERESOURCE Resource 02247 ) 02248 02249 /*++ 02250 02251 Routine Description: 02252 02253 This routine determines if a resource is acquired either shared or 02254 exclusive by the calling thread. 02255 02256 Arguments: 02257 02258 Resource - Supplies a pointer to the resource to query. 02259 02260 Return Value: 02261 02262 If the current thread has not acquired the resource a value of zero 02263 is returned. Otherwise, the thread's acquire count is returned. 02264 02265 --*/ 02266 02267 { 02268 02269 ERESOURCE_THREAD CurrentThread; 02270 ULONG Index; 02271 ULONG Number; 02272 KIRQL OldIrql; 02273 POWNER_ENTRY OwnerEntry; 02274 ULONG Result; 02275 02276 // 02277 // Acquire exclusive access to the specified resource. 02278 // 02279 02280 CurrentThread = (ERESOURCE_THREAD)PsGetCurrentThread(); 02281 ExAcquireFastLock(&Resource->SpinLock, &OldIrql); 02282 02283 ASSERT_RESOURCE(Resource); 02284 02285 // 02286 // Find the current thread in the thread array and return the count. 02287 // 02288 // N.B. If the thread is not found a value of zero will be returned. 02289 // 02290 02291 if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 02292 Result = Resource->OwnerThreads[0].OwnerCount; 02293 02294 } else if (Resource->OwnerThreads[1].OwnerThread == CurrentThread) { 02295 Result = Resource->OwnerThreads[1].OwnerCount; 02296 02297 } else { 02298 02299 // 02300 // If the resource hint is not within range or the resource table 02301 // entry does not match the current thread, then search the owner 02302 // table for a match. 02303 // 02304 02305 OwnerEntry = Resource->OwnerTable; 02306 Result = 0; 02307 if (OwnerEntry != NULL) { 02308 Index = ((PKTHREAD)(CurrentThread))->ResourceIndex; 02309 Number = OwnerEntry->TableSize; 02310 if ((Index >= Number) || 02311 (OwnerEntry[Index].OwnerThread != CurrentThread)) { 02312 for (Index = 1; Index < Number; Index += 1) { 02313 OwnerEntry += 1; 02314 if (OwnerEntry->OwnerThread == CurrentThread) { 02315 Result = OwnerEntry->OwnerCount; 02316 break; 02317 } 02318 } 02319 02320 } else { 02321 Result = OwnerEntry[Index].OwnerCount; 02322 } 02323 } 02324 } 02325 02326 // 02327 // Release exclusive access to the specified resource. 02328 // 02329 02330 ExReleaseFastLock(&Resource->SpinLock, OldIrql); 02331 return Result; 02332 } 02333 02334 NTSTATUS 02335 ExQuerySystemLockInformation( 02336 OUT PRTL_PROCESS_LOCKS LockInformation, 02337 IN ULONG LockInformationLength, 02338 OUT PULONG ReturnLength OPTIONAL 02339 ) 02340 02341 { 02342 02343 NTSTATUS Status; 02344 KIRQL OldIrql; 02345 ULONG RequiredLength; 02346 PLIST_ENTRY Head, Next; 02347 PRTL_PROCESS_LOCK_INFORMATION LockInfo; 02348 PERESOURCE Resource; 02349 PNTDDK_ERESOURCE NtDdkResource; 02350 PETHREAD OwningThread; 02351 02352 RequiredLength = FIELD_OFFSET(RTL_PROCESS_LOCKS, Locks); 02353 if (LockInformationLength < RequiredLength) { 02354 Status = STATUS_INFO_LENGTH_MISMATCH; 02355 02356 } else { 02357 Status = STATUS_SUCCESS; 02358 ExAcquireSpinLock(&ExpResourceSpinLock, &OldIrql); 02359 try { 02360 LockInformation->NumberOfLocks = 0; 02361 LockInfo = &LockInformation->Locks[0]; 02362 Head = &ExpSystemResourcesList; 02363 Next = Head->Flink; 02364 while (Next != Head) { 02365 Resource = CONTAINING_RECORD(Next, 02366 ERESOURCE, 02367 SystemResourcesList); 02368 02369 LockInformation->NumberOfLocks += 1; 02370 RequiredLength += sizeof(RTL_PROCESS_LOCK_INFORMATION); 02371 02372 // 02373 // Detect if this is an NtDdk resource. New lite resources 02374 // never contain pointers to themselves. 02375 // 02376 02377 NtDdkResource = (PNTDDK_ERESOURCE)Resource; 02378 if (NtDdkResource->OwnerThreads != &NtDdkResource->InitialOwnerThreads[0]) { 02379 NtDdkResource = NULL; 02380 } 02381 02382 if (LockInformationLength < RequiredLength) { 02383 Status = STATUS_INFO_LENGTH_MISMATCH; 02384 02385 } else { 02386 LockInfo->Address = Resource; 02387 LockInfo->Type = RTL_RESOURCE_TYPE; 02388 LockInfo->CreatorBackTraceIndex = 0; 02389 #if i386 && !FPO 02390 if (NtDdkResource) { 02391 LockInfo->CreatorBackTraceIndex = (USHORT)NtDdkResource->CreatorBackTraceIndex; 02392 } else { 02393 LockInfo->CreatorBackTraceIndex = (USHORT)Resource->CreatorBackTraceIndex; 02394 } 02395 #endif // i386 && !FPO 02396 02397 if (NtDdkResource) { 02398 if ((NtDdkResource->OwnerThreads[0] != 0) && 02399 ((NtDdkResource->OwnerThreads[0] & 3) == 0)) { 02400 OwningThread = (PETHREAD)(NtDdkResource->OwnerThreads[0]); 02401 LockInfo->OwningThread = OwningThread->Cid.UniqueThread; 02402 02403 } else { 02404 LockInfo->OwningThread = 0; 02405 } 02406 02407 LockInfo->LockCount = NtDdkResource->ActiveCount; 02408 LockInfo->ContentionCount = NtDdkResource->ContentionCount; 02409 LockInfo->NumberOfWaitingShared = NtDdkResource->NumberOfSharedWaiters; 02410 LockInfo->NumberOfWaitingExclusive = NtDdkResource->NumberOfExclusiveWaiters; 02411 02412 } else { 02413 if ((Resource->OwnerThreads[0].OwnerThread != 0) && 02414 ((Resource->OwnerThreads[0].OwnerThread & 3) == 0)) { 02415 OwningThread = (PETHREAD)(Resource->OwnerThreads[0].OwnerThread); 02416 LockInfo->OwningThread = OwningThread->Cid.UniqueThread; 02417 02418 } else { 02419 LockInfo->OwningThread = 0; 02420 } 02421 02422 LockInfo->LockCount = Resource->ActiveCount; 02423 LockInfo->ContentionCount = Resource->ContentionCount; 02424 LockInfo->NumberOfWaitingShared = Resource->NumberOfSharedWaiters; 02425 LockInfo->NumberOfWaitingExclusive = Resource->NumberOfExclusiveWaiters; 02426 } 02427 02428 LockInfo += 1; 02429 } 02430 02431 if (Next == Next->Flink) { 02432 Next = Head; 02433 02434 } else { 02435 Next = Next->Flink; 02436 } 02437 } 02438 02439 } finally { 02440 ExReleaseSpinLock(&ExpResourceSpinLock, OldIrql); 02441 } 02442 } 02443 02444 if (ARGUMENT_PRESENT(ReturnLength)) { 02445 *ReturnLength = RequiredLength; 02446 } 02447 02448 return Status; 02449 } 02450 02451 VOID 02452 FASTCALL 02453 ExpBoostOwnerThread ( 02454 IN PKTHREAD CurrentThread, 02455 IN PKTHREAD OwnerThread 02456 ) 02457 /*++ 02458 02459 Routine Description: 02460 02461 This function boots the priority of the specified owner thread iff 02462 its priority is less than that of the current thread and is also 02463 less than fourteen. 02464 02465 N.B. this function is called with the dispatcher database lock held. 02466 02467 Arguments: 02468 02469 CurrentThread - Supplies a pointer to the current thread object. 02470 02471 OwnerThread - Supplies a pointer to the owner thread object. 02472 02473 Return Value: 02474 02475 None. 02476 02477 --*/ 02478 02479 { 02480 02481 // 02482 // If the owner thread is lower priority than the current thread, the 02483 // current thread is running at a priority less than 14, then boost the 02484 // priority of the owner thread for a quantum. 02485 // 02486 // N.B. A thread that has already been boosted may be reboosted to allow 02487 // it to execute and release resources. When the boost is removed, 02488 // the thread will return to its priority before any boosting. 02489 // 02490 02491 if (((ULONG_PTR)OwnerThread & 0x3) == 0) { 02492 if ((OwnerThread->Priority < CurrentThread->Priority) && 02493 (OwnerThread->Priority < 14)) { 02494 OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority; 02495 OwnerThread->DecrementCount = ROUND_TRIP_DECREMENT_COUNT; 02496 KiSetPriorityThread(OwnerThread, 14); 02497 OwnerThread->Quantum = OwnerThread->ApcState.Process->ThreadQuantum; 02498 } 02499 } 02500 02501 return; 02502 } 02503 02504 VOID 02505 FASTCALL 02506 ExpWaitForResource ( 02507 IN PERESOURCE Resource, 02508 IN PVOID Object 02509 ) 02510 /*++ 02511 02512 Routine Description: 02513 02514 The routine waits for the specified resource object to be set. If the 02515 wait is too long the priority of the current owners of the resource 02516 are boosted. 02517 02518 Arguments: 02519 02520 Resource - Supplies a pointer to the resource to wait for. 02521 02522 Object - Supplies a pointer to an event (exclusive) or semaphore 02523 (shared) to wait for. 02524 02525 Return Value: 02526 02527 None. 02528 02529 --*/ 02530 02531 { 02532 02533 ULONG Index; 02534 ULONG Limit; 02535 ULONG Number; 02536 KIRQL OldIrql; 02537 POWNER_ENTRY OwnerEntry; 02538 PKTHREAD OwnerThread; 02539 NTSTATUS Status; 02540 PKTHREAD CurrentThread; 02541 LARGE_INTEGER Timeout; 02542 02543 // 02544 // Increment the contention count for the resource, set the initial 02545 // timeout value, and wait for the specified object to be signalled 02546 // or a timeout to occur. 02547 // 02548 02549 Limit = 0; 02550 Resource->ContentionCount += 1; 02551 Timeout.QuadPart = 500 * -10000; 02552 do { 02553 Status = KeWaitForSingleObject ( 02554 Object, 02555 Executive, 02556 KernelMode, 02557 FALSE, 02558 &Timeout ); 02559 02560 if (Status != STATUS_TIMEOUT) { 02561 break; 02562 } 02563 02564 // 02565 // The limit has been exceeded, then output status information. 02566 // 02567 02568 Limit += 1; 02569 Timeout = ExpTimeout; 02570 if (Limit > ExpResourceTimeoutCount) { 02571 Limit = 0; 02572 02573 // 02574 // Output information for the specified resource. 02575 // 02576 02577 ExAcquireSpinLock(&Resource->SpinLock, &OldIrql); 02578 DbgPrint("Resource @ %lx\n", Resource); 02579 DbgPrint(" ActiveCount = %04lx Flags = %s%s%s\n", 02580 Resource->ActiveCount, 02581 IsOwnedExclusive(Resource) ? "IsOwnedExclusive " : "", 02582 IsSharedWaiting(Resource) ? "SharedWaiter " : "", 02583 IsExclusiveWaiting(Resource) ? "ExclusiveWaiter " : ""); 02584 02585 DbgPrint(" NumberOfExclusiveWaiters = %04lx\n", Resource->NumberOfExclusiveWaiters); 02586 02587 DbgPrint(" Thread = %08lx, Count = %02x\n", 02588 Resource->OwnerThreads[0].OwnerThread, 02589 Resource->OwnerThreads[0].OwnerCount); 02590 02591 DbgPrint(" Thread = %08lx, Count = %02x\n", 02592 Resource->OwnerThreads[1].OwnerThread, 02593 Resource->OwnerThreads[1].OwnerCount); 02594 02595 OwnerEntry = Resource->OwnerTable; 02596 if (OwnerEntry != NULL) { 02597 Number = OwnerEntry->TableSize; 02598 for(Index = 1; Index < Number; Index += 1) { 02599 OwnerEntry += 1; 02600 DbgPrint(" Thread = %08lx, Count = %02x\n", 02601 OwnerEntry->OwnerThread, 02602 OwnerEntry->OwnerCount); 02603 } 02604 } 02605 02606 DbgBreakPoint(); 02607 DbgPrint("EX - Rewaiting\n"); 02608 ExReleaseSpinLock(&Resource->SpinLock, OldIrql); 02609 } 02610 02611 // 02612 // If priority boosts are allowed, then attempt to boost the priority 02613 // of owner threads. 02614 // 02615 02616 if (IsBoostAllowed(Resource)) { 02617 02618 // 02619 // Get the current thread address, lock the dispatcher database, 02620 // and set wait next in the current thread so the dispatcher 02621 // database lock does not need to be released before waiting 02622 // for the resource. 02623 // 02624 // N.B. Since the dispatcher database lock instead of the resource 02625 // lock is being used to synchronize access to the resource, 02626 // it is possible for the information being read from the 02627 // resource to be stale. However, the important thing that 02628 // cannot change is a valid thread address. Thus a thread 02629 // could possibly get boosted that actually has dropped its 02630 // access to the resource, but it guaranteed that the thread 02631 // cannot be terminated or otherwise deleted. 02632 // 02633 // N.B. The dispatcher lock is released by the wait at the top of 02634 // loop. 02635 // 02636 02637 CurrentThread = KeGetCurrentThread(); 02638 02639 KiLockDispatcherDatabase(&CurrentThread->WaitIrql); 02640 CurrentThread->WaitNext = TRUE; 02641 02642 // 02643 // Attempt to boost the one owner that can be shared or exclusive. 02644 // 02645 02646 OwnerThread = (PKTHREAD)Resource->OwnerThreads[0].OwnerThread; 02647 if (OwnerThread != NULL) { 02648 ExpBoostOwnerThread(CurrentThread, OwnerThread); 02649 } 02650 02651 // 02652 // If the specified resource is not owned exclusive, then attempt 02653 // to boost all the owning shared threads priority. 02654 // 02655 02656 if (!IsOwnedExclusive(Resource)) { 02657 OwnerThread = (PKTHREAD)Resource->OwnerThreads[1].OwnerThread; 02658 if (OwnerThread != NULL) { 02659 ExpBoostOwnerThread(CurrentThread, OwnerThread); 02660 } 02661 02662 OwnerEntry = Resource->OwnerTable; 02663 if (OwnerEntry != NULL) { 02664 Number = OwnerEntry->TableSize; 02665 for(Index = 1; Index < Number; Index += 1) { 02666 OwnerEntry += 1; 02667 OwnerThread = (PKTHREAD)OwnerEntry->OwnerThread; 02668 if (OwnerThread != NULL) { 02669 ExpBoostOwnerThread(CurrentThread, OwnerThread); 02670 } 02671 } 02672 } 02673 } 02674 } 02675 02676 } while (TRUE); 02677 02678 return; 02679 } 02680 02681 POWNER_ENTRY 02682 FASTCALL 02683 ExpFindCurrentThread( 02684 IN PERESOURCE Resource, 02685 IN ERESOURCE_THREAD CurrentThread 02686 ) 02687 02688 /*++ 02689 02690 Routine Description: 02691 02692 This function searches for the specified thread in the resource 02693 thread array. If the thread is located, then a pointer to the 02694 array entry is returned as the function value. Otherwise, a pointer 02695 to a free entry is returned. 02696 02697 Arguments: 02698 02699 Resource - Supplies a pointer to the resource for which the search 02700 is performed. 02701 02702 CurrentThread - Supplies the identification of the thread to search 02703 for. 02704 02705 Return Value: 02706 02707 A pointer to an owner entry is returned. 02708 02709 --*/ 02710 02711 { 02712 02713 POWNER_ENTRY FreeEntry; 02714 ULONG NewSize; 02715 ULONG OldSize; 02716 POWNER_ENTRY OwnerEntry; 02717 POWNER_ENTRY OwnerBound; 02718 POWNER_ENTRY OwnerTable, OldTable; 02719 KIRQL OldIrql; 02720 02721 // 02722 // Search the owner threads for the specified thread and return either 02723 // a pointer to the found thread or a pointer to a free thread table 02724 // entry. 02725 // 02726 02727 if (Resource->OwnerThreads[0].OwnerThread == CurrentThread) { 02728 return &Resource->OwnerThreads[0]; 02729 02730 } else if (Resource->OwnerThreads[1].OwnerThread == CurrentThread) { 02731 return &Resource->OwnerThreads[1]; 02732 02733 } else { 02734 FreeEntry = NULL; 02735 if (Resource->OwnerThreads[1].OwnerThread == 0) { 02736 FreeEntry = &Resource->OwnerThreads[1]; 02737 } 02738 02739 OwnerEntry = Resource->OwnerTable; 02740 if (OwnerEntry == NULL) { 02741 OldSize = 0; 02742 02743 } else { 02744 OldSize = OwnerEntry->TableSize; 02745 OwnerBound = &OwnerEntry[OldSize]; 02746 OwnerEntry += 1; 02747 do { 02748 if (OwnerEntry->OwnerThread == CurrentThread) { 02749 KeGetCurrentThread()->ResourceIndex = (UCHAR)(OwnerEntry - Resource->OwnerTable); 02750 return OwnerEntry; 02751 } 02752 02753 if ((FreeEntry == NULL) && 02754 (OwnerEntry->OwnerThread == 0)) { 02755 FreeEntry = OwnerEntry; 02756 } 02757 02758 OwnerEntry += 1; 02759 } while (OwnerEntry != OwnerBound); 02760 } 02761 } 02762 02763 // 02764 // If a free entry was found in the table, then return the address of the 02765 // free entry. Otherwise, expand the size of the owner thread table. 02766 // 02767 02768 if (FreeEntry != NULL) { 02769 KeGetCurrentThread()->ResourceIndex = (UCHAR)(FreeEntry - Resource->OwnerTable); 02770 return FreeEntry; 02771 } 02772 02773 // 02774 // Allocate an expanded owner table. 02775 // 02776 02777 ExpIncrementCounter(OwnerTableExpands); 02778 if (OldSize == 0 ) { 02779 NewSize = 3; 02780 02781 } else { 02782 NewSize = OldSize + 4; 02783 } 02784 02785 if (NewSize * sizeof(OWNER_ENTRY) <= PAGE_SIZE) { 02786 02787 OwnerTable = (POWNER_ENTRY)ExAllocatePoolWithTag( 02788 NonPagedPoolMustSucceed, 02789 NewSize * sizeof(OWNER_ENTRY), 02790 'aTeR'); 02791 } 02792 else { 02793 02794 // 02795 // If allocation is bigger than one page we need to 02796 // allocate from normal pool. If we fail then we will 02797 // bugcheck with `must_succeed_pool_empty' because logically 02798 // this is what we do. 02799 // 02800 02801 OwnerTable = (POWNER_ENTRY)ExAllocatePoolWithTag( 02802 NonPagedPool, 02803 NewSize * sizeof(OWNER_ENTRY), 02804 'aTeR'); 02805 02806 if (OwnerTable == NULL) { 02807 02808 KeBugCheck (MUST_SUCCEED_POOL_EMPTY); 02809 } 02810 02811 } 02812 02813 // 02814 // Zero the expanded owner table, compute the address of the owner 02815 // count and thread tables, and copy the old table to the new table. 02816 // 02817 02818 RtlZeroMemory((PVOID)(OwnerTable + OldSize), 02819 (NewSize - OldSize) * sizeof(OWNER_ENTRY)); 02820 02821 RtlCopyMemory((PVOID)OwnerTable, 02822 Resource->OwnerTable, 02823 OldSize * sizeof(OWNER_ENTRY)); 02824 02825 // 02826 // If an expanded table was previously allocated, then save it so it can be freed. 02827 // 02828 OldTable = Resource->OwnerTable; 02829 02830 // 02831 // Set new owner table parameters and return the address of the first 02832 // free entry. We need the dispatcher lock here to prevent table expansion while we are boosting 02833 // thread priorities. 02834 // 02835 KiLockDispatcherDatabase(&OldIrql); 02836 OwnerTable->TableSize = NewSize; 02837 Resource->OwnerTable = OwnerTable; 02838 KiUnlockDispatcherDatabase(OldIrql); 02839 02840 if (OldTable != NULL) { 02841 ExFreePool(OldTable); 02842 } 02843 02844 ASSERT_RESOURCE(Resource); 02845 02846 #if defined(_COLLECT_RESOURCE_DATA_) 02847 02848 if (NewSize > ExpResourcePerformanceData.MaximumTableExpand) { 02849 ExpResourcePerformanceData.MaximumTableExpand = NewSize; 02850 } 02851 02852 #endif 02853 02854 if (OldSize == 0) { 02855 OldSize = 1; 02856 } 02857 02858 KeGetCurrentThread()->ResourceIndex = (CCHAR)OldSize; 02859 return &OwnerTable[OldSize]; 02860 } 02861 02862 #if DBG 02863 02864 VOID 02865 ExpAssertResource ( 02866 IN PERESOURCE Resource 02867 ) 02868 02869 { 02870 ULONG Index; 02871 POWNER_ENTRY OwnerEntry; 02872 02873 // 02874 // Assert that resource structure is correct. 02875 // 02876 // N.B. This routine is called with the resource lock held. 02877 // 02878 02879 ASSERT(!Resource->SharedWaiters || 02880 Resource->SharedWaiters->Header.Type == SemaphoreObject); 02881 02882 ASSERT(!Resource->SharedWaiters || 02883 Resource->SharedWaiters->Header.Size == (sizeof(KSEMAPHORE) / sizeof(ULONG))); 02884 02885 ASSERT(!Resource->ExclusiveWaiters || 02886 Resource->ExclusiveWaiters->Header.Type == SynchronizationEvent); 02887 02888 ASSERT(!Resource->ExclusiveWaiters || 02889 Resource->ExclusiveWaiters->Header.Size == (sizeof(KEVENT) / sizeof(ULONG))); 02890 } 02891 #endif // dbg 02892 02893 PVOID 02894 ExpCheckForResource( 02895 IN PVOID p, 02896 IN ULONG Size 02897 ) 02898 02899 { 02900 02901 KIRQL OldIrql; 02902 PLIST_ENTRY Head, Next; 02903 PERESOURCE Resource; 02904 PCHAR BeginBlock; 02905 PCHAR EndBlock; 02906 02907 // 02908 // This can cause a deadlock on MP machines. 02909 // 02910 02911 if (KeNumberProcessors > 1) { 02912 return NULL; 02913 } 02914 02915 BeginBlock = (PCHAR)p; 02916 EndBlock = (PCHAR)p + Size; 02917 02918 ExAcquireSpinLock( &ExpResourceSpinLock, &OldIrql ); 02919 Head = &ExpSystemResourcesList; 02920 Next = Head->Flink; 02921 while (Next != Head) { 02922 Resource = CONTAINING_RECORD( Next, 02923 ERESOURCE, 02924 SystemResourcesList 02925 ); 02926 02927 if ((PCHAR)Resource >= BeginBlock && (PCHAR)Resource < EndBlock) { 02928 DbgPrint( "EX: ExFreePool( %lx, %lx ) contains an ERESOURCE structure that has not been ExDeleteResourced\n", 02929 p, Size 02930 ); 02931 DbgBreakPoint(); 02932 ExReleaseSpinLock( &ExpResourceSpinLock, OldIrql ); 02933 return (PVOID)Resource; 02934 } 02935 02936 Next = Next->Flink; 02937 } 02938 02939 ExReleaseSpinLock( &ExpResourceSpinLock, OldIrql ); 02940 return NULL; 02941 }

Generated on Sat May 15 19:41:39 2004 for test by doxygen 1.3.7