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