[CRT] spawn: define a unicode environment when needed
[reactos.git] / sdk / lib / rtl / critical.c
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 (hEvent != 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 /* Do we have an Event yet? */
118 if (!CriticalSection->LockSemaphore)
119 {
120 RtlpCreateCriticalSectionSem(CriticalSection);
121 }
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 (CriticalSection->DebugInfo)
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 CriticalSection->LockCount = 0;
140 return STATUS_SUCCESS;
141 }
142
143 for (;;)
144 {
145 /* Increase the number of times we've had contention */
146 if (CriticalSection->DebugInfo)
147 CriticalSection->DebugInfo->ContentionCount++;
148
149 /* Check if allocating the event failed */
150 if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE)
151 {
152 /* Use the global keyed event (NULL as keyed event handle) */
153 Status = NtWaitForKeyedEvent(NULL,
154 CriticalSection,
155 FALSE,
156 &RtlpTimeout);
157 }
158 else
159 {
160 /* Wait on the Event */
161 Status = NtWaitForSingleObject(CriticalSection->LockSemaphore,
162 FALSE,
163 &RtlpTimeout);
164 }
165
166 /* We have Timed out */
167 if (Status == STATUS_TIMEOUT)
168 {
169 /* Is this the 2nd time we've timed out? */
170 if (LastChance)
171 {
172 ERROR_DBGBREAK("Deadlock: 0x%p\n", CriticalSection);
173
174 /* Yes it is, we are raising an exception */
175 ExceptionRecord.ExceptionCode = STATUS_POSSIBLE_DEADLOCK;
176 ExceptionRecord.ExceptionFlags = 0;
177 ExceptionRecord.ExceptionRecord = NULL;
178 ExceptionRecord.ExceptionAddress = RtlRaiseException;
179 ExceptionRecord.NumberParameters = 1;
180 ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)CriticalSection;
181 RtlRaiseException(&ExceptionRecord);
182 }
183
184 /* One more try */
185 LastChance = TRUE;
186 }
187 else
188 {
189 /* If we are here, everything went fine */
190 return STATUS_SUCCESS;
191 }
192 }
193 }
194
195 /*++
196 * RtlpUnWaitCriticalSection
197 *
198 * Slow path of RtlLeaveCriticalSection. Fires an Event Object.
199 *
200 * Params:
201 * CriticalSection - Critical section to release.
202 *
203 * Returns:
204 * None. Raises an exception if the system call failed.
205 *
206 * Remarks:
207 * None
208 *
209 *--*/
210 VOID
211 NTAPI
212 RtlpUnWaitCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
213 {
214 NTSTATUS Status;
215
216 /* Do we have an Event yet? */
217 if (!CriticalSection->LockSemaphore)
218 {
219 RtlpCreateCriticalSectionSem(CriticalSection);
220 }
221
222 /* Signal the Event */
223 DPRINT("Signaling Critical Section Event: %p, %p\n",
224 CriticalSection,
225 CriticalSection->LockSemaphore);
226
227 /* Check if this critical section needs to use the keyed event */
228 if (CriticalSection->LockSemaphore == INVALID_HANDLE_VALUE)
229 {
230 /* Release keyed event */
231 Status = NtReleaseKeyedEvent(NULL, CriticalSection, FALSE, &RtlpTimeout);
232 }
233 else
234 {
235 /* Set the event */
236 Status = NtSetEvent(CriticalSection->LockSemaphore, NULL);
237 }
238
239 if (!NT_SUCCESS(Status))
240 {
241 /* We've failed */
242 DPRINT1("Signaling Failed for: %p, %p, 0x%08lx\n",
243 CriticalSection,
244 CriticalSection->LockSemaphore,
245 Status);
246 RtlRaiseStatus(Status);
247 }
248 }
249
250 /*++
251 * RtlpInitDeferedCriticalSection
252 *
253 * Initializes the Critical Section implementation.
254 *
255 * Params:
256 * None
257 *
258 * Returns:
259 * None.
260 *
261 * Remarks:
262 * After this call, the Process Critical Section list is protected.
263 *
264 *--*/
265 VOID
266 NTAPI
267 RtlpInitDeferedCriticalSection(VOID)
268 {
269 /* Initialize the Process Critical Section List */
270 InitializeListHead(&RtlCriticalSectionList);
271
272 /* Initialize the CS Protecting the List */
273 RtlInitializeCriticalSection(&RtlCriticalSectionLock);
274
275 /* It's now safe to enter it */
276 RtlpCritSectInitialized = TRUE;
277 }
278
279 /*++
280 * RtlpAllocateDebugInfo
281 *
282 * Finds or allocates memory for a Critical Section Debug Object
283 *
284 * Params:
285 * None
286 *
287 * Returns:
288 * A pointer to an empty Critical Section Debug Object.
289 *
290 * Remarks:
291 * For optimization purposes, the first 64 entries can be cached. From
292 * then on, future Critical Sections will allocate memory from the heap.
293 *
294 *--*/
295 PRTL_CRITICAL_SECTION_DEBUG
296 NTAPI
297 RtlpAllocateDebugInfo(VOID)
298 {
299 ULONG i;
300
301 /* Try to allocate from our buffer first */
302 for (i = 0; i < MAX_STATIC_CS_DEBUG_OBJECTS; i++)
303 {
304 /* Check if Entry is free */
305 if (!RtlpDebugInfoFreeList[i])
306 {
307 /* Mark entry in use */
308 DPRINT("Using entry: %lu. Buffer: %p\n", i, &RtlpStaticDebugInfo[i]);
309 RtlpDebugInfoFreeList[i] = TRUE;
310
311 /* Use free entry found */
312 return &RtlpStaticDebugInfo[i];
313 }
314 }
315
316 /* We are out of static buffer, allocate dynamic */
317 return RtlAllocateHeap(RtlGetProcessHeap(),
318 0,
319 sizeof(RTL_CRITICAL_SECTION_DEBUG));
320 }
321
322 /*++
323 * RtlpFreeDebugInfo
324 *
325 * Frees the memory for a Critical Section Debug Object
326 *
327 * Params:
328 * DebugInfo - Pointer to Critical Section Debug Object to free.
329 *
330 * Returns:
331 * None.
332 *
333 * Remarks:
334 * If the pointer is part of the static buffer, then the entry is made
335 * free again. If not, the object is de-allocated from the heap.
336 *
337 *--*/
338 VOID
339 NTAPI
340 RtlpFreeDebugInfo(PRTL_CRITICAL_SECTION_DEBUG DebugInfo)
341 {
342 SIZE_T EntryId;
343
344 /* Is it part of our cached entries? */
345 if ((DebugInfo >= RtlpStaticDebugInfo) &&
346 (DebugInfo <= &RtlpStaticDebugInfo[MAX_STATIC_CS_DEBUG_OBJECTS-1]))
347 {
348 /* Yes. zero it out */
349 RtlZeroMemory(DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG));
350
351 /* Mark as free */
352 EntryId = (DebugInfo - RtlpStaticDebugInfo);
353 DPRINT("Freeing from Buffer: %p. Entry: %Iu inside Process: %p\n",
354 DebugInfo,
355 EntryId,
356 NtCurrentTeb()->ClientId.UniqueProcess);
357 RtlpDebugInfoFreeList[EntryId] = FALSE;
358
359 }
360 else if (!DebugInfo->Flags)
361 {
362 /* It's a dynamic one, so free from the heap */
363 DPRINT("Freeing from Heap: %p inside Process: %p\n",
364 DebugInfo,
365 NtCurrentTeb()->ClientId.UniqueProcess);
366 RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, DebugInfo);
367 }
368 else
369 {
370 /* Wine stores a section name pointer in the Flags member */
371 DPRINT("Assuming static: %p inside Process: %p\n",
372 DebugInfo,
373 NtCurrentTeb()->ClientId.UniqueProcess);
374 }
375 }
376
377 /*++
378 * RtlDeleteCriticalSection
379 * @implemented NT4
380 *
381 * Deletes a Critical Section
382 *
383 * Params:
384 * CriticalSection - Critical section to delete.
385 *
386 * Returns:
387 * STATUS_SUCCESS, or error value returned by NtClose.
388 *
389 * Remarks:
390 * The critical section members should not be read after this call.
391 *
392 *--*/
393 NTSTATUS
394 NTAPI
395 RtlDeleteCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
396 {
397 NTSTATUS Status = STATUS_SUCCESS;
398
399 DPRINT("Deleting Critical Section: %p\n", CriticalSection);
400
401 /* Close the Event Object Handle if it exists */
402 if (CriticalSection->LockSemaphore)
403 {
404 /* In case NtClose fails, return the status */
405 Status = NtClose(CriticalSection->LockSemaphore);
406 }
407
408 /* Protect List */
409 RtlEnterCriticalSection(&RtlCriticalSectionLock);
410
411 if (CriticalSection->DebugInfo)
412 {
413 /* Remove it from the list */
414 RemoveEntryList(&CriticalSection->DebugInfo->ProcessLocksList);
415 #if 0
416 /* We need to preserve Flags for RtlpFreeDebugInfo */
417 RtlZeroMemory(CriticalSection->DebugInfo, sizeof(RTL_CRITICAL_SECTION_DEBUG));
418 #endif
419 }
420
421 /* Unprotect */
422 RtlLeaveCriticalSection(&RtlCriticalSectionLock);
423
424 if (CriticalSection->DebugInfo)
425 {
426 /* Free it */
427 RtlpFreeDebugInfo(CriticalSection->DebugInfo);
428 }
429
430 /* Wipe it out */
431 RtlZeroMemory(CriticalSection, sizeof(RTL_CRITICAL_SECTION));
432
433 /* Return */
434 return Status;
435 }
436
437 /*++
438 * RtlSetCriticalSectionSpinCount
439 * @implemented NT4
440 *
441 * Sets the spin count for a critical section.
442 *
443 * Params:
444 * CriticalSection - Critical section to set the spin count for.
445 *
446 * SpinCount - Spin count for the critical section.
447 *
448 * Returns:
449 * STATUS_SUCCESS.
450 *
451 * Remarks:
452 * SpinCount is ignored on single-processor systems.
453 *
454 *--*/
455 ULONG
456 NTAPI
457 RtlSetCriticalSectionSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
458 ULONG SpinCount)
459 {
460 ULONG OldCount = (ULONG)CriticalSection->SpinCount;
461
462 /* Set to parameter if MP, or to 0 if this is Uniprocessor */
463 CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0;
464 return OldCount;
465 }
466
467 /*++
468 * RtlEnterCriticalSection
469 * @implemented NT4
470 *
471 * Waits to gain ownership of the critical section.
472 *
473 * Params:
474 * CriticalSection - Critical section to wait for.
475 *
476 * Returns:
477 * STATUS_SUCCESS.
478 *
479 * Remarks:
480 * Uses a fast-path unless contention happens.
481 *
482 *--*/
483 NTSTATUS
484 NTAPI
485 RtlEnterCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
486 {
487 HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread;
488
489 /* Try to lock it */
490 if (InterlockedIncrement(&CriticalSection->LockCount) != 0)
491 {
492 /* We've failed to lock it! Does this thread actually own it? */
493 if (Thread == CriticalSection->OwningThread)
494 {
495 /*
496 * You own it, so you'll get it when you're done with it! No need to
497 * use the interlocked functions as only the thread who already owns
498 * the lock can modify this data.
499 */
500 CriticalSection->RecursionCount++;
501 return STATUS_SUCCESS;
502 }
503
504 /* NOTE - CriticalSection->OwningThread can be NULL here because changing
505 this information is not serialized. This happens when thread a
506 acquires the lock (LockCount == 0) and thread b tries to
507 acquire it as well (LockCount == 1) but thread a hasn't had a
508 chance to set the OwningThread! So it's not an error when
509 OwningThread is NULL here! */
510
511 /* We don't own it, so we must wait for it */
512 RtlpWaitForCriticalSection(CriticalSection);
513 }
514
515 /*
516 * Lock successful. Changing this information has not to be serialized
517 * because only one thread at a time can actually change it (the one who
518 * acquired the lock)!
519 */
520 CriticalSection->OwningThread = Thread;
521 CriticalSection->RecursionCount = 1;
522 return STATUS_SUCCESS;
523 }
524
525 /*++
526 * RtlInitializeCriticalSection
527 * @implemented NT4
528 *
529 * Initialises a new critical section.
530 *
531 * Params:
532 * CriticalSection - Critical section to initialise
533 *
534 * Returns:
535 * STATUS_SUCCESS.
536 *
537 * Remarks:
538 * Simply calls RtlInitializeCriticalSectionAndSpinCount
539 *
540 *--*/
541 NTSTATUS
542 NTAPI
543 RtlInitializeCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
544 {
545 /* Call the Main Function */
546 return RtlInitializeCriticalSectionAndSpinCount(CriticalSection, 0);
547 }
548
549 /*++
550 * RtlInitializeCriticalSectionAndSpinCount
551 * @implemented NT4
552 *
553 * Initialises a new critical section.
554 *
555 * Params:
556 * CriticalSection - Critical section to initialise
557 *
558 * SpinCount - Spin count for the critical section.
559 *
560 * Returns:
561 * STATUS_SUCCESS.
562 *
563 * Remarks:
564 * SpinCount is ignored on single-processor systems.
565 *
566 *--*/
567 NTSTATUS
568 NTAPI
569 RtlInitializeCriticalSectionAndSpinCount(PRTL_CRITICAL_SECTION CriticalSection,
570 ULONG SpinCount)
571 {
572 PRTL_CRITICAL_SECTION_DEBUG CritcalSectionDebugData;
573
574 /* First things first, set up the Object */
575 DPRINT("Initializing Critical Section: %p\n", CriticalSection);
576 CriticalSection->LockCount = -1;
577 CriticalSection->RecursionCount = 0;
578 CriticalSection->OwningThread = 0;
579 CriticalSection->SpinCount = (NtCurrentPeb()->NumberOfProcessors > 1) ? SpinCount : 0;
580 CriticalSection->LockSemaphore = 0;
581
582 /* Allocate the Debug Data */
583 CritcalSectionDebugData = RtlpAllocateDebugInfo();
584 DPRINT("Allocated Debug Data: %p inside Process: %p\n",
585 CritcalSectionDebugData,
586 NtCurrentTeb()->ClientId.UniqueProcess);
587
588 if (!CritcalSectionDebugData)
589 {
590 /* This is bad! */
591 DPRINT1("Couldn't allocate Debug Data for: %p\n", CriticalSection);
592 return STATUS_NO_MEMORY;
593 }
594
595 /* Set it up */
596 CritcalSectionDebugData->Type = RTL_CRITSECT_TYPE;
597 CritcalSectionDebugData->ContentionCount = 0;
598 CritcalSectionDebugData->EntryCount = 0;
599 CritcalSectionDebugData->CriticalSection = CriticalSection;
600 CritcalSectionDebugData->Flags = 0;
601 CriticalSection->DebugInfo = CritcalSectionDebugData;
602
603 /*
604 * Add it to the List of Critical Sections owned by the process.
605 * If we've initialized the Lock, then use it. If not, then probably
606 * this is the lock initialization itself, so insert it directly.
607 */
608 if ((CriticalSection != &RtlCriticalSectionLock) && (RtlpCritSectInitialized))
609 {
610 DPRINT("Securely Inserting into ProcessLocks: %p, %p, %p\n",
611 &CritcalSectionDebugData->ProcessLocksList,
612 CriticalSection,
613 &RtlCriticalSectionList);
614
615 /* Protect List */
616 RtlEnterCriticalSection(&RtlCriticalSectionLock);
617
618 /* Add this one */
619 InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
620
621 /* Unprotect */
622 RtlLeaveCriticalSection(&RtlCriticalSectionLock);
623 }
624 else
625 {
626 DPRINT("Inserting into ProcessLocks: %p, %p, %p\n",
627 &CritcalSectionDebugData->ProcessLocksList,
628 CriticalSection,
629 &RtlCriticalSectionList);
630
631 /* Add it directly */
632 InsertTailList(&RtlCriticalSectionList, &CritcalSectionDebugData->ProcessLocksList);
633 }
634
635 return STATUS_SUCCESS;
636 }
637
638 /*++
639 * RtlGetCriticalSectionRecursionCount
640 * @implemented NT5.2 SP1
641 *
642 * Retrieves the recursion count of a given critical section.
643 *
644 * Params:
645 * CriticalSection - Critical section to retrieve its recursion count.
646 *
647 * Returns:
648 * The recursion count.
649 *
650 * Remarks:
651 * We return the recursion count of the critical section if it is owned
652 * by the current thread, and otherwise we return zero.
653 *
654 *--*/
655 LONG
656 NTAPI
657 RtlGetCriticalSectionRecursionCount(PRTL_CRITICAL_SECTION CriticalSection)
658 {
659 if (CriticalSection->OwningThread == NtCurrentTeb()->ClientId.UniqueThread)
660 {
661 /*
662 * The critical section is owned by the current thread,
663 * therefore retrieve its actual recursion count.
664 */
665 return CriticalSection->RecursionCount;
666 }
667 else
668 {
669 /*
670 * It is not owned by the current thread, so
671 * for this thread there is no recursion.
672 */
673 return 0;
674 }
675 }
676
677 /*++
678 * RtlLeaveCriticalSection
679 * @implemented NT4
680 *
681 * Releases a critical section and makes if available for new owners.
682 *
683 * Params:
684 * CriticalSection - Critical section to release.
685 *
686 * Returns:
687 * STATUS_SUCCESS.
688 *
689 * Remarks:
690 * If another thread was waiting, the slow path is entered.
691 *
692 *--*/
693 NTSTATUS
694 NTAPI
695 RtlLeaveCriticalSection(PRTL_CRITICAL_SECTION CriticalSection)
696 {
697 #if DBG
698 HANDLE Thread = (HANDLE)NtCurrentTeb()->ClientId.UniqueThread;
699
700 /*
701 * In win this case isn't checked. However it's a valid check so it should
702 * only be performed in debug builds!
703 */
704 if (Thread != CriticalSection->OwningThread)
705 {
706 DPRINT1("Releasing critical section not owned!\n");
707 return STATUS_INVALID_PARAMETER;
708 }
709 #endif
710
711 /*
712 * Decrease the Recursion Count. No need to do this atomically because only
713 * the thread who holds the lock can call this function (unless the program
714 * is totally screwed...
715 */
716 if (--CriticalSection->RecursionCount)
717 {
718 /* Someone still owns us, but we are free. This needs to be done atomically. */
719 InterlockedDecrement(&CriticalSection->LockCount);
720
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 /* EOF */