1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: lib/rtl/critical.c 5 * PURPOSE: Critical sections 6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7 * Gunnar Dalsnes 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include <rtl.h> 13 14 #define NDEBUG 15 #include <debug.h> 16 17 #define MAX_STATIC_CS_DEBUG_OBJECTS 64 18 19 static RTL_CRITICAL_SECTION RtlCriticalSectionLock; 20 static LIST_ENTRY RtlCriticalSectionList = {&RtlCriticalSectionList, &RtlCriticalSectionList}; 21 static BOOLEAN RtlpCritSectInitialized = FALSE; 22 static RTL_CRITICAL_SECTION_DEBUG RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS]; 23 static BOOLEAN RtlpDebugInfoFreeList[MAX_STATIC_CS_DEBUG_OBJECTS]; 24 25 LARGE_INTEGER RtlpTimeout; 26 BOOLEAN RtlpTimeoutDisable; 27 28 extern BOOLEAN LdrpShutdownInProgress; 29 extern HANDLE LdrpShutdownThreadId; 30 31 /* FUNCTIONS *****************************************************************/ 32 33 #define CRITSECT_HAS_DEBUG_INFO(CriticalSection) \ 34 (((CriticalSection)->DebugInfo != NULL) && \ 35 ((CriticalSection)->DebugInfo != LongToPtr(-1))) 36 37 /*++ 38 * RtlpCreateCriticalSectionSem 39 * 40 * Checks if an Event has been created for the critical section. 41 * 42 * Params: 43 * None 44 * 45 * Returns: 46 * None. Raises an exception if the system call failed. 47 * 48 * Remarks: 49 * None 50 * 51 *--*/ 52 _At_(CriticalSection->LockSemaphore, _Post_notnull_) 53 VOID 54 NTAPI 55 RtlpCreateCriticalSectionSem(PRTL_CRITICAL_SECTION CriticalSection) 56 { 57 HANDLE hEvent = CriticalSection->LockSemaphore; 58 HANDLE hNewEvent; 59 NTSTATUS Status; 60 61 /* Check if we have an event */ 62 if (!hEvent) 63 { 64 /* No, so create it */ 65 Status = NtCreateEvent(&hNewEvent, 66 EVENT_ALL_ACCESS, 67 NULL, 68 SynchronizationEvent, 69 FALSE); 70 if (!NT_SUCCESS(Status)) 71 { 72 DPRINT1("Failed to Create Event!\n"); 73 74 /* 75 * Use INVALID_HANDLE_VALUE (-1) to signal that 76 * the global keyed event must be used. 77 */ 78 hNewEvent = INVALID_HANDLE_VALUE; 79 } 80 81 DPRINT("Created Event: %p\n", hNewEvent); 82 83 /* Exchange the LockSemaphore field with the new handle, if it is still 0 */ 84 if (InterlockedCompareExchangePointer((PVOID*)&CriticalSection->LockSemaphore, 85 (PVOID)hNewEvent, 86 NULL) != NULL) 87 { 88 /* Someone else just created an event */ 89 if (hNewEvent != INVALID_HANDLE_VALUE) 90 { 91 DPRINT("Closing already created event: %p\n", hNewEvent); 92 NtClose(hNewEvent); 93 } 94 } 95 } 96 97 return; 98 } 99 100 /*++ 101 * RtlpWaitForCriticalSection 102 * 103 * Slow path of RtlEnterCriticalSection. Waits on an Event Object. 104 * 105 * Params: 106 * CriticalSection - Critical section to acquire. 107 * 108 * Returns: 109 * STATUS_SUCCESS, or raises an exception if a deadlock is occuring. 110 * 111 * Remarks: 112 * None 113 * 114 *--*/ 115 NTSTATUS 116 NTAPI 117 RtlpWaitForCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 118 { 119 NTSTATUS Status; 120 EXCEPTION_RECORD ExceptionRecord; 121 BOOLEAN LastChance = FALSE; 122 123 /* Increase the Debug Entry count */ 124 DPRINT("Waiting on Critical Section Event: %p %p\n", 125 CriticalSection, 126 CriticalSection->LockSemaphore); 127 128 if (CRITSECT_HAS_DEBUG_INFO(CriticalSection)) 129 CriticalSection->DebugInfo->EntryCount++; 130 131 /* 132 * If we're shutting down the process, we're allowed to acquire any 133 * critical sections by force (the loader lock in particular) 134 */ 135 if (LdrpShutdownInProgress && 136 LdrpShutdownThreadId == NtCurrentTeb()->RealClientId.UniqueThread) 137 { 138 DPRINT("Forcing ownership of critical section %p\n", CriticalSection); 139 return STATUS_SUCCESS; 140 } 141 142 /* Do we have an Event yet? */ 143 if (!CriticalSection->LockSemaphore) 144 { 145 RtlpCreateCriticalSectionSem(CriticalSection); 146 } 147 148 for (;;) 149 { 150 /* Increase the number of times we've had contention */ 151 if (CRITSECT_HAS_DEBUG_INFO(CriticalSection)) 152 CriticalSection->DebugInfo->ContentionCount++; 153 154 /* Check if allocating the event failed */ 155 if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE) 156 { 157 /* Use the global keyed event (NULL as keyed event handle) */ 158 Status = NtWaitForKeyedEvent(NULL, 159 CriticalSection, 160 FALSE, 161 (RtlpTimeoutDisable ? NULL : &RtlpTimeout)); 162 } 163 else 164 { 165 /* Wait on the Event */ 166 Status = NtWaitForSingleObject(CriticalSection->LockSemaphore, 167 FALSE, 168 (RtlpTimeoutDisable ? NULL : &RtlpTimeout)); 169 } 170 171 /* We have Timed out */ 172 if (Status == STATUS_TIMEOUT) 173 { 174 /* Is this the 2nd time we've timed out? */ 175 if (LastChance) 176 { 177 ERROR_DBGBREAK("Deadlock: 0x%p\n", CriticalSection); 178 179 /* Yes it is, we are raising an exception */ 180 ExceptionRecord.ExceptionCode = STATUS_POSSIBLE_DEADLOCK; 181 ExceptionRecord.ExceptionFlags = 0; 182 ExceptionRecord.ExceptionRecord = NULL; 183 ExceptionRecord.ExceptionAddress = RtlRaiseException; 184 ExceptionRecord.NumberParameters = 1; 185 ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)CriticalSection; 186 RtlRaiseException(&ExceptionRecord); 187 } 188 189 /* One more try */ 190 LastChance = TRUE; 191 } 192 else 193 { 194 /* If we are here, everything went fine */ 195 return STATUS_SUCCESS; 196 } 197 } 198 } 199 200 /*++ 201 * RtlpUnWaitCriticalSection 202 * 203 * Slow path of RtlLeaveCriticalSection. Fires an Event Object. 204 * 205 * Params: 206 * CriticalSection - Critical section to release. 207 * 208 * Returns: 209 * None. Raises an exception if the system call failed. 210 * 211 * Remarks: 212 * None 213 * 214 *--*/ 215 VOID 216 NTAPI 217 RtlpUnWaitCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 218 { 219 NTSTATUS Status; 220 221 /* Do we have an Event yet? */ 222 if (!CriticalSection->LockSemaphore) 223 { 224 RtlpCreateCriticalSectionSem(CriticalSection); 225 } 226 227 /* Signal the Event */ 228 DPRINT("Signaling Critical Section Event: %p, %p\n", 229 CriticalSection, 230 CriticalSection->LockSemaphore); 231 232 /* Check if this critical section needs to use the keyed event */ 233 if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE) 234 { 235 /* Release keyed event */ 236 Status = NtReleaseKeyedEvent(NULL, CriticalSection, FALSE, &RtlpTimeout); 237 } 238 else 239 { 240 /* Set the event */ 241 Status = NtSetEvent(CriticalSection->LockSemaphore, NULL); 242 } 243 244 if (!NT_SUCCESS(Status)) 245 { 246 /* We've failed */ 247 DPRINT1("Signaling Failed for: %p, %p, 0x%08lx\n", 248 CriticalSection, 249 CriticalSection->LockSemaphore, 250 Status); 251 RtlRaiseStatus(Status); 252 } 253 } 254 255 /*++ 256 * RtlpInitDeferredCriticalSection 257 * 258 * Initializes the Critical Section implementation. 259 * 260 * Params: 261 * None 262 * 263 * Returns: 264 * None. 265 * 266 * Remarks: 267 * After this call, the Process Critical Section list is protected. 268 * 269 *--*/ 270 VOID 271 NTAPI 272 RtlpInitDeferredCriticalSection(VOID) 273 { 274 /* Initialize the CS Protecting the List */ 275 RtlInitializeCriticalSection(&RtlCriticalSectionLock); 276 277 /* It's now safe to enter it */ 278 RtlpCritSectInitialized = TRUE; 279 } 280 281 /*++ 282 * RtlpAllocateDebugInfo 283 * 284 * Finds or allocates memory for a Critical Section Debug Object 285 * 286 * Params: 287 * None 288 * 289 * Returns: 290 * A pointer to an empty Critical Section Debug Object. 291 * 292 * Remarks: 293 * For optimization purposes, the first 64 entries can be cached. From 294 * then on, future Critical Sections will allocate memory from the heap. 295 * 296 *--*/ 297 PRTL_CRITICAL_SECTION_DEBUG 298 NTAPI 299 RtlpAllocateDebugInfo(VOID) 300 { 301 ULONG i; 302 303 /* Try to allocate from our buffer first */ 304 for (i = 0; i < MAX_STATIC_CS_DEBUG_OBJECTS; i++) 305 { 306 /* Check if Entry is free */ 307 if (!RtlpDebugInfoFreeList[i]) 308 { 309 /* Mark entry in use */ 310 DPRINT("Using entry: %lu. Buffer: %p\n", i, &RtlpStaticDebugInfo[i]); 311 RtlpDebugInfoFreeList[i] = TRUE; 312 313 /* Use free entry found */ 314 return &RtlpStaticDebugInfo[i]; 315 } 316 } 317 318 /* We are out of static buffer, allocate dynamic */ 319 return RtlAllocateHeap(RtlGetProcessHeap(), 320 0, 321 sizeof(RTL_CRITICAL_SECTION_DEBUG)); 322 } 323 324 /*++ 325 * RtlpFreeDebugInfo 326 * 327 * Frees the memory for a Critical Section Debug Object 328 * 329 * Params: 330 * DebugInfo - Pointer to Critical Section Debug Object to free. 331 * 332 * Returns: 333 * None. 334 * 335 * Remarks: 336 * If the pointer is part of the static buffer, then the entry is made 337 * free again. If not, the object is de-allocated from the heap. 338 * 339 *--*/ 340 VOID 341 NTAPI 342 RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo) 343 { 344 SIZE_T EntryId; 345 346 /* Is it part of our cached entries? */ 347 if ((DebugInfo >= RtlpStaticDebugInfo) && 348 (DebugInfo <= &RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS-1])) 349 { 350 /* Yes. zero it out */ 351 RtlZeroMemory(DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG)); 352 353 /* Mark as free */ 354 EntryId = (DebugInfo - RtlpStaticDebugInfo); 355 DPRINT("Freeing from Buffer: %p. Entry: %Iu inside Process: %p\n", 356 DebugInfo, 357 EntryId, 358 NtCurrentTeb()->ClientId.UniqueProcess); 359 RtlpDebugInfoFreeList[EntryId] = FALSE; 360 361 } 362 else if (!DebugInfo->Flags) 363 { 364 /* It's a dynamic one, so free from the heap */ 365 DPRINT("Freeing from Heap: %p inside Process: %p\n", 366 DebugInfo, 367 NtCurrentTeb()->ClientId.UniqueProcess); 368 RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, DebugInfo); 369 } 370 else 371 { 372 /* Wine stores a section name pointer in the Flags member */ 373 DPRINT("Assuming static: %p inside Process: %p\n", 374 DebugInfo, 375 NtCurrentTeb()->ClientId.UniqueProcess); 376 } 377 } 378 379 /*++ 380 * RtlDeleteCriticalSection 381 * @implemented NT4 382 * 383 * Deletes a Critical Section 384 * 385 * Params: 386 * CriticalSection - Critical section to delete. 387 * 388 * Returns: 389 * STATUS_SUCCESS, or error value returned by NtClose. 390 * 391 * Remarks: 392 * The critical section members should not be read after this call. 393 * 394 *--*/ 395 NTSTATUS 396 NTAPI 397 RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 398 { 399 NTSTATUS Status = STATUS_SUCCESS; 400 401 DPRINT("Deleting Critical Section: %p\n", CriticalSection); 402 403 /* Close the Event Object Handle if it exists */ 404 if (CriticalSection->LockSemaphore) 405 { 406 /* In case NtClose fails, return the status */ 407 Status = NtClose(CriticalSection->LockSemaphore); 408 } 409 410 /* Protect List */ 411 RtlEnterCriticalSection(&RtlCriticalSectionLock); 412 413 if (CRITSECT_HAS_DEBUG_INFO(CriticalSection)) 414 { 415 /* Remove it from the list */ 416 RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList); 417 #if 0 418 /* We need to preserve Flags for RtlpFreeDebugInfo */ 419 RtlZeroMemory(CriticalSection->DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG)); 420 #endif 421 } 422 423 /* Unprotect */ 424 RtlLeaveCriticalSection(&RtlCriticalSectionLock); 425 426 if (CRITSECT_HAS_DEBUG_INFO(CriticalSection)) 427 { 428 /* Free it */ 429 RtlpFreeDebugInfo(CriticalSection->DebugInfo); 430 } 431 432 /* Wipe it out */ 433 RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION)); 434 435 /* Return */ 436 return Status; 437 } 438 439 /*++ 440 * RtlSetCriticalSectionSpinCount 441 * @implemented NT4 442 * 443 * Sets the spin count for a critical section. 444 * 445 * Params: 446 * CriticalSection - Critical section to set the spin count for. 447 * 448 * SpinCount - Spin count for the critical section. 449 * 450 * Returns: 451 * STATUS_SUCCESS. 452 * 453 * Remarks: 454 * SpinCount is ignored on single-processor systems. 455 * 456 *--*/ 457 ULONG 458 NTAPI 459 RtlSetCriticalSectionSpinCount(PRTL_CRITICAL_SECTION CriticalSection, 460 ULONG SpinCount) 461 { 462 ULONG OldCount = (ULONG)CriticalSection->SpinCount; 463 464 /* Set to parameter if MP, or to 0 if this is Uniprocessor */ 465 CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0; 466 return OldCount; 467 } 468 469 /*++ 470 * RtlEnterCriticalSection 471 * @implemented NT4 472 * 473 * Waits to gain ownership of the critical section. 474 * 475 * Params: 476 * CriticalSection - Critical section to wait for. 477 * 478 * Returns: 479 * STATUS_SUCCESS. 480 * 481 * Remarks: 482 * Uses a fast-path unless contention happens. 483 * 484 *--*/ 485 NTSTATUS 486 NTAPI 487 RtlEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 488 { 489 HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread; 490 491 /* Try to lock it */ 492 if (InterlockedIncrement(&CriticalSection->LockCount) != 0) 493 { 494 /* We've failed to lock it! Does this thread actually own it? */ 495 if (Thread == CriticalSection->OwningThread) 496 { 497 /* 498 * You own it, so you'll get it when you're done with it! No need to 499 * use the interlocked functions as only the thread who already owns 500 * the lock can modify this data. 501 */ 502 CriticalSection->RecursionCount++; 503 return STATUS_SUCCESS; 504 } 505 506 /* NOTE - CriticalSection->OwningThread can be NULL here because changing 507 this information is not serialized. This happens when thread a 508 acquires the lock (LockCount == 0) and thread b tries to 509 acquire it as well (LockCount == 1) but thread a hasn't had a 510 chance to set the OwningThread! So it's not an error when 511 OwningThread is NULL here! */ 512 513 /* We don't own it, so we must wait for it */ 514 RtlpWaitForCriticalSection(CriticalSection); 515 } 516 517 /* 518 * Lock successful. Changing this information has not to be serialized 519 * because only one thread at a time can actually change it (the one who 520 * acquired the lock)! 521 */ 522 CriticalSection->OwningThread = Thread; 523 CriticalSection->RecursionCount = 1; 524 return STATUS_SUCCESS; 525 } 526 527 /*++ 528 * RtlInitializeCriticalSection 529 * @implemented NT4 530 * 531 * Initialises a new critical section. 532 * 533 * Params: 534 * CriticalSection - Critical section to initialise 535 * 536 * Returns: 537 * STATUS_SUCCESS. 538 * 539 * Remarks: 540 * Simply calls RtlInitializeCriticalSectionAndSpinCount 541 * 542 *--*/ 543 NTSTATUS 544 NTAPI 545 RtlInitializeCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 546 { 547 /* Call the Main Function */ 548 return RtlInitializeCriticalSectionAndSpinCount(CriticalSection, 0); 549 } 550 551 /*++ 552 * RtlInitializeCriticalSectionEx 553 * @implemented NT6.0 554 * 555 * Initialises a new critical section. 556 * 557 * Params: 558 * CriticalSection - Critical section to initialise 559 * 560 * SpinCount - Spin count for the critical section. 561 * 562 * Flags - Flags for initialization. 563 * 564 * Returns: 565 * STATUS_SUCCESS. 566 * 567 * Remarks: 568 * SpinCount is ignored on single-processor systems. 569 * 570 *--*/ 571 NTSTATUS 572 NTAPI 573 RtlInitializeCriticalSectionEx( 574 _Out_ PRTL_CRITICAL_SECTION CriticalSection, 575 _In_ ULONG SpinCount, 576 _In_ ULONG Flags) 577 { 578 PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData; 579 ULONG AllowedFlags; 580 ULONG OsVersion; 581 582 /* Remove lower bits from flags */ 583 Flags &= RTL_CRITICAL_SECTION_ALL_FLAG_BITS; 584 585 /* These flags generally allowed */ 586 AllowedFlags = RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO | 587 RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN | 588 RTL_CRITICAL_SECTION_FLAG_STATIC_INIT; 589 590 /* Flags for Windows 7+ (CHECKME) */ 591 OsVersion = NtCurrentPeb()->OSMajorVersion << 8 | 592 NtCurrentPeb()->OSMinorVersion; 593 if (OsVersion >= _WIN32_WINNT_WIN7) 594 { 595 AllowedFlags |= RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE | 596 RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO; 597 } 598 599 if (Flags & ~AllowedFlags) 600 { 601 return STATUS_INVALID_PARAMETER_3; 602 } 603 604 if (SpinCount & RTL_CRITICAL_SECTION_ALL_FLAG_BITS) 605 { 606 return STATUS_INVALID_PARAMETER_2; 607 } 608 609 /* First things first, set up the Object */ 610 DPRINT("Initializing Critical Section: %p\n", CriticalSection); 611 CriticalSection->LockCount = -1; 612 CriticalSection->RecursionCount = 0; 613 CriticalSection->OwningThread = 0; 614 CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0; 615 CriticalSection->LockSemaphore = 0; 616 617 if (Flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) 618 { 619 CriticalSection->DebugInfo = LongToPtr(-1); 620 } 621 else 622 { 623 /* Allocate the Debug Data */ 624 CritcalSectionDebugData = RtlpAllocateDebugInfo(); 625 DPRINT("Allocated Debug Data: %p inside Process: %p\n", 626 CritcalSectionDebugData, 627 NtCurrentTeb()->ClientId.UniqueProcess); 628 629 if (!CritcalSectionDebugData) 630 { 631 /* This is bad! */ 632 DPRINT1("Couldn't allocate Debug Data for: %p\n", CriticalSection); 633 return STATUS_NO_MEMORY; 634 } 635 636 /* Set it up */ 637 CritcalSectionDebugData->Type = RTL_CRITSECT_TYPE; 638 CritcalSectionDebugData->ContentionCount = 0; 639 CritcalSectionDebugData->EntryCount = 0; 640 CritcalSectionDebugData->CriticalSection = CriticalSection; 641 CritcalSectionDebugData->Flags = 0; 642 CriticalSection->DebugInfo = CritcalSectionDebugData; 643 644 /* 645 * Add it to the List of Critical Sections owned by the process. 646 * If we've initialized the Lock, then use it. If not, then probably 647 * this is the lock initialization itself, so insert it directly. 648 */ 649 if ((CriticalSection != &RtlCriticalSectionLock) && (RtlpCritSectInitialized)) 650 { 651 DPRINT("Securely Inserting into ProcessLocks: %p, %p, %p\n", 652 &CritcalSectionDebugData->ProcessLocksList, 653 CriticalSection, 654 &RtlCriticalSectionList); 655 656 /* Protect List */ 657 RtlEnterCriticalSection(&RtlCriticalSectionLock); 658 659 /* Add this one */ 660 InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList); 661 662 /* Unprotect */ 663 RtlLeaveCriticalSection(&RtlCriticalSectionLock); 664 } 665 else 666 { 667 DPRINT("Inserting into ProcessLocks: %p, %p, %p\n", 668 &CritcalSectionDebugData->ProcessLocksList, 669 CriticalSection, 670 &RtlCriticalSectionList); 671 672 /* Add it directly */ 673 InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList); 674 } 675 } 676 677 return STATUS_SUCCESS; 678 } 679 680 /*++ 681 * RtlInitializeCriticalSectionAndSpinCount 682 * @implemented NT4 683 * 684 * Initialises a new critical section. 685 * 686 * Params: 687 * CriticalSection - Critical section to initialise 688 * 689 * SpinCount - Spin count for the critical section. 690 * 691 * Returns: 692 * STATUS_SUCCESS. 693 * 694 * Remarks: 695 * SpinCount is ignored on single-processor systems. 696 * 697 *--*/ 698 NTSTATUS 699 NTAPI 700 RtlInitializeCriticalSectionAndSpinCount( 701 _Out_ PRTL_CRITICAL_SECTION CriticalSection, 702 _In_ ULONG SpinCount) 703 { 704 SpinCount &= ~RTL_CRITICAL_SECTION_ALL_FLAG_BITS; 705 return RtlInitializeCriticalSectionEx(CriticalSection, SpinCount, 0); 706 } 707 708 /*++ 709 * RtlGetCriticalSectionRecursionCount 710 * @implemented NT5.2 SP1 711 * 712 * Retrieves the recursion count of a given critical section. 713 * 714 * Params: 715 * CriticalSection - Critical section to retrieve its recursion count. 716 * 717 * Returns: 718 * The recursion count. 719 * 720 * Remarks: 721 * We return the recursion count of the critical section if it is owned 722 * by the current thread, and otherwise we return zero. 723 * 724 *--*/ 725 LONG 726 NTAPI 727 RtlGetCriticalSectionRecursionCount(PRTL_CRITICAL_SECTION CriticalSection) 728 { 729 if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread) 730 { 731 /* 732 * The critical section is owned by the current thread, 733 * therefore retrieve its actual recursion count. 734 */ 735 return CriticalSection->RecursionCount; 736 } 737 else 738 { 739 /* 740 * It is not owned by the current thread, so 741 * for this thread there is no recursion. 742 */ 743 return 0; 744 } 745 } 746 747 /*++ 748 * RtlLeaveCriticalSection 749 * @implemented NT4 750 * 751 * Releases a critical section and makes if available for new owners. 752 * 753 * Params: 754 * CriticalSection - Critical section to release. 755 * 756 * Returns: 757 * STATUS_SUCCESS. 758 * 759 * Remarks: 760 * If another thread was waiting, the slow path is entered. 761 * 762 *--*/ 763 NTSTATUS 764 NTAPI 765 RtlLeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 766 { 767 #if DBG 768 HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread; 769 770 /* 771 * In win this case isn't checked. However it's a valid check so it should 772 * only be performed in debug builds! 773 */ 774 if (Thread != CriticalSection->OwningThread) 775 { 776 DPRINT1("Releasing critical section not owned!\n"); 777 return STATUS_INVALID_PARAMETER; 778 } 779 #endif 780 781 /* 782 * Decrease the Recursion Count. No need to do this atomically because only 783 * the thread who holds the lock can call this function (unless the program 784 * is totally screwed... 785 */ 786 if (--CriticalSection->RecursionCount) 787 { 788 if (CriticalSection->RecursionCount < 0) 789 { 790 DPRINT1("CRITICAL SECTION MESS: Section %p is not acquired!\n", CriticalSection); 791 return STATUS_UNSUCCESSFUL; 792 } 793 /* Someone still owns us, but we are free. This needs to be done atomically. */ 794 InterlockedDecrement(&CriticalSection->LockCount); 795 } 796 else 797 { 798 /* 799 * Nobody owns us anymore. No need to do this atomically. 800 * See comment above. 801 */ 802 CriticalSection->OwningThread = 0; 803 804 /* Was someone wanting us? This needs to be done atomically. */ 805 if (-1 != InterlockedDecrement(&CriticalSection->LockCount)) 806 { 807 /* Let him have us */ 808 RtlpUnWaitCriticalSection(CriticalSection); 809 } 810 } 811 812 /* Sucessful! */ 813 return STATUS_SUCCESS; 814 } 815 816 /*++ 817 * RtlTryEnterCriticalSection 818 * @implemented NT4 819 * 820 * Attemps to gain ownership of the critical section without waiting. 821 * 822 * Params: 823 * CriticalSection - Critical section to attempt acquiring. 824 * 825 * Returns: 826 * TRUE if the critical section has been acquired, FALSE otherwise. 827 * 828 * Remarks: 829 * None 830 * 831 *--*/ 832 BOOLEAN 833 NTAPI 834 RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 835 { 836 /* Try to take control */ 837 if (InterlockedCompareExchange(&CriticalSection->LockCount, 0, -1) == -1) 838 { 839 /* It's ours */ 840 CriticalSection->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; 841 CriticalSection->RecursionCount = 1; 842 return TRUE; 843 } 844 else if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread) 845 { 846 /* It's already ours */ 847 InterlockedIncrement(&CriticalSection->LockCount); 848 CriticalSection->RecursionCount++; 849 return TRUE; 850 } 851 852 /* It's not ours */ 853 return FALSE; 854 } 855 856 VOID 857 NTAPI 858 RtlCheckForOrphanedCriticalSections(HANDLE ThreadHandle) 859 { 860 UNIMPLEMENTED; 861 } 862 863 ULONG 864 NTAPI 865 RtlIsCriticalSectionLocked(PRTL_CRITICAL_SECTION CriticalSection) 866 { 867 return CriticalSection->RecursionCount != 0; 868 } 869 870 ULONG 871 NTAPI 872 RtlIsCriticalSectionLockedByThread(PRTL_CRITICAL_SECTION CriticalSection) 873 { 874 return CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread && 875 CriticalSection->RecursionCount != 0; 876 } 877 878 VOID 879 NTAPI 880 RtlpNotOwnerCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 881 { 882 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 883 } 884 885 /* EOF */ 886