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