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