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 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 CS Protecting the List */ 269 RtlInitializeCriticalSection(&RtlCriticalSectionLock); 270 271 /* It's now safe to enter it */ 272 RtlpCritSectInitialized = TRUE; 273 } 274 275 /*++ 276 * RtlpAllocateDebugInfo 277 * 278 * Finds or allocates memory for a Critical Section Debug Object 279 * 280 * Params: 281 * None 282 * 283 * Returns: 284 * A pointer to an empty Critical Section Debug Object. 285 * 286 * Remarks: 287 * For optimization purposes, the first 64 entries can be cached. From 288 * then on, future Critical Sections will allocate memory from the heap. 289 * 290 *--*/ 291 PRTL_CRITICAL_SECTION_DEBUG 292 NTAPI 293 RtlpAllocateDebugInfo(VOID) 294 { 295 ULONG i; 296 297 /* Try to allocate from our buffer first */ 298 for (i = 0; i < MAX_STATIC_CS_DEBUG_OBJECTS; i++) 299 { 300 /* Check if Entry is free */ 301 if (!RtlpDebugInfoFreeList[i]) 302 { 303 /* Mark entry in use */ 304 DPRINT("Using entry: %lu. Buffer: %p\n", i, &RtlpStaticDebugInfo[i]); 305 RtlpDebugInfoFreeList[i] = TRUE; 306 307 /* Use free entry found */ 308 return &RtlpStaticDebugInfo[i]; 309 } 310 } 311 312 /* We are out of static buffer, allocate dynamic */ 313 return RtlAllocateHeap(RtlGetProcessHeap(), 314 0, 315 sizeof(RTL_CRITICAL_SECTION_DEBUG)); 316 } 317 318 /*++ 319 * RtlpFreeDebugInfo 320 * 321 * Frees the memory for a Critical Section Debug Object 322 * 323 * Params: 324 * DebugInfo - Pointer to Critical Section Debug Object to free. 325 * 326 * Returns: 327 * None. 328 * 329 * Remarks: 330 * If the pointer is part of the static buffer, then the entry is made 331 * free again. If not, the object is de-allocated from the heap. 332 * 333 *--*/ 334 VOID 335 NTAPI 336 RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo) 337 { 338 SIZE_T EntryId; 339 340 /* Is it part of our cached entries? */ 341 if ((DebugInfo >= RtlpStaticDebugInfo) && 342 (DebugInfo <= &RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS-1])) 343 { 344 /* Yes. zero it out */ 345 RtlZeroMemory(DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG)); 346 347 /* Mark as free */ 348 EntryId = (DebugInfo - RtlpStaticDebugInfo); 349 DPRINT("Freeing from Buffer: %p. Entry: %Iu inside Process: %p\n", 350 DebugInfo, 351 EntryId, 352 NtCurrentTeb()->ClientId.UniqueProcess); 353 RtlpDebugInfoFreeList[EntryId] = FALSE; 354 355 } 356 else if (!DebugInfo->Flags) 357 { 358 /* It's a dynamic one, so free from the heap */ 359 DPRINT("Freeing from Heap: %p inside Process: %p\n", 360 DebugInfo, 361 NtCurrentTeb()->ClientId.UniqueProcess); 362 RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, DebugInfo); 363 } 364 else 365 { 366 /* Wine stores a section name pointer in the Flags member */ 367 DPRINT("Assuming static: %p inside Process: %p\n", 368 DebugInfo, 369 NtCurrentTeb()->ClientId.UniqueProcess); 370 } 371 } 372 373 /*++ 374 * RtlDeleteCriticalSection 375 * @implemented NT4 376 * 377 * Deletes a Critical Section 378 * 379 * Params: 380 * CriticalSection - Critical section to delete. 381 * 382 * Returns: 383 * STATUS_SUCCESS, or error value returned by NtClose. 384 * 385 * Remarks: 386 * The critical section members should not be read after this call. 387 * 388 *--*/ 389 NTSTATUS 390 NTAPI 391 RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 392 { 393 NTSTATUS Status = STATUS_SUCCESS; 394 395 DPRINT("Deleting Critical Section: %p\n", CriticalSection); 396 397 /* Close the Event Object Handle if it exists */ 398 if (CriticalSection->LockSemaphore) 399 { 400 /* In case NtClose fails, return the status */ 401 Status = NtClose(CriticalSection->LockSemaphore); 402 } 403 404 /* Protect List */ 405 RtlEnterCriticalSection(&RtlCriticalSectionLock); 406 407 if (CriticalSection->DebugInfo) 408 { 409 /* Remove it from the list */ 410 RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList); 411 #if 0 412 /* We need to preserve Flags for RtlpFreeDebugInfo */ 413 RtlZeroMemory(CriticalSection->DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG)); 414 #endif 415 } 416 417 /* Unprotect */ 418 RtlLeaveCriticalSection(&RtlCriticalSectionLock); 419 420 if (CriticalSection->DebugInfo) 421 { 422 /* Free it */ 423 RtlpFreeDebugInfo(CriticalSection->DebugInfo); 424 } 425 426 /* Wipe it out */ 427 RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION)); 428 429 /* Return */ 430 return Status; 431 } 432 433 /*++ 434 * RtlSetCriticalSectionSpinCount 435 * @implemented NT4 436 * 437 * Sets the spin count for a critical section. 438 * 439 * Params: 440 * CriticalSection - Critical section to set the spin count for. 441 * 442 * SpinCount - Spin count for the critical section. 443 * 444 * Returns: 445 * STATUS_SUCCESS. 446 * 447 * Remarks: 448 * SpinCount is ignored on single-processor systems. 449 * 450 *--*/ 451 ULONG 452 NTAPI 453 RtlSetCriticalSectionSpinCount(PRTL_CRITICAL_SECTION CriticalSection, 454 ULONG SpinCount) 455 { 456 ULONG OldCount = (ULONG)CriticalSection->SpinCount; 457 458 /* Set to parameter if MP, or to 0 if this is Uniprocessor */ 459 CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0; 460 return OldCount; 461 } 462 463 /*++ 464 * RtlEnterCriticalSection 465 * @implemented NT4 466 * 467 * Waits to gain ownership of the critical section. 468 * 469 * Params: 470 * CriticalSection - Critical section to wait for. 471 * 472 * Returns: 473 * STATUS_SUCCESS. 474 * 475 * Remarks: 476 * Uses a fast-path unless contention happens. 477 * 478 *--*/ 479 NTSTATUS 480 NTAPI 481 RtlEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 482 { 483 HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread; 484 485 /* Try to lock it */ 486 if (InterlockedIncrement(&CriticalSection->LockCount) != 0) 487 { 488 /* We've failed to lock it! Does this thread actually own it? */ 489 if (Thread == CriticalSection->OwningThread) 490 { 491 /* 492 * You own it, so you'll get it when you're done with it! No need to 493 * use the interlocked functions as only the thread who already owns 494 * the lock can modify this data. 495 */ 496 CriticalSection->RecursionCount++; 497 return STATUS_SUCCESS; 498 } 499 500 /* NOTE - CriticalSection->OwningThread can be NULL here because changing 501 this information is not serialized. This happens when thread a 502 acquires the lock (LockCount == 0) and thread b tries to 503 acquire it as well (LockCount == 1) but thread a hasn't had a 504 chance to set the OwningThread! So it's not an error when 505 OwningThread is NULL here! */ 506 507 /* We don't own it, so we must wait for it */ 508 RtlpWaitForCriticalSection(CriticalSection); 509 } 510 511 /* 512 * Lock successful. Changing this information has not to be serialized 513 * because only one thread at a time can actually change it (the one who 514 * acquired the lock)! 515 */ 516 CriticalSection->OwningThread = Thread; 517 CriticalSection->RecursionCount = 1; 518 return STATUS_SUCCESS; 519 } 520 521 /*++ 522 * RtlInitializeCriticalSection 523 * @implemented NT4 524 * 525 * Initialises a new critical section. 526 * 527 * Params: 528 * CriticalSection - Critical section to initialise 529 * 530 * Returns: 531 * STATUS_SUCCESS. 532 * 533 * Remarks: 534 * Simply calls RtlInitializeCriticalSectionAndSpinCount 535 * 536 *--*/ 537 NTSTATUS 538 NTAPI 539 RtlInitializeCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 540 { 541 /* Call the Main Function */ 542 return RtlInitializeCriticalSectionAndSpinCount(CriticalSection, 0); 543 } 544 545 /*++ 546 * RtlInitializeCriticalSectionAndSpinCount 547 * @implemented NT4 548 * 549 * Initialises a new critical section. 550 * 551 * Params: 552 * CriticalSection - Critical section to initialise 553 * 554 * SpinCount - Spin count for the critical section. 555 * 556 * Returns: 557 * STATUS_SUCCESS. 558 * 559 * Remarks: 560 * SpinCount is ignored on single-processor systems. 561 * 562 *--*/ 563 NTSTATUS 564 NTAPI 565 RtlInitializeCriticalSectionAndSpinCount(PRTL_CRITICAL_SECTION CriticalSection, 566 ULONG SpinCount) 567 { 568 PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData; 569 570 /* First things first, set up the Object */ 571 DPRINT("Initializing Critical Section: %p\n", CriticalSection); 572 CriticalSection->LockCount = -1; 573 CriticalSection->RecursionCount = 0; 574 CriticalSection->OwningThread = 0; 575 CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0; 576 CriticalSection->LockSemaphore = 0; 577 578 /* Allocate the Debug Data */ 579 CritcalSectionDebugData = RtlpAllocateDebugInfo(); 580 DPRINT("Allocated Debug Data: %p inside Process: %p\n", 581 CritcalSectionDebugData, 582 NtCurrentTeb()->ClientId.UniqueProcess); 583 584 if (!CritcalSectionDebugData) 585 { 586 /* This is bad! */ 587 DPRINT1("Couldn't allocate Debug Data for: %p\n", CriticalSection); 588 return STATUS_NO_MEMORY; 589 } 590 591 /* Set it up */ 592 CritcalSectionDebugData->Type = RTL_CRITSECT_TYPE; 593 CritcalSectionDebugData->ContentionCount = 0; 594 CritcalSectionDebugData->EntryCount = 0; 595 CritcalSectionDebugData->CriticalSection = CriticalSection; 596 CritcalSectionDebugData->Flags = 0; 597 CriticalSection->DebugInfo = CritcalSectionDebugData; 598 599 /* 600 * Add it to the List of Critical Sections owned by the process. 601 * If we've initialized the Lock, then use it. If not, then probably 602 * this is the lock initialization itself, so insert it directly. 603 */ 604 if ((CriticalSection != &RtlCriticalSectionLock) && (RtlpCritSectInitialized)) 605 { 606 DPRINT("Securely Inserting into ProcessLocks: %p, %p, %p\n", 607 &CritcalSectionDebugData->ProcessLocksList, 608 CriticalSection, 609 &RtlCriticalSectionList); 610 611 /* Protect List */ 612 RtlEnterCriticalSection(&RtlCriticalSectionLock); 613 614 /* Add this one */ 615 InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList); 616 617 /* Unprotect */ 618 RtlLeaveCriticalSection(&RtlCriticalSectionLock); 619 } 620 else 621 { 622 DPRINT("Inserting into ProcessLocks: %p, %p, %p\n", 623 &CritcalSectionDebugData->ProcessLocksList, 624 CriticalSection, 625 &RtlCriticalSectionList); 626 627 /* Add it directly */ 628 InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList); 629 } 630 631 return STATUS_SUCCESS; 632 } 633 634 /*++ 635 * RtlGetCriticalSectionRecursionCount 636 * @implemented NT5.2 SP1 637 * 638 * Retrieves the recursion count of a given critical section. 639 * 640 * Params: 641 * CriticalSection - Critical section to retrieve its recursion count. 642 * 643 * Returns: 644 * The recursion count. 645 * 646 * Remarks: 647 * We return the recursion count of the critical section if it is owned 648 * by the current thread, and otherwise we return zero. 649 * 650 *--*/ 651 LONG 652 NTAPI 653 RtlGetCriticalSectionRecursionCount(PRTL_CRITICAL_SECTION CriticalSection) 654 { 655 if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread) 656 { 657 /* 658 * The critical section is owned by the current thread, 659 * therefore retrieve its actual recursion count. 660 */ 661 return CriticalSection->RecursionCount; 662 } 663 else 664 { 665 /* 666 * It is not owned by the current thread, so 667 * for this thread there is no recursion. 668 */ 669 return 0; 670 } 671 } 672 673 /*++ 674 * RtlLeaveCriticalSection 675 * @implemented NT4 676 * 677 * Releases a critical section and makes if available for new owners. 678 * 679 * Params: 680 * CriticalSection - Critical section to release. 681 * 682 * Returns: 683 * STATUS_SUCCESS. 684 * 685 * Remarks: 686 * If another thread was waiting, the slow path is entered. 687 * 688 *--*/ 689 NTSTATUS 690 NTAPI 691 RtlLeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 692 { 693 #if DBG 694 HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread; 695 696 /* 697 * In win this case isn't checked. However it's a valid check so it should 698 * only be performed in debug builds! 699 */ 700 if (Thread != CriticalSection->OwningThread) 701 { 702 DPRINT1("Releasing critical section not owned!\n"); 703 return STATUS_INVALID_PARAMETER; 704 } 705 #endif 706 707 /* 708 * Decrease the Recursion Count. No need to do this atomically because only 709 * the thread who holds the lock can call this function (unless the program 710 * is totally screwed... 711 */ 712 if (--CriticalSection->RecursionCount) 713 { 714 if (CriticalSection->RecursionCount < 0) 715 { 716 DPRINT1("CRITICAL SECTION MESS: Section %p is not acquired!\n", CriticalSection); 717 return STATUS_UNSUCCESSFUL; 718 } 719 /* Someone still owns us, but we are free. This needs to be done atomically. */ 720 InterlockedDecrement(&CriticalSection->LockCount); 721 } 722 else 723 { 724 /* 725 * Nobody owns us anymore. No need to do this atomically. 726 * See comment above. 727 */ 728 CriticalSection->OwningThread = 0; 729 730 /* Was someone wanting us? This needs to be done atomically. */ 731 if (-1 != InterlockedDecrement(&CriticalSection->LockCount)) 732 { 733 /* Let him have us */ 734 RtlpUnWaitCriticalSection(CriticalSection); 735 } 736 } 737 738 /* Sucessful! */ 739 return STATUS_SUCCESS; 740 } 741 742 /*++ 743 * RtlTryEnterCriticalSection 744 * @implemented NT4 745 * 746 * Attemps to gain ownership of the critical section without waiting. 747 * 748 * Params: 749 * CriticalSection - Critical section to attempt acquiring. 750 * 751 * Returns: 752 * TRUE if the critical section has been acquired, FALSE otherwise. 753 * 754 * Remarks: 755 * None 756 * 757 *--*/ 758 BOOLEAN 759 NTAPI 760 RtlTryEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 761 { 762 /* Try to take control */ 763 if (InterlockedCompareExchange(&CriticalSection->LockCount, 0, -1) == -1) 764 { 765 /* It's ours */ 766 CriticalSection->OwningThread = NtCurrentTeb()->ClientId.UniqueThread; 767 CriticalSection->RecursionCount = 1; 768 return TRUE; 769 } 770 else if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread) 771 { 772 /* It's already ours */ 773 InterlockedIncrement(&CriticalSection->LockCount); 774 CriticalSection->RecursionCount++; 775 return TRUE; 776 } 777 778 /* It's not ours */ 779 return FALSE; 780 } 781 782 VOID 783 NTAPI 784 RtlCheckForOrphanedCriticalSections(HANDLE ThreadHandle) 785 { 786 UNIMPLEMENTED; 787 } 788 789 ULONG 790 NTAPI 791 RtlIsCriticalSectionLocked(PRTL_CRITICAL_SECTION CriticalSection) 792 { 793 return CriticalSection->RecursionCount != 0; 794 } 795 796 ULONG 797 NTAPI 798 RtlIsCriticalSectionLockedByThread(PRTL_CRITICAL_SECTION CriticalSection) 799 { 800 return CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread && 801 CriticalSection->RecursionCount != 0; 802 } 803 804 VOID 805 NTAPI 806 RtlpNotOwnerCriticalSection(PRTL_CRITICAL_SECTION CriticalSection) 807 { 808 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 809 } 810 811 /* EOF */ 812