1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ex/resource.c 5 * PURPOSE: Executive Resource Implementation 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* Macros for reading resource flags */ 16 #define IsExclusiveWaiting(r) (r->NumberOfExclusiveWaiters > 0) 17 #define IsSharedWaiting(r) (r->NumberOfSharedWaiters > 0) 18 #define IsOwnedExclusive(r) (r->Flag & ResourceOwnedExclusive) 19 #define IsBoostAllowed(r) (!(r->Flag & ResourceHasDisabledPriorityBoost)) 20 21 #if !defined(CONFIG_SMP) && !DBG 22 23 FORCEINLINE 24 VOID 25 ExAcquireResourceLock(IN PERESOURCE Resource, 26 IN PKLOCK_QUEUE_HANDLE LockHandle) 27 { 28 UNREFERENCED_PARAMETER(Resource); 29 UNREFERENCED_PARAMETER(LockHandle); 30 31 /* Simply disable interrupts */ 32 _disable(); 33 } 34 35 FORCEINLINE 36 VOID 37 ExReleaseResourceLock(IN PERESOURCE Resource, 38 IN PKLOCK_QUEUE_HANDLE LockHandle) 39 { 40 UNREFERENCED_PARAMETER(Resource); 41 UNREFERENCED_PARAMETER(LockHandle); 42 43 /* Simply enable interrupts */ 44 _enable(); 45 } 46 47 #else 48 49 FORCEINLINE 50 VOID 51 ExAcquireResourceLock(IN PERESOURCE Resource, 52 IN PKLOCK_QUEUE_HANDLE LockHandle) 53 { 54 /* Acquire the lock */ 55 KeAcquireInStackQueuedSpinLock(&Resource->SpinLock, LockHandle); 56 } 57 58 FORCEINLINE 59 VOID 60 ExReleaseResourceLock(IN PERESOURCE Resource, 61 IN PKLOCK_QUEUE_HANDLE LockHandle) 62 { 63 UNREFERENCED_PARAMETER(Resource); 64 65 /* Release the lock */ 66 KeReleaseInStackQueuedSpinLock(LockHandle); 67 } 68 69 #endif // !defined(CONFIG_SMP) && !DBG 70 71 /* DATA***********************************************************************/ 72 73 LARGE_INTEGER ExShortTime = {{-100000, -1}}; 74 LARGE_INTEGER ExpTimeout; 75 76 /* Timeout value for resources in 4-second units (7 days) */ 77 ULONG ExpResourceTimeoutCount = 90 * 3600 / 2; // NT value: 648000 (30 days) 78 79 KSPIN_LOCK ExpResourceSpinLock; 80 LIST_ENTRY ExpSystemResourcesList; 81 BOOLEAN ExResourceStrict = TRUE; 82 83 /* PRIVATE FUNCTIONS *********************************************************/ 84 85 #if DBG 86 /*++ 87 * @name ExpVerifyResource 88 * 89 * The ExpVerifyResource routine verifies the correctness of an ERESOURCE 90 * 91 * @param Resource 92 * Pointer to the resource being verified. 93 * 94 * @return None. 95 * 96 * @remarks Only present on DBG builds. 97 * 98 *--*/ 99 VOID 100 NTAPI 101 ExpVerifyResource(IN PERESOURCE Resource) 102 { 103 /* Verify the resource data */ 104 ASSERT((((ULONG_PTR)Resource) & (sizeof(ULONG_PTR) - 1)) == 0); 105 ASSERT(!Resource->SharedWaiters || 106 Resource->SharedWaiters->Header.Type == SemaphoreObject); 107 ASSERT(!Resource->SharedWaiters || 108 Resource->SharedWaiters->Header.Size == (sizeof(KSEMAPHORE) / sizeof(ULONG))); 109 ASSERT(!Resource->ExclusiveWaiters || 110 Resource->ExclusiveWaiters->Header.Type == SynchronizationEvent); 111 ASSERT(!Resource->ExclusiveWaiters || 112 Resource->ExclusiveWaiters->Header.Size == (sizeof(KEVENT) / sizeof(ULONG))); 113 } 114 115 /*++ 116 * @name ExpCheckForApcsDisabled 117 * 118 * The ExpCheckForApcsDisabled routine checks if Kernel APCs are still 119 * enabled when they should be disabled, and optionally breakpoints. 120 * 121 * @param Irql 122 * Specifies the IRQL during the acquire attempt. 123 * 124 * @param Resource 125 * Pointer to the resource being checked. 126 * 127 * @param Thread 128 * Pointer to the thread being checked. 129 * 130 * @return None. 131 * 132 * @remarks Only present on DBG builds. Depends on ExResourceStrict value. 133 * 134 *--*/ 135 VOID 136 NTAPI 137 ExpCheckForApcsDisabled(IN KIRQL Irql, 138 IN PERESOURCE Resource, 139 IN PKTHREAD Thread) 140 { 141 /* Check if we should care and check if we should break */ 142 if ((ExResourceStrict) && 143 (Irql < APC_LEVEL) && 144 !(((PETHREAD)Thread)->SystemThread) && 145 !(Thread->CombinedApcDisable)) 146 { 147 /* Bad! */ 148 DPRINT1("EX: resource: APCs still enabled before resource %p acquire/release " 149 "!!!\n", Resource); 150 DbgBreakPoint(); 151 } 152 } 153 #else 154 #define ExpVerifyResource(r) 155 #define ExpCheckForApcsDisabled(b,r,t) 156 #endif 157 158 /*++ 159 * @name ExpResourceInitialization 160 * 161 * The ExpResourceInitialization routine initializes resources for use. 162 * 163 * @param None. 164 * 165 * @return None. 166 * 167 * @remarks This routine should only be called once, during system startup. 168 * 169 *--*/ 170 CODE_SEG("INIT") 171 VOID 172 NTAPI 173 ExpResourceInitialization(VOID) 174 { 175 /* Setup the timeout */ 176 ExpTimeout.QuadPart = Int32x32To64(4, -10000000); 177 InitializeListHead(&ExpSystemResourcesList); 178 KeInitializeSpinLock(&ExpResourceSpinLock); 179 } 180 181 /*++ 182 * @name ExpAllocateExclusiveWaiterEvent 183 * 184 * The ExpAllocateExclusiveWaiterEvent routine creates the event that will 185 * be used by exclusive waiters on the resource. 186 * 187 * @param Resource 188 * Pointer to the resource. 189 * 190 * @param LockHandle 191 * Pointer to in-stack queued spinlock. 192 * 193 * @return None. 194 * 195 * @remarks The pointer to the event must be atomically set. 196 * 197 *--*/ 198 VOID 199 NTAPI 200 ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource, 201 IN PKLOCK_QUEUE_HANDLE LockHandle) 202 { 203 PKEVENT Event; 204 205 /* Release the lock */ 206 ExReleaseResourceLock(Resource, LockHandle); 207 208 /* Loop as long as we keep running out of memory */ 209 do 210 { 211 /* Allocate the event */ 212 Event = ExAllocatePoolWithTag(NonPagedPool, 213 sizeof(KEVENT), 214 TAG_RESOURCE_EVENT); 215 if (Event) 216 { 217 /* Initialize it */ 218 KeInitializeEvent(Event, SynchronizationEvent, FALSE); 219 220 /* Set it */ 221 if (InterlockedCompareExchangePointer((PVOID*)&Resource->ExclusiveWaiters, 222 Event, 223 NULL)) 224 { 225 /* Someone already set it, free our event */ 226 DPRINT1("WARNING: Handling race condition\n"); 227 ExFreePoolWithTag(Event, TAG_RESOURCE_EVENT); 228 } 229 230 break; 231 } 232 233 /* Wait a bit before trying again */ 234 KeDelayExecutionThread(KernelMode, FALSE, &ExShortTime); 235 } while (TRUE); 236 237 /* Re-acquire the lock */ 238 ExAcquireResourceLock(Resource, LockHandle); 239 } 240 241 /*++ 242 * @name ExpAllocateSharedWaiterSemaphore 243 * 244 * The ExpAllocateSharedWaiterSemaphore routine creates the semaphore that 245 * will be used by shared waiters on the resource. 246 * 247 * @param Resource 248 * Pointer to the resource. 249 * 250 * @param LockHandle 251 * Pointer to in-stack queued spinlock. 252 * 253 * @return None. 254 * 255 * @remarks The pointer to the semaphore must be atomically set. 256 * 257 *--*/ 258 VOID 259 NTAPI 260 ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource, 261 IN PKLOCK_QUEUE_HANDLE LockHandle) 262 { 263 PKSEMAPHORE Semaphore; 264 265 /* Release the lock */ 266 ExReleaseResourceLock(Resource, LockHandle); 267 268 /* Loop as long as we keep running out of memory */ 269 do 270 { 271 /* Allocate the semaphore */ 272 Semaphore = ExAllocatePoolWithTag(NonPagedPool, 273 sizeof(KSEMAPHORE), 274 TAG_RESOURCE_SEMAPHORE); 275 if (Semaphore) 276 { 277 /* Initialize it */ 278 KeInitializeSemaphore(Semaphore, 0, MAXLONG); 279 280 /* Set it */ 281 if (InterlockedCompareExchangePointer((PVOID*)&Resource->SharedWaiters, 282 Semaphore, 283 NULL)) 284 { 285 /* Someone already set it, free our semaphore */ 286 DPRINT1("WARNING: Handling race condition\n"); 287 ExFreePoolWithTag(Semaphore, TAG_RESOURCE_SEMAPHORE); 288 } 289 290 break; 291 } 292 293 /* Wait a bit before trying again */ 294 KeDelayExecutionThread(KernelMode, FALSE, &ExShortTime); 295 } while (TRUE); 296 297 /* Re-acquire the lock */ 298 ExAcquireResourceLock(Resource, LockHandle); 299 } 300 301 /*++ 302 * @name ExpExpandResourceOwnerTable 303 * 304 * The ExpExpandResourceOwnerTable routine expands the owner table of the 305 * specified resource. 306 * 307 * @param Resource 308 * Pointer to the resource. 309 * 310 * @param LockHandle 311 * Pointer to in-stack queued spinlock. 312 * 313 * @return None. 314 * 315 * @remarks None. 316 * 317 *--*/ 318 VOID 319 NTAPI 320 ExpExpandResourceOwnerTable(IN PERESOURCE Resource, 321 IN PKLOCK_QUEUE_HANDLE LockHandle) 322 { 323 POWNER_ENTRY Owner, Table; 324 KIRQL OldIrql; 325 ULONG NewSize, OldSize; 326 327 /* Get the owner table */ 328 Owner = Resource->OwnerTable; 329 if (!Owner) 330 { 331 /* Start with the default size of 3 */ 332 OldSize = 0; 333 NewSize = 3; 334 } 335 else 336 { 337 /* Add 4 more entries */ 338 OldSize = Owner->TableSize; 339 NewSize = OldSize + 4; 340 } 341 342 /* Release the lock */ 343 ExReleaseResourceLock(Resource, LockHandle); 344 345 /* Allocate memory for the table */ 346 Table = ExAllocatePoolWithTag(NonPagedPool, 347 NewSize * sizeof(OWNER_ENTRY), 348 TAG_RESOURCE_TABLE); 349 350 /* Zero the table */ 351 RtlZeroMemory(Table + OldSize, 352 (NewSize - OldSize) * sizeof(OWNER_ENTRY)); 353 354 /* Lock the resource */ 355 ExAcquireResourceLock(Resource, LockHandle); 356 357 /* Make sure nothing has changed */ 358 if ((Owner != Resource->OwnerTable) || 359 ((Owner) && (OldSize != Owner->TableSize))) 360 { 361 /* Resource changed while we weren't holding the lock; bail out */ 362 ExReleaseResourceLock(Resource, LockHandle); 363 ExFreePoolWithTag(Table, TAG_RESOURCE_TABLE); 364 } 365 else 366 { 367 /* Copy the table */ 368 if (Owner) RtlCopyMemory(Table, Owner, OldSize * sizeof(OWNER_ENTRY)); 369 370 /* Acquire dispatcher lock to prevent thread boosting */ 371 OldIrql = KiAcquireDispatcherLock(); 372 373 /* Set the new table data */ 374 Table->TableSize = NewSize; 375 Resource->OwnerTable = Table; 376 377 /* Release dispatcher lock */ 378 KiReleaseDispatcherLock(OldIrql); 379 380 /* Sanity check */ 381 ExpVerifyResource(Resource); 382 383 /* Release lock */ 384 ExReleaseResourceLock(Resource, LockHandle); 385 386 /* Free the old table */ 387 if (Owner) ExFreePoolWithTag(Owner, TAG_RESOURCE_TABLE); 388 389 /* Set the resource index */ 390 if (!OldSize) OldSize = 1; 391 } 392 393 /* Set the resource index */ 394 KeGetCurrentThread()->ResourceIndex = (UCHAR)OldSize; 395 396 /* Lock the resource again */ 397 ExAcquireResourceLock(Resource, LockHandle); 398 } 399 400 /*++ 401 * @name ExpFindFreeEntry 402 * 403 * The ExpFindFreeEntry routine locates an empty owner entry in the 404 * specified resource. If none was found, then the owner table is 405 * expanded. 406 * 407 * @param Resource 408 * Pointer to the resource. 409 * 410 * @param LockHandle 411 * Pointer to in-stack queued spinlock. 412 * 413 * @return Pointer to an empty OWNER_ENTRY structure. 414 * 415 * @remarks None. 416 * 417 *--*/ 418 POWNER_ENTRY 419 FASTCALL 420 ExpFindFreeEntry(IN PERESOURCE Resource, 421 IN PKLOCK_QUEUE_HANDLE LockHandle) 422 { 423 POWNER_ENTRY Owner, Limit; 424 425 /* Sanity check */ 426 ASSERT(LockHandle != 0); 427 ASSERT(Resource->OwnerEntry.OwnerThread != 0); 428 429 /* Get the current table pointer */ 430 Owner = Resource->OwnerTable; 431 if (Owner) 432 { 433 /* Set the limit, move to the next owner and loop owner entries */ 434 Limit = &Owner[Owner->TableSize]; 435 Owner++; 436 while (Owner->OwnerThread) 437 { 438 /* Move to the next one */ 439 Owner++; 440 441 /* Check if the entry is free */ 442 if (Owner == Limit) goto Expand; 443 } 444 445 /* Update the resource entry */ 446 KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner - Resource->OwnerTable); 447 } 448 else 449 { 450 Expand: 451 /* No free entry, expand the table */ 452 ExpExpandResourceOwnerTable(Resource, LockHandle); 453 Owner = NULL; 454 } 455 456 /* Return the entry found */ 457 return Owner; 458 } 459 460 /*++ 461 * @name ExpFindEntryForThread 462 * 463 * The ExpFindEntryForThread routine locates the owner entry associated with 464 * the specified thread in the given resource. If none was found, then the 465 * owner table is expanded. 466 * 467 * @param Resource 468 * Pointer to the resource. 469 * 470 * @param Thread 471 * Pointer to the thread to find. 472 * 473 * @param LockHandle 474 * Pointer to in-stack queued spinlock. 475 * 476 * @return Pointer to an empty OWNER_ENTRY structure. 477 * 478 * @remarks None. 479 * 480 *--*/ 481 POWNER_ENTRY 482 FASTCALL 483 ExpFindEntryForThread(IN PERESOURCE Resource, 484 IN ERESOURCE_THREAD Thread, 485 IN PKLOCK_QUEUE_HANDLE LockHandle, 486 IN BOOLEAN FirstEntryInelligible) 487 { 488 POWNER_ENTRY FreeEntry, Owner, Limit; 489 490 /* Start by looking in the static array */ 491 Owner = &Resource->OwnerEntry; 492 if (Owner->OwnerThread == Thread) return Owner; 493 494 /* Check if this is a free entry */ 495 if ((FirstEntryInelligible) || (Owner->OwnerThread)) 496 { 497 /* No free entry */ 498 FreeEntry = NULL; 499 } 500 else 501 { 502 /* Use the first entry as our free entry */ 503 FreeEntry = Owner; 504 } 505 506 /* Get the current table pointer */ 507 Owner = Resource->OwnerTable; 508 if (Owner) 509 { 510 /* Set the limit, move to the next owner and loop owner entries */ 511 Limit = &Owner[Owner->TableSize]; 512 Owner++; 513 while (Owner->OwnerThread != Thread) 514 { 515 /* Check if we don't have a free entry */ 516 if (!FreeEntry) 517 { 518 /* Check if this entry is free */ 519 if (!Owner->OwnerThread) 520 { 521 /* Save it as our free entry */ 522 FreeEntry = Owner; 523 } 524 } 525 526 /* Move to the next one */ 527 Owner++; 528 529 /* Check if the entry is free */ 530 if (Owner == Limit) goto Expand; 531 } 532 533 /* Update the resource entry */ 534 KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner - Resource->OwnerTable); 535 return Owner; 536 } 537 else 538 { 539 Expand: 540 /* Check if it's OK to do an expansion */ 541 if (!LockHandle) return NULL; 542 543 /* If we found a free entry by now, return it */ 544 if (FreeEntry) 545 { 546 /* Set the resource index */ 547 KeGetCurrentThread()->ResourceIndex = (UCHAR)(FreeEntry - Resource->OwnerTable); 548 return FreeEntry; 549 } 550 551 /* No free entry, expand the table */ 552 ExpExpandResourceOwnerTable(Resource, LockHandle); 553 return NULL; 554 } 555 } 556 557 /*++ 558 * @name ExpBoostOwnerThread 559 * 560 * The ExpBoostOwnerThread routine increases the priority of a waiting 561 * thread in an attempt to fight a possible deadlock. 562 * 563 * @param Thread 564 * Pointer to the current thread. 565 * 566 * @param OwnerThread 567 * Pointer to thread that owns the resource. 568 * 569 * @return None. 570 * 571 * @remarks None. 572 * 573 *--*/ 574 VOID 575 FASTCALL 576 ExpBoostOwnerThread(IN PKTHREAD Thread, 577 IN PKTHREAD OwnerThread) 578 { 579 /* Make sure the owner thread is a pointer, not an ID */ 580 if (!((ULONG_PTR)OwnerThread & 0x3)) 581 { 582 /* Check if we can actually boost it */ 583 if ((OwnerThread->Priority < Thread->Priority) && 584 (OwnerThread->Priority < 14)) 585 { 586 /* Acquire the thread lock */ 587 KiAcquireThreadLock(Thread); 588 589 /* Set the new priority */ 590 OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority; 591 592 /* Update quantum */ 593 OwnerThread->Quantum = OwnerThread->QuantumReset; 594 595 /* Update the kernel state */ 596 KiSetPriorityThread(OwnerThread, 14); 597 598 /* Release the thread lock */ 599 KiReleaseThreadLock(Thread); 600 } 601 } 602 } 603 604 /*++ 605 * @name ExpWaitForResource 606 * 607 * The ExpWaitForResource routine performs a wait on the specified resource. 608 * 609 * @param Resource 610 * Pointer to the resource to wait on. 611 * 612 * @param OwnerThread 613 * Pointer to object (exclusive event or shared semaphore) to wait on. 614 * 615 * @return None. 616 * 617 * @remarks None. 618 * 619 *--*/ 620 VOID 621 FASTCALL 622 ExpWaitForResource(IN PERESOURCE Resource, 623 IN PVOID Object) 624 { 625 ULONG i; 626 ULONG Size; 627 POWNER_ENTRY Owner; 628 ULONG WaitCount = 0; 629 NTSTATUS Status; 630 LARGE_INTEGER Timeout; 631 PKTHREAD Thread, OwnerThread; 632 #if DBG 633 KLOCK_QUEUE_HANDLE LockHandle; 634 #endif 635 636 /* Increase contention count and use a 5 second timeout */ 637 Resource->ContentionCount++; 638 Timeout.QuadPart = 500 * -10000LL; 639 for (;;) 640 { 641 /* Wait for ownership */ 642 Status = KeWaitForSingleObject(Object, 643 WrResource, 644 KernelMode, 645 FALSE, 646 &Timeout); 647 if (Status != STATUS_TIMEOUT) 648 break; 649 650 /* Increase wait count */ 651 WaitCount++; 652 Timeout = ExpTimeout; 653 654 /* Check if we've exceeded the limit */ 655 if (WaitCount > ExpResourceTimeoutCount) 656 { 657 /* Reset wait count */ 658 WaitCount = 0; 659 #if DBG 660 /* Lock the resource */ 661 ExAcquireResourceLock(Resource, &LockHandle); 662 663 /* Dump debug information */ 664 DPRINT1("Resource @ %p\n", Resource); 665 DPRINT1(" ActiveEntries = %04lx Flags = %s%s%s\n", 666 Resource->ActiveEntries, 667 IsOwnedExclusive(Resource) ? "IsOwnedExclusive " : "", 668 IsSharedWaiting(Resource) ? "SharedWaiter " : "", 669 IsExclusiveWaiting(Resource) ? "ExclusiveWaiter " : ""); 670 DPRINT1(" NumberOfExclusiveWaiters = %04lx\n", 671 Resource->NumberOfExclusiveWaiters); 672 DPRINT1(" Thread = %08lx, Count = %02x\n", 673 Resource->OwnerEntry.OwnerThread, 674 Resource->OwnerEntry.OwnerCount); 675 676 /* Dump out the table too */ 677 Owner = Resource->OwnerTable; 678 if (Owner) 679 { 680 /* Loop every entry */ 681 Size = Owner->TableSize; 682 for (i = 1; i < Size; i++) 683 { 684 /* Print the data */ 685 Owner++; 686 DPRINT1(" Thread = %08lx, Count = %02x\n", 687 Owner->OwnerThread, 688 Owner->OwnerCount); 689 } 690 } 691 692 /* Break */ 693 DbgBreakPoint(); 694 DPRINT1("EX - Rewaiting\n"); 695 ExReleaseResourceLock(Resource, &LockHandle); 696 #endif 697 } 698 699 /* Check if we can boost */ 700 if (IsBoostAllowed(Resource)) 701 { 702 /* Get the current kernel thread and lock the dispatcher */ 703 Thread = KeGetCurrentThread(); 704 Thread->WaitIrql = KiAcquireDispatcherLock(); 705 Thread->WaitNext = TRUE; 706 707 /* Get the owner thread and boost it */ 708 OwnerThread = (PKTHREAD)Resource->OwnerEntry.OwnerThread; 709 if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread); 710 711 /* If it's a shared resource */ 712 if (!IsOwnedExclusive(Resource)) 713 { 714 /* Get the table */ 715 Owner = Resource->OwnerTable; 716 if (Owner) 717 { 718 /* Loop every entry */ 719 Size = Owner->TableSize; 720 for (i = 1; i < Size; i++) 721 { 722 /* Move to next entry */ 723 Owner++; 724 725 /* Get the thread */ 726 OwnerThread = (PKTHREAD)Owner->OwnerThread; 727 728 /* Boost it */ 729 if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread); 730 } 731 } 732 } 733 } 734 } 735 } 736 737 /* FUNCTIONS *****************************************************************/ 738 739 /*++ 740 * @name ExAcquireResourceExclusiveLite 741 * @implemented NT4 742 * 743 * The ExAcquireResourceExclusiveLite routine acquires the given resource 744 * for exclusive access by the calling thread. 745 * 746 * @param Resource 747 * Pointer to the resource to acquire. 748 * 749 * @param Wait 750 * Specifies the routine's behavior whenever the resource cannot be 751 * acquired immediately. 752 * 753 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE 754 * and exclusive access cannot be granted immediately. 755 * 756 * @remarks The caller can release the resource by calling either 757 * ExReleaseResourceLite or ExReleaseResourceForThreadLite. 758 * 759 * Normal kernel APC delivery must be disabled before calling this 760 * routine. Disable normal kernel APC delivery by calling 761 * KeEnterCriticalRegion. Delivery must remain disabled until the 762 * resource is released, at which point it can be reenabled by calling 763 * KeLeaveCriticalRegion. 764 * 765 * For better performance, call ExTryToAcquireResourceExclusiveLite, 766 * rather than calling ExAcquireResourceExclusiveLite with Wait set 767 * to FALSE. 768 * 769 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL < 770 * DISPATCH_LEVEL. 771 * 772 *--*/ 773 BOOLEAN 774 NTAPI 775 ExAcquireResourceExclusiveLite(IN PERESOURCE Resource, 776 IN BOOLEAN Wait) 777 { 778 KLOCK_QUEUE_HANDLE LockHandle; 779 ERESOURCE_THREAD Thread; 780 BOOLEAN Success; 781 782 /* Sanity check */ 783 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0); 784 785 /* Get the thread */ 786 Thread = ExGetCurrentResourceThread(); 787 788 /* Sanity check and validation */ 789 ASSERT(KeIsExecutingDpc() == FALSE); 790 ExpVerifyResource(Resource); 791 792 /* Acquire the lock */ 793 ExAcquireResourceLock(Resource, &LockHandle); 794 ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread); 795 796 /* Check if there is a shared owner or exclusive owner */ 797 TryAcquire: 798 if (Resource->ActiveEntries) 799 { 800 /* Check if it's exclusively owned, and we own it */ 801 if ((IsOwnedExclusive(Resource)) && 802 (Resource->OwnerEntry.OwnerThread == Thread)) 803 { 804 /* Increase the owning count */ 805 Resource->OwnerEntry.OwnerCount++; 806 Success = TRUE; 807 } 808 else 809 { 810 /* 811 * If the caller doesn't want us to wait, we can't acquire the 812 * resource because someone else then us owns it. If we can wait, 813 * then we'll wait. 814 */ 815 if (!Wait) 816 { 817 Success = FALSE; 818 } 819 else 820 { 821 /* Check if it has exclusive waiters */ 822 if (!Resource->ExclusiveWaiters) 823 { 824 /* It doesn't, allocate the event and try acquiring again */ 825 ExpAllocateExclusiveWaiterEvent(Resource, &LockHandle); 826 goto TryAcquire; 827 } 828 829 /* Has exclusive waiters, wait on it */ 830 Resource->NumberOfExclusiveWaiters++; 831 ExReleaseResourceLock(Resource, &LockHandle); 832 ExpWaitForResource(Resource, Resource->ExclusiveWaiters); 833 834 /* Set owner and return success */ 835 Resource->OwnerEntry.OwnerThread = ExGetCurrentResourceThread(); 836 return TRUE; 837 } 838 } 839 } 840 else 841 { 842 /* Nobody owns it, so let's! */ 843 ASSERT(Resource->ActiveEntries == 0); 844 ASSERT(Resource->ActiveCount == 0); 845 Resource->Flag |= ResourceOwnedExclusive; 846 Resource->ActiveEntries = 1; 847 Resource->ActiveCount = 1; 848 Resource->OwnerEntry.OwnerThread = Thread; 849 Resource->OwnerEntry.OwnerCount = 1; 850 Success = TRUE; 851 } 852 853 /* Release the lock and return */ 854 ExReleaseResourceLock(Resource, &LockHandle); 855 return Success; 856 } 857 858 /*++ 859 * @name ExAcquireResourceSharedLite 860 * @implemented NT4 861 * 862 * The ExAcquireResourceSharedLite routine acquires the given resource 863 * for shared access by the calling thread. 864 * 865 * @param Resource 866 * Pointer to the resource to acquire. 867 * 868 * @param Wait 869 * Specifies the routine's behavior whenever the resource cannot be 870 * acquired immediately. 871 * 872 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE 873 * and exclusive access cannot be granted immediately. 874 * 875 * @remarks The caller can release the resource by calling either 876 * ExReleaseResourceLite or ExReleaseResourceForThreadLite. 877 * 878 * Normal kernel APC delivery must be disabled before calling this 879 * routine. Disable normal kernel APC delivery by calling 880 * KeEnterCriticalRegion. Delivery must remain disabled until the 881 * resource is released, at which point it can be reenabled by calling 882 * KeLeaveCriticalRegion. 883 * 884 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL < 885 * DISPATCH_LEVEL. 886 * 887 *--*/ 888 BOOLEAN 889 NTAPI 890 ExAcquireResourceSharedLite(IN PERESOURCE Resource, 891 IN BOOLEAN Wait) 892 { 893 KLOCK_QUEUE_HANDLE LockHandle; 894 ERESOURCE_THREAD Thread; 895 POWNER_ENTRY Owner = NULL; 896 BOOLEAN FirstEntryBusy; 897 898 /* Get the thread */ 899 Thread = ExGetCurrentResourceThread(); 900 901 /* Sanity check and validation */ 902 ASSERT(KeIsExecutingDpc() == FALSE); 903 ExpVerifyResource(Resource); 904 905 /* Acquire the lock */ 906 ExAcquireResourceLock(Resource, &LockHandle); 907 ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread); 908 909 /* Check how many active entries we've got */ 910 while (Resource->ActiveEntries != 0) 911 { 912 /* Check if it's exclusively owned */ 913 if (IsOwnedExclusive(Resource)) 914 { 915 /* Check if we own it */ 916 if (Resource->OwnerEntry.OwnerThread == Thread) 917 { 918 /* Increase the owning count */ 919 Resource->OwnerEntry.OwnerCount++; 920 921 /* Release the lock and return */ 922 ExReleaseResourceLock(Resource, &LockHandle); 923 return TRUE; 924 } 925 926 /* Find a free entry */ 927 Owner = ExpFindFreeEntry(Resource, &LockHandle); 928 if (!Owner) continue; 929 } 930 else 931 { 932 /* Resource is shared, find who owns it */ 933 FirstEntryBusy = IsExclusiveWaiting(Resource); 934 Owner = ExpFindEntryForThread(Resource, 935 Thread, 936 &LockHandle, 937 FirstEntryBusy); 938 if (!Owner) continue; 939 940 /* Is it us? */ 941 if (Owner->OwnerThread == Thread) 942 { 943 /* Increase acquire count and return */ 944 Owner->OwnerCount++; 945 ASSERT(Owner->OwnerCount != 0); 946 947 /* Release the lock and return */ 948 ExReleaseResourceLock(Resource, &LockHandle); 949 return TRUE; 950 } 951 952 /* Try to find if there are exclusive waiters */ 953 if (!FirstEntryBusy) 954 { 955 /* There are none, so acquire it */ 956 Owner->OwnerThread = Thread; 957 Owner->OwnerCount = 1; 958 959 /* Check how many active entries we had */ 960 if (Resource->ActiveEntries == 0) 961 { 962 /* Set initial counts */ 963 ASSERT(Resource->ActiveCount == 0); 964 Resource->ActiveEntries = 1; 965 Resource->ActiveCount = 1; 966 } 967 else 968 { 969 /* Increase active entries */ 970 ASSERT(Resource->ActiveCount == 1); 971 Resource->ActiveEntries++; 972 } 973 974 /* Release the lock and return */ 975 ExReleaseResourceLock(Resource, &LockHandle); 976 return TRUE; 977 } 978 } 979 980 /* If we got here, then we need to wait. Are we allowed? */ 981 if (!Wait) 982 { 983 /* Release the lock and return */ 984 ExReleaseResourceLock(Resource, &LockHandle); 985 return FALSE; 986 } 987 988 /* Check if we have a shared waiters semaphore */ 989 if (!Resource->SharedWaiters) 990 { 991 /* Allocate it and try another acquire */ 992 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle); 993 } 994 else 995 { 996 /* We have shared waiters, wait for it */ 997 break; 998 } 999 } 1000 1001 /* Did we get here because we don't have active entries? */ 1002 if (Resource->ActiveEntries == 0) 1003 { 1004 /* Acquire it */ 1005 ASSERT(Resource->ActiveEntries == 0); 1006 ASSERT(Resource->ActiveCount == 0); 1007 Resource->ActiveEntries = 1; 1008 Resource->ActiveCount = 1; 1009 Resource->OwnerEntry.OwnerThread = Thread; 1010 Resource->OwnerEntry.OwnerCount = 1; 1011 1012 /* Release the lock and return */ 1013 ExReleaseResourceLock(Resource, &LockHandle); 1014 return TRUE; 1015 } 1016 1017 /* Now wait for the resource */ 1018 Owner->OwnerThread = Thread; 1019 Owner->OwnerCount = 1; 1020 Resource->NumberOfSharedWaiters++; 1021 1022 /* Release the lock and return */ 1023 ExReleaseResourceLock(Resource, &LockHandle); 1024 ExpWaitForResource(Resource, Resource->SharedWaiters); 1025 return TRUE; 1026 } 1027 1028 /*++ 1029 * @name ExAcquireSharedStarveExclusive 1030 * @implemented NT4 1031 * 1032 * The ExAcquireSharedStarveExclusive routine acquires the given resource 1033 * shared access without waiting for any pending attempts to acquire 1034 * exclusive access to the same resource. 1035 * 1036 * @param Resource 1037 * Pointer to the resource to acquire. 1038 * 1039 * @param Wait 1040 * Specifies the routine's behavior whenever the resource cannot be 1041 * acquired immediately. 1042 * 1043 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE 1044 * and exclusive access cannot be granted immediately. 1045 * 1046 * @remarks The caller can release the resource by calling either 1047 * ExReleaseResourceLite or ExReleaseResourceForThreadLite. 1048 * 1049 * Normal kernel APC delivery must be disabled before calling this 1050 * routine. Disable normal kernel APC delivery by calling 1051 * KeEnterCriticalRegion. Delivery must remain disabled until the 1052 * resource is released, at which point it can be reenabled by calling 1053 * KeLeaveCriticalRegion. 1054 * 1055 * Callers of ExAcquireSharedStarveExclusive usually need quick access 1056 * to a shared resource in order to save an exclusive accessor from 1057 * doing redundant work. For example, a file system might call this 1058 * routine to modify a cached resource, such as a BCB pinned in the 1059 * cache, before the Cache Manager can acquire exclusive access to the 1060 * resource and write the cache out to disk. 1061 * 1062 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL < 1063 * DISPATCH_LEVEL. 1064 * 1065 *--*/ 1066 BOOLEAN 1067 NTAPI 1068 ExAcquireSharedStarveExclusive(IN PERESOURCE Resource, 1069 IN BOOLEAN Wait) 1070 { 1071 KLOCK_QUEUE_HANDLE LockHandle; 1072 ERESOURCE_THREAD Thread; 1073 POWNER_ENTRY Owner; 1074 1075 /* Get the thread */ 1076 Thread = ExGetCurrentResourceThread(); 1077 1078 /* Sanity check and validation */ 1079 ASSERT(KeIsExecutingDpc() == FALSE); 1080 ExpVerifyResource(Resource); 1081 1082 /* Acquire the lock */ 1083 ExAcquireResourceLock(Resource, &LockHandle); 1084 1085 /* See if anyone owns it */ 1086 TryAcquire: 1087 if (Resource->ActiveEntries == 0) 1088 { 1089 /* Nobody owns it, so let's take control */ 1090 ASSERT(Resource->ActiveEntries == 0); 1091 ASSERT(Resource->ActiveCount == 0); 1092 Resource->ActiveCount = 1; 1093 Resource->ActiveEntries = 1; 1094 Resource->OwnerEntry.OwnerThread = Thread; 1095 Resource->OwnerEntry.OwnerCount = 1; 1096 1097 /* Release the lock and return */ 1098 ExReleaseResourceLock(Resource, &LockHandle); 1099 return TRUE; 1100 } 1101 1102 /* Check if it's exclusively owned */ 1103 if (IsOwnedExclusive(Resource)) 1104 { 1105 /* Check if we own it */ 1106 if (Resource->OwnerEntry.OwnerThread == Thread) 1107 { 1108 /* Increase the owning count */ 1109 Resource->OwnerEntry.OwnerCount++; 1110 1111 /* Release the lock and return */ 1112 ExReleaseResourceLock(Resource, &LockHandle); 1113 return TRUE; 1114 } 1115 1116 /* Find a free entry */ 1117 Owner = ExpFindFreeEntry(Resource, &LockHandle); 1118 if (!Owner) goto TryAcquire; 1119 } 1120 else 1121 { 1122 /* Resource is shared, find who owns it */ 1123 Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, FALSE); 1124 if (!Owner) goto TryAcquire; 1125 1126 /* Is it us? */ 1127 if (Owner->OwnerThread == Thread) 1128 { 1129 /* Increase acquire count and return */ 1130 Owner->OwnerCount++; 1131 ASSERT(Owner->OwnerCount != 0); 1132 1133 /* Release the lock and return */ 1134 ExReleaseResourceLock(Resource, &LockHandle); 1135 return TRUE; 1136 } 1137 1138 /* Acquire it */ 1139 Owner->OwnerThread = Thread; 1140 Owner->OwnerCount = 1; 1141 1142 /* Check how many active entries we had */ 1143 if (Resource->ActiveEntries == 0) 1144 { 1145 /* Set initial counts */ 1146 ASSERT(Resource->ActiveCount == 0); 1147 Resource->ActiveEntries = 1; 1148 Resource->ActiveCount = 1; 1149 } 1150 else 1151 { 1152 /* Increase active entries */ 1153 ASSERT(Resource->ActiveCount == 1); 1154 Resource->ActiveEntries++; 1155 } 1156 1157 /* Release the lock and return */ 1158 ExReleaseResourceLock(Resource, &LockHandle); 1159 return TRUE; 1160 } 1161 1162 /* If we got here, then we need to wait. Are we allowed? */ 1163 if (!Wait) 1164 { 1165 /* Release the lock and return */ 1166 ExReleaseResourceLock(Resource, &LockHandle); 1167 return FALSE; 1168 } 1169 1170 /* Check if we have a shared waiters semaphore */ 1171 if (!Resource->SharedWaiters) 1172 { 1173 /* Allocate it and try another acquire */ 1174 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle); 1175 goto TryAcquire; 1176 } 1177 1178 /* Now wait for the resource */ 1179 Owner->OwnerThread = Thread; 1180 Owner->OwnerCount = 1; 1181 Resource->NumberOfSharedWaiters++; 1182 1183 /* Release the lock and return */ 1184 ExReleaseResourceLock(Resource, &LockHandle); 1185 ExpWaitForResource(Resource, Resource->SharedWaiters); 1186 return TRUE; 1187 } 1188 1189 /*++ 1190 * @name ExAcquireSharedWaitForExclusive 1191 * @implemented NT4 1192 * 1193 * The ExAcquireSharedWaitForExclusive routine acquires the given resource 1194 * for shared access if shared access can be granted and there are no 1195 * exclusive waiters. 1196 * 1197 * @param Resource 1198 * Pointer to the resource to acquire. 1199 * 1200 * @param Wait 1201 * Specifies the routine's behavior whenever the resource cannot be 1202 * acquired immediately. 1203 * 1204 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE 1205 * and exclusive access cannot be granted immediately. 1206 * 1207 * @remarks The caller can release the resource by calling either 1208 * ExReleaseResourceLite or ExReleaseResourceForThreadLite. 1209 * 1210 * Normal kernel APC delivery must be disabled before calling this 1211 * routine. Disable normal kernel APC delivery by calling 1212 * KeEnterCriticalRegion. Delivery must remain disabled until the 1213 * resource is released, at which point it can be reenabled by calling 1214 * KeLeaveCriticalRegion. 1215 * 1216 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL < 1217 * DISPATCH_LEVEL. 1218 * 1219 *--*/ 1220 BOOLEAN 1221 NTAPI 1222 ExAcquireSharedWaitForExclusive(IN PERESOURCE Resource, 1223 IN BOOLEAN Wait) 1224 { 1225 KLOCK_QUEUE_HANDLE LockHandle; 1226 ERESOURCE_THREAD Thread; 1227 POWNER_ENTRY Owner; 1228 1229 /* Get the thread */ 1230 Thread = ExGetCurrentResourceThread(); 1231 1232 /* Sanity check and validation */ 1233 ASSERT(KeIsExecutingDpc() == FALSE); 1234 ExpVerifyResource(Resource); 1235 1236 /* Acquire the lock */ 1237 ExAcquireResourceLock(Resource, &LockHandle); 1238 1239 /* See if nobody owns us */ 1240 TryAcquire: 1241 if (!Resource->ActiveEntries) 1242 { 1243 /* Nobody owns it, so let's take control */ 1244 ASSERT(Resource->ActiveEntries == 0); 1245 ASSERT(Resource->ActiveCount == 0); 1246 Resource->ActiveCount = 1; 1247 Resource->ActiveEntries = 1; 1248 Resource->OwnerEntry.OwnerThread = Thread; 1249 Resource->OwnerEntry.OwnerCount = 1; 1250 1251 /* Release the lock and return */ 1252 ExReleaseResourceLock(Resource, &LockHandle); 1253 return TRUE; 1254 } 1255 1256 /* Check if it's exclusively owned */ 1257 if (IsOwnedExclusive(Resource)) 1258 { 1259 /* Check if we own it */ 1260 if (Resource->OwnerEntry.OwnerThread == Thread) 1261 { 1262 /* Increase the owning count */ 1263 Resource->OwnerEntry.OwnerCount++; 1264 1265 /* Release the lock and return */ 1266 ExReleaseResourceLock(Resource, &LockHandle); 1267 return TRUE; 1268 } 1269 1270 /* Find a free entry */ 1271 Owner = ExpFindFreeEntry(Resource, &LockHandle); 1272 if (!Owner) goto TryAcquire; 1273 } 1274 else 1275 { 1276 /* Try to find if there are exclusive waiters */ 1277 if (IsExclusiveWaiting(Resource)) 1278 { 1279 /* We have to wait for the exclusive waiter to be done */ 1280 if (!Wait) 1281 { 1282 /* So bail out if we're not allowed */ 1283 ExReleaseResourceLock(Resource, &LockHandle); 1284 return FALSE; 1285 } 1286 1287 /* Check if we have a shared waiters semaphore */ 1288 if (!Resource->SharedWaiters) 1289 { 1290 /* Allocate one and try again */ 1291 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle); 1292 goto TryAcquire; 1293 } 1294 1295 /* Now wait for the resource */ 1296 Resource->NumberOfSharedWaiters++; 1297 ExReleaseResourceLock(Resource, &LockHandle); 1298 ExpWaitForResource(Resource, Resource->SharedWaiters); 1299 1300 /* Get the lock back */ 1301 ExAcquireResourceLock(Resource, &LockHandle); 1302 1303 /* Find who owns it now */ 1304 while (!(Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, TRUE))); 1305 1306 /* Sanity checks */ 1307 ASSERT(IsOwnedExclusive(Resource) == FALSE); 1308 ASSERT(Resource->ActiveEntries > 0); 1309 ASSERT(Owner->OwnerThread != Thread); 1310 1311 /* Take control */ 1312 Owner->OwnerThread = Thread; 1313 Owner->OwnerCount = 1; 1314 1315 /* Release the lock and return */ 1316 ExReleaseResourceLock(Resource, &LockHandle); 1317 return TRUE; 1318 } 1319 else 1320 { 1321 /* Resource is shared, find who owns it */ 1322 Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, FALSE); 1323 if (!Owner) goto TryAcquire; 1324 1325 /* Is it us? */ 1326 if (Owner->OwnerThread == Thread) 1327 { 1328 /* Increase acquire count and return */ 1329 Owner->OwnerCount++; 1330 ASSERT(Owner->OwnerCount != 0); 1331 1332 /* Release the lock and return */ 1333 ExReleaseResourceLock(Resource, &LockHandle); 1334 return TRUE; 1335 } 1336 1337 /* No exclusive waiters, so acquire it */ 1338 Owner->OwnerThread = Thread; 1339 Owner->OwnerCount = 1; 1340 1341 /* Check how many active entries we had */ 1342 if (Resource->ActiveEntries == 0) 1343 { 1344 /* Set initial counts */ 1345 ASSERT(Resource->ActiveCount == 0); 1346 Resource->ActiveEntries = 1; 1347 Resource->ActiveCount = 1; 1348 } 1349 else 1350 { 1351 /* Increase active entries */ 1352 ASSERT(Resource->ActiveCount == 1); 1353 Resource->ActiveEntries++; 1354 } 1355 1356 /* Release the lock and return */ 1357 ExReleaseResourceLock(Resource, &LockHandle); 1358 return TRUE; 1359 } 1360 } 1361 1362 /* We have to wait for the exclusive waiter to be done */ 1363 if (!Wait) 1364 { 1365 /* So bail out if we're not allowed */ 1366 ExReleaseResourceLock(Resource, &LockHandle); 1367 return FALSE; 1368 } 1369 1370 /* Check if we have a shared waiters semaphore */ 1371 if (!Resource->SharedWaiters) 1372 { 1373 /* Allocate one and try again */ 1374 ExpAllocateSharedWaiterSemaphore(Resource,&LockHandle); 1375 goto TryAcquire; 1376 } 1377 1378 /* Take control */ 1379 Owner->OwnerThread = Thread; 1380 Owner->OwnerCount = 1; 1381 Resource->NumberOfSharedWaiters++; 1382 1383 /* Release the lock and return */ 1384 ExReleaseResourceLock(Resource, &LockHandle); 1385 ExpWaitForResource(Resource, Resource->SharedWaiters); 1386 return TRUE; 1387 } 1388 1389 /*++ 1390 * @name ExConvertExclusiveToSharedLite 1391 * @implemented NT4 1392 * 1393 * The ExConvertExclusiveToSharedLite routine converts an exclusively 1394 * acquired resource into a resource that can be acquired shared. 1395 * 1396 * @param Resource 1397 * Pointer to the resource to convert. 1398 * 1399 * @return None. 1400 * 1401 * @remarks Callers of ExConvertExclusiveToSharedLite must be running at IRQL < 1402 * DISPATCH_LEVEL. 1403 * 1404 *--*/ 1405 VOID 1406 NTAPI 1407 ExConvertExclusiveToSharedLite(IN PERESOURCE Resource) 1408 { 1409 ULONG OldWaiters; 1410 KLOCK_QUEUE_HANDLE LockHandle; 1411 1412 /* Sanity checks */ 1413 ASSERT(KeIsExecutingDpc() == FALSE); 1414 ExpVerifyResource(Resource); 1415 ASSERT(IsOwnedExclusive(Resource)); 1416 ASSERT(Resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)PsGetCurrentThread()); 1417 1418 /* Lock the resource */ 1419 ExAcquireResourceLock(Resource, &LockHandle); 1420 1421 /* Erase the exclusive flag */ 1422 Resource->Flag &= ~ResourceOwnedExclusive; 1423 1424 /* Check if we have shared waiters */ 1425 if (IsSharedWaiting(Resource)) 1426 { 1427 /* Make the waiters active owners */ 1428 OldWaiters = Resource->NumberOfSharedWaiters; 1429 Resource->ActiveEntries += OldWaiters; 1430 Resource->NumberOfSharedWaiters = 0; 1431 1432 /* Release lock and wake the waiters */ 1433 ExReleaseResourceLock(Resource, &LockHandle); 1434 KeReleaseSemaphore(Resource->SharedWaiters, 0, OldWaiters, FALSE); 1435 } 1436 else 1437 { 1438 /* Release lock */ 1439 ExReleaseResourceLock(Resource, &LockHandle); 1440 } 1441 } 1442 1443 /*++ 1444 * @name ExDeleteResourceLite 1445 * @implemented NT4 1446 * 1447 * The ExConvertExclusiveToSharedLite routine deletes a given resource 1448 * from the system�s resource list. 1449 * 1450 * @param Resource 1451 * Pointer to the resource to delete. 1452 * 1453 * @return STATUS_SUCCESS if the resource was deleted. 1454 * 1455 * @remarks Callers of ExDeleteResourceLite must be running at IRQL < 1456 * DISPATCH_LEVEL. 1457 * 1458 *--*/ 1459 NTSTATUS 1460 NTAPI 1461 ExDeleteResourceLite(IN PERESOURCE Resource) 1462 { 1463 KLOCK_QUEUE_HANDLE LockHandle; 1464 1465 /* Sanity checks */ 1466 ASSERT(IsSharedWaiting(Resource) == FALSE); 1467 ASSERT(IsExclusiveWaiting(Resource) == FALSE); 1468 ASSERT(KeIsExecutingDpc() == FALSE); 1469 ExpVerifyResource(Resource); 1470 1471 /* Lock the resource */ 1472 KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock, &LockHandle); 1473 1474 /* Remove the resource */ 1475 RemoveEntryList(&Resource->SystemResourcesList); 1476 1477 /* Release the lock */ 1478 KeReleaseInStackQueuedSpinLock(&LockHandle); 1479 1480 /* Free every structure */ 1481 if (Resource->OwnerTable) ExFreePoolWithTag(Resource->OwnerTable, TAG_RESOURCE_TABLE); 1482 if (Resource->SharedWaiters) ExFreePoolWithTag(Resource->SharedWaiters, TAG_RESOURCE_SEMAPHORE); 1483 if (Resource->ExclusiveWaiters) ExFreePoolWithTag(Resource->ExclusiveWaiters, TAG_RESOURCE_EVENT); 1484 1485 /* Return success */ 1486 return STATUS_SUCCESS; 1487 } 1488 1489 /*++ 1490 * @name ExDisableResourceBoostLite 1491 * @implemented NT4 1492 * 1493 * The ExDisableResourceBoostLite routine disables thread boosting for 1494 * the given resource. 1495 * 1496 * @param Resource 1497 * Pointer to the resource whose thread boosting will be disabled. 1498 * 1499 * @return None. 1500 * 1501 * @remarks None. 1502 * 1503 *--*/ 1504 VOID 1505 NTAPI 1506 ExDisableResourceBoostLite(IN PERESOURCE Resource) 1507 { 1508 KLOCK_QUEUE_HANDLE LockHandle; 1509 1510 /* Sanity check */ 1511 ExpVerifyResource(Resource); 1512 1513 /* Lock the resource */ 1514 ExAcquireResourceLock(Resource, &LockHandle); 1515 1516 /* Remove the flag */ 1517 Resource->Flag |= ResourceHasDisabledPriorityBoost; 1518 1519 /* Release the lock */ 1520 ExReleaseResourceLock(Resource, &LockHandle); 1521 } 1522 1523 /*++ 1524 * @name ExGetExclusiveWaiterCount 1525 * @implemented NT4 1526 * 1527 * The ExGetExclusiveWaiterCount routine returns the number of exclusive 1528 * waiters for the given resource. 1529 * 1530 * @param Resource 1531 * Pointer to the resource to check. 1532 * 1533 * @return The number of exclusive waiters. 1534 * 1535 * @remarks None. 1536 * 1537 *--*/ 1538 ULONG 1539 NTAPI 1540 ExGetExclusiveWaiterCount(IN PERESOURCE Resource) 1541 { 1542 /* Return the count */ 1543 return Resource->NumberOfExclusiveWaiters; 1544 } 1545 1546 /*++ 1547 * @name ExGetSharedWaiterCount 1548 * @implemented NT4 1549 * 1550 * The ExGetSharedWaiterCount routine returns the number of shared 1551 * waiters for the given resource. 1552 * 1553 * @param Resource 1554 * Pointer to the resource to check. 1555 * 1556 * @return The number of shared waiters. 1557 * 1558 * @remarks None. 1559 * 1560 *--*/ 1561 ULONG 1562 NTAPI 1563 ExGetSharedWaiterCount(IN PERESOURCE Resource) 1564 { 1565 /* Return the count */ 1566 return Resource->NumberOfSharedWaiters; 1567 } 1568 1569 /*++ 1570 * @name ExInitializeResourceLite 1571 * @implemented NT4 1572 * 1573 * The ExInitializeResourceLite routine initializes a resource variable. 1574 * 1575 * @param Resource 1576 * Pointer to the resource to check. 1577 * 1578 * @return STATUS_SUCCESS. 1579 * 1580 * @remarks The storage for ERESOURCE must not be allocated from paged pool. 1581 * 1582 * The storage must be 8-byte aligned. 1583 * 1584 *--*/ 1585 NTSTATUS 1586 NTAPI 1587 ExInitializeResourceLite(IN PERESOURCE Resource) 1588 { 1589 KLOCK_QUEUE_HANDLE LockHandle; 1590 1591 /* Clear the structure */ 1592 RtlZeroMemory(Resource, sizeof(ERESOURCE)); 1593 1594 /* Initialize the lock */ 1595 KeInitializeSpinLock(&Resource->SpinLock); 1596 1597 /* Add it into the system list */ 1598 KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock, &LockHandle); 1599 InsertTailList(&ExpSystemResourcesList, &Resource->SystemResourcesList); 1600 KeReleaseInStackQueuedSpinLock(&LockHandle); 1601 1602 /* Return success */ 1603 return STATUS_SUCCESS; 1604 } 1605 1606 /*++ 1607 * @name ExIsResourceAcquiredExclusiveLite 1608 * @implemented NT4 1609 * 1610 * The ExIsResourceAcquiredExclusiveLite routine returns whether the 1611 * current thread has exclusive access to a given resource. 1612 * 1613 * @param Resource 1614 * Pointer to the resource to check. 1615 * 1616 * @return TRUE if the caller already has exclusive access to the given resource. 1617 * 1618 * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at 1619 * IRQL <= DISPATCH_LEVEL. 1620 * 1621 *--*/ 1622 BOOLEAN 1623 NTAPI 1624 ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource) 1625 { 1626 BOOLEAN IsAcquired = FALSE; 1627 1628 /* Sanity check */ 1629 ExpVerifyResource(Resource); 1630 1631 /* Check if it's exclusively acquired */ 1632 if ((IsOwnedExclusive(Resource)) && 1633 (Resource->OwnerEntry.OwnerThread == ExGetCurrentResourceThread())) 1634 { 1635 /* It is acquired */ 1636 IsAcquired = TRUE; 1637 } 1638 1639 /* Return if it's acquired */ 1640 return IsAcquired; 1641 } 1642 1643 /*++ 1644 * @name ExIsResourceAcquiredSharedLite 1645 * @implemented NT4 1646 * 1647 * The ExIsResourceAcquiredSharedLite routine returns whether the 1648 * current thread has has access (either shared or exclusive) to a 1649 * given resource. 1650 * 1651 * @param Resource 1652 * Pointer to the resource to check. 1653 * 1654 * @return Number of times the caller has acquired the given resource for 1655 * shared or exclusive access. 1656 * 1657 * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at 1658 * IRQL <= DISPATCH_LEVEL. 1659 * 1660 *--*/ 1661 ULONG 1662 NTAPI 1663 ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource) 1664 { 1665 ERESOURCE_THREAD Thread; 1666 ULONG i, Size; 1667 ULONG Count = 0; 1668 KLOCK_QUEUE_HANDLE LockHandle; 1669 POWNER_ENTRY Owner; 1670 1671 /* Sanity check */ 1672 ExpVerifyResource(Resource); 1673 1674 /* Check if nobody owns us */ 1675 if (!Resource->ActiveEntries) return 0; 1676 1677 /* Get the thread */ 1678 Thread = ExGetCurrentResourceThread(); 1679 1680 /* Check if we are in the thread list */ 1681 if (Resource->OwnerEntry.OwnerThread == Thread) 1682 { 1683 /* Found it, return count */ 1684 Count = Resource->OwnerEntry.OwnerCount; 1685 } 1686 else 1687 { 1688 /* We can't own an exclusive resource at this point */ 1689 if (IsOwnedExclusive(Resource)) return 0; 1690 1691 /* Lock the resource */ 1692 ExAcquireResourceLock(Resource, &LockHandle); 1693 1694 /* Not in the list, do a full table look up */ 1695 Owner = Resource->OwnerTable; 1696 if (Owner) 1697 { 1698 /* Get the resource index */ 1699 i = ((PKTHREAD)Thread)->ResourceIndex; 1700 Size = Owner->TableSize; 1701 1702 /* Check if the index is valid and check if we don't match */ 1703 if ((i >= Size) || (Owner[i].OwnerThread != Thread)) 1704 { 1705 /* Sh*t! We need to do a full search */ 1706 for (i = 1; i < Size; i++) 1707 { 1708 /* Move to next owner */ 1709 Owner++; 1710 1711 /* Try to find a match */ 1712 if (Owner->OwnerThread == Thread) 1713 { 1714 /* Finally! */ 1715 Count = Owner->OwnerCount; 1716 break; 1717 } 1718 } 1719 } 1720 else 1721 { 1722 /* We found the match directlry */ 1723 Count = Owner[i].OwnerCount; 1724 } 1725 } 1726 1727 /* Release the lock */ 1728 ExReleaseResourceLock(Resource, &LockHandle); 1729 } 1730 1731 /* Return count */ 1732 return Count; 1733 } 1734 1735 /*++ 1736 * @name ExReinitializeResourceLite 1737 * @implemented NT4 1738 * 1739 * The ExReinitializeResourceLite routine routine reinitializes 1740 * an existing resource variable. 1741 * 1742 * @param Resource 1743 * Pointer to the resource to be reinitialized. 1744 * 1745 * @return STATUS_SUCCESS. 1746 * 1747 * @remarks With a single call to ExReinitializeResource, a driver writer can 1748 * replace three calls: one to ExDeleteResourceLite, another to 1749 * ExAllocatePool, and a third to ExInitializeResourceLite. As 1750 * contention for a resource variable increases, memory is dynamically 1751 * allocated and attached to the resource in order to track this 1752 * contention. As an optimization, ExReinitializeResourceLite retains 1753 * and zeroes this previously allocated memory. 1754 * 1755 * Callers of ExReinitializeResourceLite must be running at 1756 * IRQL <= DISPATCH_LEVEL. 1757 * 1758 *--*/ 1759 NTSTATUS 1760 NTAPI 1761 ExReinitializeResourceLite(IN PERESOURCE Resource) 1762 { 1763 PKEVENT Event; 1764 PKSEMAPHORE Semaphore; 1765 ULONG i, Size; 1766 POWNER_ENTRY Owner; 1767 1768 /* Get the owner table */ 1769 Owner = Resource->OwnerTable; 1770 if (Owner) 1771 { 1772 /* Get the size and loop it */ 1773 Size = Owner->TableSize; 1774 for (i = 0; i < Size; i++) 1775 { 1776 /* Zero the table */ 1777 Owner[i].OwnerThread = 0; 1778 Owner[i].OwnerCount = 0; 1779 } 1780 } 1781 1782 /* Zero the flags and count */ 1783 Resource->Flag = 0; 1784 Resource->ActiveCount = 0; 1785 Resource->ActiveEntries = 0; 1786 1787 /* Reset the semaphore */ 1788 Semaphore = Resource->SharedWaiters; 1789 if (Semaphore) KeInitializeSemaphore(Semaphore, 0, MAXLONG); 1790 1791 /* Reset the event */ 1792 Event = Resource->ExclusiveWaiters; 1793 if (Event) KeInitializeEvent(Event, SynchronizationEvent, FALSE); 1794 1795 /* Clear the resource data */ 1796 Resource->OwnerEntry.OwnerThread = 0; 1797 Resource->OwnerEntry.OwnerCount = 0; 1798 Resource->ContentionCount = 0; 1799 Resource->NumberOfSharedWaiters = 0; 1800 Resource->NumberOfExclusiveWaiters = 0; 1801 return STATUS_SUCCESS; 1802 } 1803 1804 /*++ 1805 * @name ExReleaseResourceLite 1806 * @implemented NT4 1807 * 1808 * The ExReleaseResourceLite routine routine releases 1809 * a specified executive resource owned by the current thread. 1810 * 1811 * @param Resource 1812 * Pointer to the resource to be released. 1813 * 1814 * @return None. 1815 * 1816 * @remarks Callers of ExReleaseResourceLite must be running at 1817 * IRQL <= DISPATCH_LEVEL. 1818 * 1819 *--*/ 1820 VOID 1821 FASTCALL 1822 ExReleaseResourceLite(IN PERESOURCE Resource) 1823 { 1824 /* Just call the For-Thread function */ 1825 ExReleaseResourceForThreadLite(Resource, ExGetCurrentResourceThread()); 1826 } 1827 1828 /*++ 1829 * @name ExReleaseResourceForThreadLite 1830 * @implemented NT4 1831 * 1832 * The ExReleaseResourceForThreadLite routine routine releases 1833 * the input resource of the indicated thread. 1834 * 1835 * @param Resource 1836 * Pointer to the resource to be released. 1837 * 1838 * @param Thread 1839 * Identifies the thread that originally acquired the resource. 1840 * 1841 * @return None. 1842 * 1843 * @remarks Callers of ExReleaseResourceForThreadLite must be running at 1844 * IRQL <= DISPATCH_LEVEL. 1845 * 1846 *--*/ 1847 VOID 1848 NTAPI 1849 ExReleaseResourceForThreadLite(IN PERESOURCE Resource, 1850 IN ERESOURCE_THREAD Thread) 1851 { 1852 ULONG i; 1853 ULONG Count; 1854 KLOCK_QUEUE_HANDLE LockHandle; 1855 POWNER_ENTRY Owner, Limit; 1856 ASSERT(Thread != 0); 1857 1858 /* Get the thread and lock the resource */ 1859 ExAcquireResourceLock(Resource, &LockHandle); 1860 1861 /* Sanity checks */ 1862 ExpVerifyResource(Resource); 1863 ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, KeGetCurrentThread()); 1864 1865 /* Check if it's exclusively owned */ 1866 if (IsOwnedExclusive(Resource)) 1867 { 1868 /* Decrement owner count and check if we're done */ 1869 ASSERT(Resource->OwnerEntry.OwnerThread == Thread); 1870 if (--Resource->OwnerEntry.OwnerCount) 1871 { 1872 /* Done, release lock! */ 1873 ExReleaseResourceLock(Resource, &LockHandle); 1874 return; 1875 } 1876 1877 /* Clear the owner */ 1878 Resource->OwnerEntry.OwnerThread = 0; 1879 1880 /* Decrement the number of active entries */ 1881 ASSERT(Resource->ActiveEntries == 1); 1882 Resource->ActiveEntries--; 1883 1884 /* Check if there are shared waiters */ 1885 if (IsSharedWaiting(Resource)) 1886 { 1887 /* Remove the exclusive flag */ 1888 Resource->Flag &= ~ResourceOwnedExclusive; 1889 1890 /* Give ownage to another thread */ 1891 Count = Resource->NumberOfSharedWaiters; 1892 Resource->ActiveEntries = Count; 1893 Resource->NumberOfSharedWaiters = 0; 1894 1895 /* Release lock and let someone else have it */ 1896 ASSERT(Resource->ActiveCount == 1); 1897 ExReleaseResourceLock(Resource, &LockHandle); 1898 KeReleaseSemaphore(Resource->SharedWaiters, 0, Count, FALSE); 1899 return; 1900 } 1901 else if (IsExclusiveWaiting(Resource)) 1902 { 1903 /* Give exclusive access */ 1904 Resource->OwnerEntry.OwnerThread = 1; 1905 Resource->OwnerEntry.OwnerCount = 1; 1906 Resource->ActiveEntries = 1; 1907 Resource->NumberOfExclusiveWaiters--; 1908 1909 /* Release the lock and give it away */ 1910 ASSERT(Resource->ActiveCount == 1); 1911 ExReleaseResourceLock(Resource, &LockHandle); 1912 KeSetEventBoostPriority(Resource->ExclusiveWaiters, 1913 (PKTHREAD*)&Resource->OwnerEntry.OwnerThread); 1914 return; 1915 } 1916 1917 /* Remove the exclusive flag */ 1918 Resource->Flag &= ~ResourceOwnedExclusive; 1919 Resource->ActiveCount = 0; 1920 } 1921 else 1922 { 1923 /* Check if we are in the thread list */ 1924 if (Resource->OwnerEntry.OwnerThread == Thread) 1925 { 1926 /* Found it, get owner */ 1927 Owner = &Resource->OwnerEntry; 1928 } 1929 else 1930 { 1931 /* Assume no valid index */ 1932 i = 1; 1933 1934 /* If we got a valid pointer, try to get the resource index */ 1935 if (!((ULONG)Thread & 3)) i = ((PKTHREAD)Thread)->ResourceIndex; 1936 1937 /* Do a table lookup */ 1938 Owner = Resource->OwnerTable; 1939 ASSERT(Owner != NULL); 1940 1941 /* Check if we're out of the size and don't match */ 1942 if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread)) 1943 { 1944 /* Get the last entry */ 1945 Limit = &Owner[Owner->TableSize]; 1946 for (;;) 1947 { 1948 /* Move to the next entry */ 1949 Owner++; 1950 1951 /* Make sure we're not out of bounds */ 1952 if (Owner >= Limit) 1953 { 1954 /* Bugcheck, nobody owns us */ 1955 KeBugCheckEx(RESOURCE_NOT_OWNED, 1956 (ULONG_PTR)Resource, 1957 (ULONG_PTR)Thread, 1958 (ULONG_PTR)Resource->OwnerTable, 1959 (ULONG_PTR)3); 1960 } 1961 1962 /* Check for a match */ 1963 if (Owner->OwnerThread == Thread) break; 1964 } 1965 } 1966 else 1967 { 1968 /* Get the entry directly */ 1969 Owner = &Owner[i]; 1970 } 1971 } 1972 1973 /* Sanity checks */ 1974 ASSERT(Owner->OwnerThread == Thread); 1975 ASSERT(Owner->OwnerCount > 0); 1976 1977 /* Check if we are the last owner */ 1978 if (--Owner->OwnerCount) 1979 { 1980 /* There are other owners, release lock */ 1981 ExReleaseResourceLock(Resource, &LockHandle); 1982 return; 1983 } 1984 1985 /* Clear owner */ 1986 Owner->OwnerThread = 0; 1987 1988 /* See if the resource isn't being owned anymore */ 1989 ASSERT(Resource->ActiveEntries > 0); 1990 if (!(--Resource->ActiveEntries)) 1991 { 1992 /* Check if there's an exclusive waiter */ 1993 if (IsExclusiveWaiting(Resource)) 1994 { 1995 /* Give exclusive access */ 1996 Resource->Flag |= ResourceOwnedExclusive; 1997 Resource->OwnerEntry.OwnerThread = 1; 1998 Resource->OwnerEntry.OwnerCount = 1; 1999 Resource->ActiveEntries = 1; 2000 Resource->NumberOfExclusiveWaiters--; 2001 2002 /* Release the lock and give it away */ 2003 ASSERT(Resource->ActiveCount == 1); 2004 ExReleaseResourceLock(Resource, &LockHandle); 2005 KeSetEventBoostPriority(Resource->ExclusiveWaiters, 2006 (PKTHREAD*)&Resource->OwnerEntry.OwnerThread); 2007 return; 2008 } 2009 2010 /* Clear the active count */ 2011 Resource->ActiveCount = 0; 2012 } 2013 } 2014 2015 /* Release lock */ 2016 ExReleaseResourceLock(Resource, &LockHandle); 2017 } 2018 2019 /*++ 2020 * @name ExSetResourceOwnerPointer 2021 * @implemented NT4 2022 * 2023 * The ExSetResourceOwnerPointer routine routine sets the owner thread 2024 * thread pointer for an executive resource. 2025 * 2026 * @param Resource 2027 * Pointer to the resource whose owner to change. 2028 * 2029 * @param OwnerPointer 2030 * Pointer to an owner thread pointer of type ERESOURCE_THREAD. 2031 * 2032 * @return None. 2033 * 2034 * @remarks ExSetResourceOwnerPointer, used in conjunction with 2035 * ExReleaseResourceForThreadLite, provides a means for one thread 2036 * (acting as an resource manager thread) to acquire and release 2037 * resources for use by another thread (acting as a resource user 2038 * thread). 2039 * 2040 * After calling ExSetResourceOwnerPointer for a specific resource, 2041 * the only other routine that can be called for that resource is 2042 * ExReleaseResourceForThreadLite. 2043 * 2044 * Callers of ExSetResourceOwnerPointer must be running at 2045 * IRQL <= DISPATCH_LEVEL. 2046 * 2047 *--*/ 2048 VOID 2049 NTAPI 2050 ExSetResourceOwnerPointer(IN PERESOURCE Resource, 2051 IN PVOID OwnerPointer) 2052 { 2053 ERESOURCE_THREAD Thread; 2054 KLOCK_QUEUE_HANDLE LockHandle; 2055 POWNER_ENTRY Owner, ThisOwner; 2056 2057 /* Sanity check */ 2058 ASSERT((OwnerPointer != 0) && (((ULONG_PTR)OwnerPointer & 3) == 3)); 2059 2060 /* Get the thread */ 2061 Thread = ExGetCurrentResourceThread(); 2062 2063 /* Sanity check */ 2064 ExpVerifyResource(Resource); 2065 2066 /* Lock the resource */ 2067 ExAcquireResourceLock(Resource, &LockHandle); 2068 2069 /* Check if it's exclusive */ 2070 if (IsOwnedExclusive(Resource)) 2071 { 2072 /* If it's exclusive, set the first entry no matter what */ 2073 ASSERT(Resource->OwnerEntry.OwnerThread == Thread); 2074 ASSERT(Resource->OwnerEntry.OwnerCount > 0); 2075 Resource->OwnerEntry.OwnerThread = (ULONG_PTR)OwnerPointer; 2076 } 2077 else 2078 { 2079 /* Set the thread in both entries */ 2080 ThisOwner = ExpFindEntryForThread(Resource, 2081 (ERESOURCE_THREAD)OwnerPointer, 2082 0, 2083 FALSE); 2084 Owner = ExpFindEntryForThread(Resource, Thread, 0, FALSE); 2085 if (!Owner) 2086 { 2087 /* Nobody owns it, crash */ 2088 KeBugCheckEx(RESOURCE_NOT_OWNED, 2089 (ULONG_PTR)Resource, 2090 Thread, 2091 (ULONG_PTR)Resource->OwnerTable, 2092 3); 2093 } 2094 2095 /* Set if we are the owner */ 2096 if (ThisOwner) 2097 { 2098 /* Update data */ 2099 ThisOwner->OwnerCount += Owner->OwnerCount; 2100 Owner->OwnerCount = 0; 2101 Owner->OwnerThread = 0; 2102 ASSERT(Resource->ActiveEntries >= 2); 2103 Resource->ActiveEntries--; 2104 } 2105 else 2106 { 2107 /* Update the owner entry instead */ 2108 Owner->OwnerThread = (ERESOURCE_THREAD)OwnerPointer; 2109 } 2110 } 2111 2112 /* Release the resource */ 2113 ExReleaseResourceLock(Resource, &LockHandle); 2114 } 2115 2116 /*++ 2117 * @name ExTryToAcquireResourceExclusiveLite 2118 * @implemented NT4 2119 * 2120 * The ExTryToAcquireResourceExclusiveLite routine routine attemps to 2121 * acquire the given resource for exclusive access. 2122 * 2123 * @param Resource 2124 * Pointer to the resource to be acquired. 2125 * 2126 * @return TRUE if the given resource has been acquired for the caller. 2127 * 2128 * @remarks Callers of ExTryToAcquireResourceExclusiveLite must be running at 2129 * IRQL < DISPATCH_LEVEL. 2130 * 2131 *--*/ 2132 BOOLEAN 2133 NTAPI 2134 ExTryToAcquireResourceExclusiveLite(IN PERESOURCE Resource) 2135 { 2136 ERESOURCE_THREAD Thread; 2137 KLOCK_QUEUE_HANDLE LockHandle; 2138 BOOLEAN Acquired = FALSE; 2139 2140 /* Sanity check */ 2141 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0); 2142 2143 /* Get the thread */ 2144 Thread = ExGetCurrentResourceThread(); 2145 2146 /* Sanity check and validation */ 2147 ASSERT(KeIsExecutingDpc() == FALSE); 2148 ExpVerifyResource(Resource); 2149 2150 /* Acquire the lock */ 2151 ExAcquireResourceLock(Resource, &LockHandle); 2152 2153 /* Check if there is an owner */ 2154 if (!Resource->ActiveCount) 2155 { 2156 /* No owner, give exclusive access */ 2157 Resource->Flag |= ResourceOwnedExclusive; 2158 Resource->OwnerEntry.OwnerThread = Thread; 2159 Resource->OwnerEntry.OwnerCount = 1; 2160 Resource->ActiveCount = 1; 2161 Resource->ActiveEntries = 1; 2162 Acquired = TRUE; 2163 } 2164 else if ((IsOwnedExclusive(Resource)) && 2165 (Resource->OwnerEntry.OwnerThread == Thread)) 2166 { 2167 /* Do a recursive acquire */ 2168 Resource->OwnerEntry.OwnerCount++; 2169 Acquired = TRUE; 2170 } 2171 2172 /* Release the resource */ 2173 ExReleaseResourceLock(Resource, &LockHandle); 2174 return Acquired; 2175 } 2176 2177 /*++ 2178 * @name ExEnterCriticalRegionAndAcquireResourceExclusive 2179 * @implemented NT5.1 2180 * 2181 * The ExEnterCriticalRegionAndAcquireResourceExclusive enters a critical 2182 * region and then exclusively acquires a resource. 2183 * 2184 * @param Resource 2185 * Pointer to the resource to acquire. 2186 * 2187 * @return Pointer to the Win32K thread pointer of the current thread. 2188 * 2189 * @remarks See ExAcquireResourceExclusiveLite. 2190 * 2191 *--*/ 2192 PVOID 2193 NTAPI 2194 ExEnterCriticalRegionAndAcquireResourceExclusive(IN PERESOURCE Resource) 2195 { 2196 /* Enter critical region */ 2197 KeEnterCriticalRegion(); 2198 2199 /* Acquire the resource */ 2200 NT_VERIFY(ExAcquireResourceExclusiveLite(Resource, TRUE)); 2201 2202 /* Return the Win32 Thread */ 2203 return KeGetCurrentThread()->Win32Thread; 2204 } 2205 2206 /*++ 2207 * @name ExEnterCriticalRegionAndAcquireResourceShared 2208 * @implemented NT5.2 2209 * 2210 * The ExEnterCriticalRegionAndAcquireResourceShared routine 2211 * enters a critical region and then acquires a resource shared. 2212 * 2213 * @param Resource 2214 * Pointer to the resource to acquire. 2215 * 2216 * @return Pointer to the Win32K thread pointer of the current thread. 2217 * 2218 * @remarks See ExAcquireResourceSharedLite. 2219 * 2220 *--*/ 2221 PVOID 2222 NTAPI 2223 ExEnterCriticalRegionAndAcquireResourceShared(IN PERESOURCE Resource) 2224 { 2225 /* Enter critical region */ 2226 KeEnterCriticalRegion(); 2227 2228 /* Acquire the resource */ 2229 NT_VERIFY(ExAcquireResourceSharedLite(Resource, TRUE)); 2230 2231 /* Return the Win32 Thread */ 2232 return KeGetCurrentThread()->Win32Thread; 2233 } 2234 2235 /*++ 2236 * @name ExEnterCriticalRegionAndAcquireSharedWaitForExclusive 2237 * @implemented NT5.2 2238 * 2239 * The ExEnterCriticalRegionAndAcquireSharedWaitForExclusive routine 2240 * enters a critical region and then acquires a resource shared if 2241 * shared access can be granted and there are no exclusive waiters. 2242 * It then acquires the resource exclusively. 2243 * 2244 * @param Resource 2245 * Pointer to the resource to acquire. 2246 * 2247 * @return Pointer to the Win32K thread pointer of the current thread. 2248 * 2249 * @remarks See ExAcquireSharedWaitForExclusive. 2250 * 2251 *--*/ 2252 PVOID 2253 NTAPI 2254 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(IN PERESOURCE Resource) 2255 { 2256 /* Enter critical region */ 2257 KeEnterCriticalRegion(); 2258 2259 /* Acquire the resource */ 2260 NT_VERIFY(ExAcquireSharedWaitForExclusive(Resource, TRUE)); 2261 2262 /* Return the Win32 Thread */ 2263 return KeGetCurrentThread()->Win32Thread; 2264 } 2265 2266 /*++ 2267 * @name ExReleaseResourceAndLeaveCriticalRegion 2268 * @implemented NT5.1 2269 * 2270 * The ExReleaseResourceAndLeaveCriticalRegion release a resource and 2271 * then leaves a critical region. 2272 * 2273 * @param Resource 2274 * Pointer to the resource to release. 2275 * 2276 * @return None 2277 * 2278 * @remarks See ExReleaseResourceLite. 2279 * 2280 *--*/ 2281 VOID 2282 FASTCALL 2283 ExReleaseResourceAndLeaveCriticalRegion(IN PERESOURCE Resource) 2284 { 2285 /* Release the resource */ 2286 ExReleaseResourceLite(Resource); 2287 2288 /* Leave critical region */ 2289 KeLeaveCriticalRegion(); 2290 } 2291