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)
9 /* INCLUDES *****************************************************************/
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))
21 #if (!(defined(CONFIG_SMP)) && !(DBG))
25 ExAcquireResourceLock(IN PERESOURCE Resource
,
26 IN PKLOCK_QUEUE_HANDLE LockHandle
)
28 UNREFERENCED_PARAMETER(Resource
);
29 UNREFERENCED_PARAMETER(LockHandle
);
31 /* Simply disable interrupts */
37 ExReleaseResourceLock(IN PERESOURCE Resource
,
38 IN PKLOCK_QUEUE_HANDLE LockHandle
)
40 UNREFERENCED_PARAMETER(Resource
);
41 UNREFERENCED_PARAMETER(LockHandle
);
43 /* Simply enable interrupts */
51 ExAcquireResourceLock(IN PERESOURCE Resource
,
52 IN PKLOCK_QUEUE_HANDLE LockHandle
)
54 /* Acquire the lock */
55 KeAcquireInStackQueuedSpinLock(&Resource
->SpinLock
, LockHandle
);
60 ExReleaseResourceLock(IN PERESOURCE Resource
,
61 IN PKLOCK_QUEUE_HANDLE LockHandle
)
63 UNREFERENCED_PARAMETER(Resource
);
65 /* Release the lock */
66 KeReleaseInStackQueuedSpinLock(LockHandle
);
70 /* DATA***********************************************************************/
72 LARGE_INTEGER ExShortTime
= {{-100000, -1}};
73 LARGE_INTEGER ExpTimeout
;
74 ULONG ExpResourceTimeoutCount
= 90 * 3600 / 2;
75 KSPIN_LOCK ExpResourceSpinLock
;
76 LIST_ENTRY ExpSystemResourcesList
;
77 BOOLEAN ExResourceStrict
= TRUE
;
79 /* PRIVATE FUNCTIONS *********************************************************/
83 * @name ExpVerifyResource
85 * The ExpVerifyResource routine verifies the correctness of an ERESOURCE
88 * Pointer to the resource being verified.
92 * @remarks Only present on DBG builds.
97 ExpVerifyResource(IN PERESOURCE Resource
)
99 /* Verify the resource data */
100 ASSERT((((ULONG_PTR
)Resource
) & (sizeof(ULONG_PTR
) - 1)) == 0);
101 ASSERT(!Resource
->SharedWaiters
||
102 Resource
->SharedWaiters
->Header
.Type
== SemaphoreObject
);
103 ASSERT(!Resource
->SharedWaiters
||
104 Resource
->SharedWaiters
->Header
.Size
== (sizeof(KSEMAPHORE
) / sizeof(ULONG
)));
105 ASSERT(!Resource
->ExclusiveWaiters
||
106 Resource
->ExclusiveWaiters
->Header
.Type
== SynchronizationEvent
);
107 ASSERT(!Resource
->ExclusiveWaiters
||
108 Resource
->ExclusiveWaiters
->Header
.Size
== (sizeof(KEVENT
) / sizeof(ULONG
)));
112 * @name ExpCheckForApcsDisabled
114 * The ExpCheckForApcsDisabled routine checks if Kernel APCs are still
115 * enabled when they should be disabled, and optionally breakpoints.
118 * Specifies the IRQL during the acquire attempt.
121 * Pointer to the resource being checked.
124 * Pointer to the thread being checked.
128 * @remarks Only present on DBG builds. Depends on ExResourceStrict value.
133 ExpCheckForApcsDisabled(IN KIRQL Irql
,
134 IN PERESOURCE Resource
,
137 /* Check if we should care and check if we should break */
138 if ((ExResourceStrict
) &&
139 (Irql
< APC_LEVEL
) &&
140 !(((PETHREAD
)Thread
)->SystemThread
) &&
141 !(Thread
->CombinedApcDisable
))
144 DPRINT1("EX: resource: APCs still enabled before resource %p acquire "
150 #define ExpVerifyResource(r)
151 #define ExpCheckForApcsDisabled(b,r,t)
155 * @name ExpResourceInitialization
157 * The ExpResourceInitialization routine initializes resources for use.
163 * @remarks This routine should only be called once, during system startup.
169 ExpResourceInitialization(VOID
)
171 /* Setup the timeout */
172 ExpTimeout
.QuadPart
= Int32x32To64(4, -10000000);
173 InitializeListHead(&ExpSystemResourcesList
);
174 KeInitializeSpinLock(&ExpResourceSpinLock
);
178 * @name ExpAllocateExclusiveWaiterEvent
180 * The ExpAllocateExclusiveWaiterEvent routine creates the event that will
181 * be used by exclusive waiters on the resource.
184 * Pointer to the resource.
187 * Pointer to in-stack queued spinlock.
191 * @remarks The pointer to the event must be atomically set.
196 ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource
,
197 IN PKLOCK_QUEUE_HANDLE LockHandle
)
201 /* Release the lock */
202 ExReleaseResourceLock(Resource
, LockHandle
);
204 /* Loop as long as we keep running out of memory */
207 /* Allocate the event */
208 Event
= ExAllocatePoolWithTag(NonPagedPool
,
214 KeInitializeEvent(Event
, SynchronizationEvent
, FALSE
);
217 if (InterlockedCompareExchangePointer((PVOID
*)&Resource
->ExclusiveWaiters
,
221 /* Someone already set it, free our event */
222 DPRINT1("WARNING: Handling race condition\n");
223 ExFreePoolWithTag(Event
, TAG_RESOURCE_EVENT
);
229 /* Wait a bit before trying again */
230 KeDelayExecutionThread(KernelMode
, FALSE
, &ExShortTime
);
233 /* Re-acquire the lock */
234 ExAcquireResourceLock(Resource
, LockHandle
);
238 * @name ExpAllocateSharedWaiterSemaphore
240 * The ExpAllocateSharedWaiterSemaphore routine creates the semaphore that
241 * will be used by shared waiters on the resource.
244 * Pointer to the resource.
247 * Pointer to in-stack queued spinlock.
251 * @remarks The pointer to the semaphore must be atomically set.
256 ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource
,
257 IN PKLOCK_QUEUE_HANDLE LockHandle
)
259 PKSEMAPHORE Semaphore
;
261 /* Release the lock */
262 ExReleaseResourceLock(Resource
, LockHandle
);
264 /* Loop as long as we keep running out of memory */
267 /* Allocate the semaphore */
268 Semaphore
= ExAllocatePoolWithTag(NonPagedPool
,
270 TAG_RESOURCE_SEMAPHORE
);
274 KeInitializeSemaphore(Semaphore
, 0, MAXLONG
);
277 if (InterlockedCompareExchangePointer((PVOID
*)&Resource
->SharedWaiters
,
281 /* Someone already set it, free our semaphore */
282 DPRINT1("WARNING: Handling race condition\n");
283 ExFreePoolWithTag(Semaphore
, TAG_RESOURCE_SEMAPHORE
);
289 /* Wait a bit before trying again */
290 KeDelayExecutionThread(KernelMode
, FALSE
, &ExShortTime
);
293 /* Re-acquire the lock */
294 ExAcquireResourceLock(Resource
, LockHandle
);
298 * @name ExpExpandResourceOwnerTable
300 * The ExpExpandResourceOwnerTable routine expands the owner table of the
301 * specified resource.
304 * Pointer to the resource.
307 * Pointer to in-stack queued spinlock.
316 ExpExpandResourceOwnerTable(IN PERESOURCE Resource
,
317 IN PKLOCK_QUEUE_HANDLE LockHandle
)
319 POWNER_ENTRY Owner
, Table
;
321 ULONG NewSize
, OldSize
;
323 /* Get the owner table */
324 Owner
= Resource
->OwnerTable
;
327 /* Start with the default size of 3 */
333 /* Add 4 more entries */
334 OldSize
= Owner
->TableSize
;
335 NewSize
= OldSize
+ 4;
338 /* Release the lock */
339 ExReleaseResourceLock(Resource
, LockHandle
);
341 /* Allocate memory for the table */
342 Table
= ExAllocatePoolWithTag(NonPagedPool
,
343 NewSize
* sizeof(OWNER_ENTRY
),
347 RtlZeroMemory(Table
+ OldSize
,
348 (NewSize
- OldSize
) * sizeof(OWNER_ENTRY
));
350 /* Lock the resource */
351 ExAcquireResourceLock(Resource
, LockHandle
);
353 /* Make sure nothing has changed */
354 if ((Owner
!= Resource
->OwnerTable
) ||
355 ((Owner
) && (OldSize
!= Owner
->TableSize
)))
357 /* Resource changed while we weren't holding the lock; bail out */
358 ExReleaseResourceLock(Resource
, LockHandle
);
359 ExFreePoolWithTag(Table
, TAG_RESOURCE_TABLE
);
364 if (Owner
) RtlCopyMemory(Table
, Owner
, OldSize
* sizeof(OWNER_ENTRY
));
366 /* Acquire dispatcher lock to prevent thread boosting */
367 OldIrql
= KiAcquireDispatcherLock();
369 /* Set the new table data */
370 Table
->TableSize
= NewSize
;
371 Resource
->OwnerTable
= Table
;
373 /* Release dispatcher lock */
374 KiReleaseDispatcherLock(OldIrql
);
377 ExpVerifyResource(Resource
);
380 ExReleaseResourceLock(Resource
, LockHandle
);
382 /* Free the old table */
383 if (Owner
) ExFreePoolWithTag(Owner
, TAG_RESOURCE_TABLE
);
385 /* Set the resource index */
386 if (!OldSize
) OldSize
= 1;
389 /* Set the resource index */
390 KeGetCurrentThread()->ResourceIndex
= (UCHAR
)OldSize
;
392 /* Lock the resource again */
393 ExAcquireResourceLock(Resource
, LockHandle
);
397 * @name ExpFindFreeEntry
399 * The ExpFindFreeEntry routine locates an empty owner entry in the
400 * specified resource. If none was found, then the owner table is
404 * Pointer to the resource.
407 * Pointer to in-stack queued spinlock.
409 * @return Pointer to an empty OWNER_ENTRY structure.
416 ExpFindFreeEntry(IN PERESOURCE Resource
,
417 IN PKLOCK_QUEUE_HANDLE LockHandle
)
419 POWNER_ENTRY Owner
, Limit
;
422 ASSERT(LockHandle
!= 0);
423 ASSERT(Resource
->OwnerEntry
.OwnerThread
!= 0);
425 /* Get the current table pointer */
426 Owner
= Resource
->OwnerTable
;
429 /* Set the limit, move to the next owner and loop owner entries */
430 Limit
= &Owner
[Owner
->TableSize
];
432 while (Owner
->OwnerThread
)
434 /* Move to the next one */
437 /* Check if the entry is free */
438 if (Owner
== Limit
) goto Expand
;
441 /* Update the resource entry */
442 KeGetCurrentThread()->ResourceIndex
= (UCHAR
)(Owner
- Resource
->OwnerTable
);
447 /* No free entry, expand the table */
448 ExpExpandResourceOwnerTable(Resource
, LockHandle
);
452 /* Return the entry found */
457 * @name ExpFindEntryForThread
459 * The ExpFindEntryForThread routine locates the owner entry associated with
460 * the specified thread in the given resource. If none was found, then the
461 * owner table is expanded.
464 * Pointer to the resource.
467 * Pointer to the thread to find.
470 * Pointer to in-stack queued spinlock.
472 * @return Pointer to an empty OWNER_ENTRY structure.
479 ExpFindEntryForThread(IN PERESOURCE Resource
,
480 IN ERESOURCE_THREAD Thread
,
481 IN PKLOCK_QUEUE_HANDLE LockHandle
,
482 IN BOOLEAN FirstEntryInelligible
)
484 POWNER_ENTRY FreeEntry
, Owner
, Limit
;
486 /* Start by looking in the static array */
487 Owner
= &Resource
->OwnerEntry
;
488 if (Owner
->OwnerThread
== Thread
) return Owner
;
490 /* Check if this is a free entry */
491 if ((FirstEntryInelligible
) || (Owner
->OwnerThread
))
498 /* Use the first entry as our free entry */
502 /* Get the current table pointer */
503 Owner
= Resource
->OwnerTable
;
506 /* Set the limit, move to the next owner and loop owner entries */
507 Limit
= &Owner
[Owner
->TableSize
];
509 while (Owner
->OwnerThread
!= Thread
)
511 /* Check if we don't have a free entry */
514 /* Check if this entry is free */
515 if (!Owner
->OwnerThread
)
517 /* Save it as our free entry */
522 /* Move to the next one */
525 /* Check if the entry is free */
526 if (Owner
== Limit
) goto Expand
;
529 /* Update the resource entry */
530 KeGetCurrentThread()->ResourceIndex
= (UCHAR
)(Owner
- Resource
->OwnerTable
);
536 /* Check if it's OK to do an expansion */
537 if (!LockHandle
) return NULL
;
539 /* If we found a free entry by now, return it */
542 /* Set the resource index */
543 KeGetCurrentThread()->ResourceIndex
= (UCHAR
)(FreeEntry
- Resource
->OwnerTable
);
547 /* No free entry, expand the table */
548 ExpExpandResourceOwnerTable(Resource
, LockHandle
);
554 * @name ExpBoostOwnerThread
556 * The ExpBoostOwnerThread routine increases the priority of a waiting
557 * thread in an attempt to fight a possible deadlock.
560 * Pointer to the current thread.
563 * Pointer to thread that owns the resource.
572 ExpBoostOwnerThread(IN PKTHREAD Thread
,
573 IN PKTHREAD OwnerThread
)
575 /* Make sure the owner thread is a pointer, not an ID */
576 if (!((ULONG_PTR
)OwnerThread
& 0x3))
578 /* Check if we can actually boost it */
579 if ((OwnerThread
->Priority
< Thread
->Priority
) &&
580 (OwnerThread
->Priority
< 14))
582 /* Acquire the thread lock */
583 KiAcquireThreadLock(Thread
);
585 /* Set the new priority */
586 OwnerThread
->PriorityDecrement
+= 14 - OwnerThread
->Priority
;
589 OwnerThread
->Quantum
= OwnerThread
->QuantumReset
;
591 /* Update the kernel state */
592 KiSetPriorityThread(OwnerThread
, 14);
594 /* Release the thread lock */
595 KiReleaseThreadLock(Thread
);
601 * @name ExpWaitForResource
603 * The ExpWaitForResource routine performs a wait on the specified resource.
606 * Pointer to the resource to wait on.
609 * Pointer to object (exclusive event or shared semaphore) to wait on.
618 ExpWaitForResource(IN PERESOURCE Resource
,
626 LARGE_INTEGER Timeout
;
627 PKTHREAD Thread
, OwnerThread
;
629 KLOCK_QUEUE_HANDLE LockHandle
;
632 /* Increase contention count and use a 5 second timeout */
633 Resource
->ContentionCount
++;
634 Timeout
.QuadPart
= 500 * -10000;
637 /* Wait for ownership */
638 Status
= KeWaitForSingleObject(Object
,
643 if (Status
!= STATUS_TIMEOUT
) break;
645 /* Increase wait count */
647 Timeout
= ExpTimeout
;
649 /* Check if we've exceeded the limit */
650 if (WaitCount
> ExpResourceTimeoutCount
)
652 /* Reset wait count */
655 /* Lock the resource */
656 ExAcquireResourceLock(Resource
, &LockHandle
);
658 /* Dump debug information */
659 DPRINT1("Resource @ %p\n", Resource
);
660 DPRINT1(" ActiveEntries = %04lx Flags = %s%s%s\n",
661 Resource
->ActiveEntries
,
662 IsOwnedExclusive(Resource
) ? "IsOwnedExclusive " : "",
663 IsSharedWaiting(Resource
) ? "SharedWaiter " : "",
664 IsExclusiveWaiting(Resource
) ? "ExclusiveWaiter " : "");
665 DPRINT1(" NumberOfExclusiveWaiters = %04lx\n",
666 Resource
->NumberOfExclusiveWaiters
);
667 DPRINT1(" Thread = %08lx, Count = %02x\n",
668 Resource
->OwnerEntry
.OwnerThread
,
669 Resource
->OwnerEntry
.OwnerCount
);
671 /* Dump out the table too */
672 Owner
= Resource
->OwnerTable
;
675 /* Loop every entry */
676 Size
= Owner
->TableSize
;
677 for (i
= 1; i
< Size
; i
++)
681 DPRINT1(" Thread = %08lx, Count = %02x\n",
689 DPRINT1("EX - Rewaiting\n");
690 ExReleaseResourceLock(Resource
, &LockHandle
);
694 /* Check if we can boost */
695 if (IsBoostAllowed(Resource
))
697 /* Get the current kernel thread and lock the dispatcher */
698 Thread
= KeGetCurrentThread();
699 Thread
->WaitIrql
= KiAcquireDispatcherLock();
700 Thread
->WaitNext
= TRUE
;
702 /* Get the owner thread and boost it */
703 OwnerThread
= (PKTHREAD
)Resource
->OwnerEntry
.OwnerThread
;
704 if (OwnerThread
) ExpBoostOwnerThread(Thread
, OwnerThread
);
706 /* If it's a shared resource */
707 if (!IsOwnedExclusive(Resource
))
710 Owner
= Resource
->OwnerTable
;
713 /* Loop every entry */
714 Size
= Owner
->TableSize
;
715 for (i
= 1; i
< Size
; i
++)
717 /* Move to next entry */
721 OwnerThread
= (PKTHREAD
)Owner
->OwnerThread
;
724 if (OwnerThread
) ExpBoostOwnerThread(Thread
, OwnerThread
);
732 /* FUNCTIONS *****************************************************************/
735 * @name ExAcquireResourceExclusiveLite
738 * The ExAcquireResourceExclusiveLite routine acquires the given resource
739 * for exclusive access by the calling thread.
742 * Pointer to the resource to acquire.
745 * Specifies the routine's behavior whenever the resource cannot be
746 * acquired immediately.
748 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
749 * and exclusive access cannot be granted immediately.
751 * @remarks The caller can release the resource by calling either
752 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
754 * Normal kernel APC delivery must be disabled before calling this
755 * routine. Disable normal kernel APC delivery by calling
756 * KeEnterCriticalRegion. Delivery must remain disabled until the
757 * resource is released, at which point it can be reenabled by calling
758 * KeLeaveCriticalRegion.
760 * For better performance, call ExTryToAcquireResourceExclusiveLite,
761 * rather than calling ExAcquireResourceExclusiveLite with Wait set
764 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
770 ExAcquireResourceExclusiveLite(IN PERESOURCE Resource
,
773 KLOCK_QUEUE_HANDLE LockHandle
;
774 ERESOURCE_THREAD Thread
;
778 ASSERT((Resource
->Flag
& ResourceNeverExclusive
) == 0);
781 Thread
= ExGetCurrentResourceThread();
783 /* Sanity check and validation */
784 ASSERT(KeIsExecutingDpc() == FALSE
);
785 ExpVerifyResource(Resource
);
787 /* Acquire the lock */
788 ExAcquireResourceLock(Resource
, &LockHandle
);
789 ExpCheckForApcsDisabled(LockHandle
.OldIrql
, Resource
, (PKTHREAD
)Thread
);
791 /* Check if there is a shared owner or exclusive owner */
793 if (Resource
->ActiveEntries
)
795 /* Check if it's exclusively owned, and we own it */
796 if ((IsOwnedExclusive(Resource
)) &&
797 (Resource
->OwnerEntry
.OwnerThread
== Thread
))
799 /* Increase the owning count */
800 Resource
->OwnerEntry
.OwnerCount
++;
806 * If the caller doesn't want us to wait, we can't acquire the
807 * resource because someone else then us owns it. If we can wait,
816 /* Check if it has exclusive waiters */
817 if (!Resource
->ExclusiveWaiters
)
819 /* It doesn't, allocate the event and try acquiring again */
820 ExpAllocateExclusiveWaiterEvent(Resource
, &LockHandle
);
824 /* Has exclusive waiters, wait on it */
825 Resource
->NumberOfExclusiveWaiters
++;
826 ExReleaseResourceLock(Resource
, &LockHandle
);
827 ExpWaitForResource(Resource
, Resource
->ExclusiveWaiters
);
829 /* Set owner and return success */
830 Resource
->OwnerEntry
.OwnerThread
= ExGetCurrentResourceThread();
837 /* Nobody owns it, so let's! */
838 ASSERT(Resource
->ActiveEntries
== 0);
839 ASSERT(Resource
->ActiveCount
== 0);
840 Resource
->Flag
|= ResourceOwnedExclusive
;
841 Resource
->ActiveEntries
= 1;
842 Resource
->ActiveCount
= 1;
843 Resource
->OwnerEntry
.OwnerThread
= Thread
;
844 Resource
->OwnerEntry
.OwnerCount
= 1;
848 /* Release the lock and return */
849 ExReleaseResourceLock(Resource
, &LockHandle
);
854 * @name ExAcquireResourceSharedLite
857 * The ExAcquireResourceSharedLite routine acquires the given resource
858 * for shared access by the calling thread.
861 * Pointer to the resource to acquire.
864 * Specifies the routine's behavior whenever the resource cannot be
865 * acquired immediately.
867 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
868 * and exclusive access cannot be granted immediately.
870 * @remarks The caller can release the resource by calling either
871 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
873 * Normal kernel APC delivery must be disabled before calling this
874 * routine. Disable normal kernel APC delivery by calling
875 * KeEnterCriticalRegion. Delivery must remain disabled until the
876 * resource is released, at which point it can be reenabled by calling
877 * KeLeaveCriticalRegion.
879 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
885 ExAcquireResourceSharedLite(IN PERESOURCE Resource
,
888 KLOCK_QUEUE_HANDLE LockHandle
;
889 ERESOURCE_THREAD Thread
;
890 POWNER_ENTRY Owner
= NULL
;
891 BOOLEAN FirstEntryBusy
;
894 Thread
= ExGetCurrentResourceThread();
896 /* Sanity check and validation */
897 ASSERT(KeIsExecutingDpc() == FALSE
);
898 ExpVerifyResource(Resource
);
900 /* Acquire the lock */
901 ExAcquireResourceLock(Resource
, &LockHandle
);
902 ExpCheckForApcsDisabled(LockHandle
.OldIrql
, Resource
, (PKTHREAD
)Thread
);
904 /* Check how many active entries we've got */
905 while (Resource
->ActiveEntries
!= 0)
907 /* Check if it's exclusively owned */
908 if (IsOwnedExclusive(Resource
))
910 /* Check if we own it */
911 if (Resource
->OwnerEntry
.OwnerThread
== Thread
)
913 /* Increase the owning count */
914 Resource
->OwnerEntry
.OwnerCount
++;
916 /* Release the lock and return */
917 ExReleaseResourceLock(Resource
, &LockHandle
);
921 /* Find a free entry */
922 Owner
= ExpFindFreeEntry(Resource
, &LockHandle
);
923 if (!Owner
) continue;
927 /* Resource is shared, find who owns it */
928 FirstEntryBusy
= IsExclusiveWaiting(Resource
);
929 Owner
= ExpFindEntryForThread(Resource
,
933 if (!Owner
) continue;
936 if (Owner
->OwnerThread
== Thread
)
938 /* Increase acquire count and return */
940 ASSERT(Owner
->OwnerCount
!= 0);
942 /* Release the lock and return */
943 ExReleaseResourceLock(Resource
, &LockHandle
);
947 /* Try to find if there are exclusive waiters */
950 /* There are none, so acquire it */
951 Owner
->OwnerThread
= Thread
;
952 Owner
->OwnerCount
= 1;
954 /* Check how many active entries we had */
955 if (Resource
->ActiveEntries
== 0)
957 /* Set initial counts */
958 ASSERT(Resource
->ActiveCount
== 0);
959 Resource
->ActiveEntries
= 1;
960 Resource
->ActiveCount
= 1;
964 /* Increase active entries */
965 ASSERT(Resource
->ActiveCount
== 1);
966 Resource
->ActiveEntries
++;
969 /* Release the lock and return */
970 ExReleaseResourceLock(Resource
, &LockHandle
);
975 /* If we got here, then we need to wait. Are we allowed? */
978 /* Release the lock and return */
979 ExReleaseResourceLock(Resource
, &LockHandle
);
983 /* Check if we have a shared waiters semaphore */
984 if (!Resource
->SharedWaiters
)
986 /* Allocate it and try another acquire */
987 ExpAllocateSharedWaiterSemaphore(Resource
, &LockHandle
);
991 /* We have shared waiters, wait for it */
996 /* Did we get here because we don't have active entries? */
997 if (Resource
->ActiveEntries
== 0)
1000 ASSERT(Resource
->ActiveEntries
== 0);
1001 ASSERT(Resource
->ActiveCount
== 0);
1002 Resource
->ActiveEntries
= 1;
1003 Resource
->ActiveCount
= 1;
1004 Resource
->OwnerEntry
.OwnerThread
= Thread
;
1005 Resource
->OwnerEntry
.OwnerCount
= 1;
1007 /* Release the lock and return */
1008 ExReleaseResourceLock(Resource
, &LockHandle
);
1012 /* Now wait for the resource */
1013 Owner
->OwnerThread
= Thread
;
1014 Owner
->OwnerCount
= 1;
1015 Resource
->NumberOfSharedWaiters
++;
1017 /* Release the lock and return */
1018 ExReleaseResourceLock(Resource
, &LockHandle
);
1019 ExpWaitForResource(Resource
, Resource
->SharedWaiters
);
1024 * @name ExAcquireSharedStarveExclusive
1027 * The ExAcquireSharedStarveExclusive routine acquires the given resource
1028 * shared access without waiting for any pending attempts to acquire
1029 * exclusive access to the same resource.
1032 * Pointer to the resource to acquire.
1035 * Specifies the routine's behavior whenever the resource cannot be
1036 * acquired immediately.
1038 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
1039 * and exclusive access cannot be granted immediately.
1041 * @remarks The caller can release the resource by calling either
1042 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
1044 * Normal kernel APC delivery must be disabled before calling this
1045 * routine. Disable normal kernel APC delivery by calling
1046 * KeEnterCriticalRegion. Delivery must remain disabled until the
1047 * resource is released, at which point it can be reenabled by calling
1048 * KeLeaveCriticalRegion.
1050 * Callers of ExAcquireSharedStarveExclusive usually need quick access
1051 * to a shared resource in order to save an exclusive accessor from
1052 * doing redundant work. For example, a file system might call this
1053 * routine to modify a cached resource, such as a BCB pinned in the
1054 * cache, before the Cache Manager can acquire exclusive access to the
1055 * resource and write the cache out to disk.
1057 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
1063 ExAcquireSharedStarveExclusive(IN PERESOURCE Resource
,
1066 KLOCK_QUEUE_HANDLE LockHandle
;
1067 ERESOURCE_THREAD Thread
;
1070 /* Get the thread */
1071 Thread
= ExGetCurrentResourceThread();
1073 /* Sanity check and validation */
1074 ASSERT(KeIsExecutingDpc() == FALSE
);
1075 ExpVerifyResource(Resource
);
1077 /* Acquire the lock */
1078 ExAcquireResourceLock(Resource
, &LockHandle
);
1080 /* See if anyone owns it */
1082 if (Resource
->ActiveEntries
== 0)
1084 /* Nobody owns it, so let's take control */
1085 ASSERT(Resource
->ActiveEntries
== 0);
1086 ASSERT(Resource
->ActiveCount
== 0);
1087 Resource
->ActiveCount
= 1;
1088 Resource
->ActiveEntries
= 1;
1089 Resource
->OwnerEntry
.OwnerThread
= Thread
;
1090 Resource
->OwnerEntry
.OwnerCount
= 1;
1092 /* Release the lock and return */
1093 ExReleaseResourceLock(Resource
, &LockHandle
);
1097 /* Check if it's exclusively owned */
1098 if (IsOwnedExclusive(Resource
))
1100 /* Check if we own it */
1101 if (Resource
->OwnerEntry
.OwnerThread
== Thread
)
1103 /* Increase the owning count */
1104 Resource
->OwnerEntry
.OwnerCount
++;
1106 /* Release the lock and return */
1107 ExReleaseResourceLock(Resource
, &LockHandle
);
1111 /* Find a free entry */
1112 Owner
= ExpFindFreeEntry(Resource
, &LockHandle
);
1113 if (!Owner
) goto TryAcquire
;
1117 /* Resource is shared, find who owns it */
1118 Owner
= ExpFindEntryForThread(Resource
, Thread
, &LockHandle
, FALSE
);
1119 if (!Owner
) goto TryAcquire
;
1122 if (Owner
->OwnerThread
== Thread
)
1124 /* Increase acquire count and return */
1125 Owner
->OwnerCount
++;
1126 ASSERT(Owner
->OwnerCount
!= 0);
1128 /* Release the lock and return */
1129 ExReleaseResourceLock(Resource
, &LockHandle
);
1134 Owner
->OwnerThread
= Thread
;
1135 Owner
->OwnerCount
= 1;
1137 /* Check how many active entries we had */
1138 if (Resource
->ActiveEntries
== 0)
1140 /* Set initial counts */
1141 ASSERT(Resource
->ActiveCount
== 0);
1142 Resource
->ActiveEntries
= 1;
1143 Resource
->ActiveCount
= 1;
1147 /* Increase active entries */
1148 ASSERT(Resource
->ActiveCount
== 1);
1149 Resource
->ActiveEntries
++;
1152 /* Release the lock and return */
1153 ExReleaseResourceLock(Resource
, &LockHandle
);
1157 /* If we got here, then we need to wait. Are we allowed? */
1160 /* Release the lock and return */
1161 ExReleaseResourceLock(Resource
, &LockHandle
);
1165 /* Check if we have a shared waiters semaphore */
1166 if (!Resource
->SharedWaiters
)
1168 /* Allocate it and try another acquire */
1169 ExpAllocateSharedWaiterSemaphore(Resource
, &LockHandle
);
1173 /* Now wait for the resource */
1174 Owner
->OwnerThread
= Thread
;
1175 Owner
->OwnerCount
= 1;
1176 Resource
->NumberOfSharedWaiters
++;
1178 /* Release the lock and return */
1179 ExReleaseResourceLock(Resource
, &LockHandle
);
1180 ExpWaitForResource(Resource
, Resource
->SharedWaiters
);
1185 * @name ExAcquireSharedWaitForExclusive
1188 * The ExAcquireSharedWaitForExclusive routine acquires the given resource
1189 * for shared access if shared access can be granted and there are no
1190 * exclusive waiters.
1193 * Pointer to the resource to acquire.
1196 * Specifies the routine's behavior whenever the resource cannot be
1197 * acquired immediately.
1199 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
1200 * and exclusive access cannot be granted immediately.
1202 * @remarks The caller can release the resource by calling either
1203 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
1205 * Normal kernel APC delivery must be disabled before calling this
1206 * routine. Disable normal kernel APC delivery by calling
1207 * KeEnterCriticalRegion. Delivery must remain disabled until the
1208 * resource is released, at which point it can be reenabled by calling
1209 * KeLeaveCriticalRegion.
1211 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
1217 ExAcquireSharedWaitForExclusive(IN PERESOURCE Resource
,
1220 KLOCK_QUEUE_HANDLE LockHandle
;
1221 ERESOURCE_THREAD Thread
;
1224 /* Get the thread */
1225 Thread
= ExGetCurrentResourceThread();
1227 /* Sanity check and validation */
1228 ASSERT(KeIsExecutingDpc() == FALSE
);
1229 ExpVerifyResource(Resource
);
1231 /* Acquire the lock */
1232 ExAcquireResourceLock(Resource
, &LockHandle
);
1234 /* See if nobody owns us */
1236 if (!Resource
->ActiveEntries
)
1238 /* Nobody owns it, so let's take control */
1239 ASSERT(Resource
->ActiveEntries
== 0);
1240 ASSERT(Resource
->ActiveCount
== 0);
1241 Resource
->ActiveCount
= 1;
1242 Resource
->ActiveEntries
= 1;
1243 Resource
->OwnerEntry
.OwnerThread
= Thread
;
1244 Resource
->OwnerEntry
.OwnerCount
= 1;
1246 /* Release the lock and return */
1247 ExReleaseResourceLock(Resource
, &LockHandle
);
1251 /* Check if it's exclusively owned */
1252 if (IsOwnedExclusive(Resource
))
1254 /* Check if we own it */
1255 if (Resource
->OwnerEntry
.OwnerThread
== Thread
)
1257 /* Increase the owning count */
1258 Resource
->OwnerEntry
.OwnerCount
++;
1260 /* Release the lock and return */
1261 ExReleaseResourceLock(Resource
, &LockHandle
);
1265 /* Find a free entry */
1266 Owner
= ExpFindFreeEntry(Resource
, &LockHandle
);
1267 if (!Owner
) goto TryAcquire
;
1271 /* Try to find if there are exclusive waiters */
1272 if (IsExclusiveWaiting(Resource
))
1274 /* We have to wait for the exclusive waiter to be done */
1277 /* So bail out if we're not allowed */
1278 ExReleaseResourceLock(Resource
, &LockHandle
);
1282 /* Check if we have a shared waiters semaphore */
1283 if (!Resource
->SharedWaiters
)
1285 /* Allocate one and try again */
1286 ExpAllocateSharedWaiterSemaphore(Resource
, &LockHandle
);
1290 /* Now wait for the resource */
1291 Resource
->NumberOfSharedWaiters
++;
1292 ExReleaseResourceLock(Resource
, &LockHandle
);
1293 ExpWaitForResource(Resource
, Resource
->SharedWaiters
);
1295 /* Get the lock back */
1296 ExAcquireResourceLock(Resource
, &LockHandle
);
1298 /* Find who owns it now */
1299 while (!(Owner
= ExpFindEntryForThread(Resource
, Thread
, &LockHandle
, TRUE
)));
1302 ASSERT(IsOwnedExclusive(Resource
) == FALSE
);
1303 ASSERT(Resource
->ActiveEntries
> 0);
1304 ASSERT(Owner
->OwnerThread
!= Thread
);
1307 Owner
->OwnerThread
= Thread
;
1308 Owner
->OwnerCount
= 1;
1310 /* Release the lock and return */
1311 ExReleaseResourceLock(Resource
, &LockHandle
);
1316 /* Resource is shared, find who owns it */
1317 Owner
= ExpFindEntryForThread(Resource
, Thread
, &LockHandle
, FALSE
);
1318 if (!Owner
) goto TryAcquire
;
1321 if (Owner
->OwnerThread
== Thread
)
1323 /* Increase acquire count and return */
1324 Owner
->OwnerCount
++;
1325 ASSERT(Owner
->OwnerCount
!= 0);
1327 /* Release the lock and return */
1328 ExReleaseResourceLock(Resource
, &LockHandle
);
1332 /* No exclusive waiters, so acquire it */
1333 Owner
->OwnerThread
= Thread
;
1334 Owner
->OwnerCount
= 1;
1336 /* Check how many active entries we had */
1337 if (Resource
->ActiveEntries
== 0)
1339 /* Set initial counts */
1340 ASSERT(Resource
->ActiveCount
== 0);
1341 Resource
->ActiveEntries
= 1;
1342 Resource
->ActiveCount
= 1;
1346 /* Increase active entries */
1347 ASSERT(Resource
->ActiveCount
== 1);
1348 Resource
->ActiveEntries
++;
1351 /* Release the lock and return */
1352 ExReleaseResourceLock(Resource
, &LockHandle
);
1357 /* We have to wait for the exclusive waiter to be done */
1360 /* So bail out if we're not allowed */
1361 ExReleaseResourceLock(Resource
, &LockHandle
);
1365 /* Check if we have a shared waiters semaphore */
1366 if (!Resource
->SharedWaiters
)
1368 /* Allocate one and try again */
1369 ExpAllocateSharedWaiterSemaphore(Resource
,&LockHandle
);
1374 Owner
->OwnerThread
= Thread
;
1375 Owner
->OwnerCount
= 1;
1376 Resource
->NumberOfSharedWaiters
++;
1378 /* Release the lock and return */
1379 ExReleaseResourceLock(Resource
, &LockHandle
);
1380 ExpWaitForResource(Resource
, Resource
->SharedWaiters
);
1385 * @name ExConvertExclusiveToSharedLite
1388 * The ExConvertExclusiveToSharedLite routine converts an exclusively
1389 * acquired resource into a resource that can be acquired shared.
1392 * Pointer to the resource to convert.
1396 * @remarks Callers of ExConvertExclusiveToSharedLite must be running at IRQL <
1402 ExConvertExclusiveToSharedLite(IN PERESOURCE Resource
)
1405 KLOCK_QUEUE_HANDLE LockHandle
;
1408 ASSERT(KeIsExecutingDpc() == FALSE
);
1409 ExpVerifyResource(Resource
);
1410 ASSERT(IsOwnedExclusive(Resource
));
1411 ASSERT(Resource
->OwnerEntry
.OwnerThread
== (ERESOURCE_THREAD
)PsGetCurrentThread());
1413 /* Lock the resource */
1414 ExAcquireResourceLock(Resource
, &LockHandle
);
1416 /* Erase the exclusive flag */
1417 Resource
->Flag
&= ~ResourceOwnedExclusive
;
1419 /* Check if we have shared waiters */
1420 if (IsSharedWaiting(Resource
))
1422 /* Make the waiters active owners */
1423 OldWaiters
= Resource
->NumberOfSharedWaiters
;
1424 Resource
->ActiveEntries
+= OldWaiters
;
1425 Resource
->NumberOfSharedWaiters
= 0;
1427 /* Release lock and wake the waiters */
1428 ExReleaseResourceLock(Resource
, &LockHandle
);
1429 KeReleaseSemaphore(Resource
->SharedWaiters
, 0, OldWaiters
, FALSE
);
1434 ExReleaseResourceLock(Resource
, &LockHandle
);
1439 * @name ExDeleteResourceLite
1442 * The ExConvertExclusiveToSharedLite routine deletes a given resource
1443 * from the system\92s resource list.
1446 * Pointer to the resource to delete.
1448 * @return STATUS_SUCCESS if the resource was deleted.
1450 * @remarks Callers of ExDeleteResourceLite must be running at IRQL <
1456 ExDeleteResourceLite(IN PERESOURCE Resource
)
1458 KLOCK_QUEUE_HANDLE LockHandle
;
1461 ASSERT(IsSharedWaiting(Resource
) == FALSE
);
1462 ASSERT(IsExclusiveWaiting(Resource
) == FALSE
);
1463 ASSERT(KeIsExecutingDpc() == FALSE
);
1464 ExpVerifyResource(Resource
);
1466 /* Lock the resource */
1467 KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock
, &LockHandle
);
1469 /* Remove the resource */
1470 RemoveEntryList(&Resource
->SystemResourcesList
);
1472 /* Release the lock */
1473 KeReleaseInStackQueuedSpinLock(&LockHandle
);
1475 /* Free every structure */
1476 if (Resource
->OwnerTable
) ExFreePoolWithTag(Resource
->OwnerTable
, TAG_RESOURCE_TABLE
);
1477 if (Resource
->SharedWaiters
) ExFreePoolWithTag(Resource
->SharedWaiters
, TAG_RESOURCE_SEMAPHORE
);
1478 if (Resource
->ExclusiveWaiters
) ExFreePoolWithTag(Resource
->ExclusiveWaiters
, TAG_RESOURCE_EVENT
);
1480 /* Return success */
1481 return STATUS_SUCCESS
;
1485 * @name ExDisableResourceBoostLite
1488 * The ExDisableResourceBoostLite routine disables thread boosting for
1489 * the given resource.
1492 * Pointer to the resource whose thread boosting will be disabled.
1501 ExDisableResourceBoostLite(IN PERESOURCE Resource
)
1503 KLOCK_QUEUE_HANDLE LockHandle
;
1506 ExpVerifyResource(Resource
);
1508 /* Lock the resource */
1509 ExAcquireResourceLock(Resource
, &LockHandle
);
1511 /* Remove the flag */
1512 Resource
->Flag
|= ResourceHasDisabledPriorityBoost
;
1514 /* Release the lock */
1515 ExReleaseResourceLock(Resource
, &LockHandle
);
1519 * @name ExGetExclusiveWaiterCount
1522 * The ExGetExclusiveWaiterCount routine returns the number of exclusive
1523 * waiters for the given resource.
1526 * Pointer to the resource to check.
1528 * @return The number of exclusive waiters.
1535 ExGetExclusiveWaiterCount(IN PERESOURCE Resource
)
1537 /* Return the count */
1538 return Resource
->NumberOfExclusiveWaiters
;
1542 * @name ExGetSharedWaiterCount
1545 * The ExGetSharedWaiterCount routine returns the number of shared
1546 * waiters for the given resource.
1549 * Pointer to the resource to check.
1551 * @return The number of shared waiters.
1558 ExGetSharedWaiterCount(IN PERESOURCE Resource
)
1560 /* Return the count */
1561 return Resource
->NumberOfSharedWaiters
;
1565 * @name ExInitializeResourceLite
1568 * The ExInitializeResourceLite routine initializes a resource variable.
1571 * Pointer to the resource to check.
1573 * @return STATUS_SUCCESS.
1575 * @remarks The storage for ERESOURCE must not be allocated from paged pool.
1577 * The storage must be 8-byte aligned.
1582 ExInitializeResourceLite(IN PERESOURCE Resource
)
1584 KLOCK_QUEUE_HANDLE LockHandle
;
1586 /* Clear the structure */
1587 RtlZeroMemory(Resource
, sizeof(ERESOURCE
));
1589 /* Initialize the lock */
1590 KeInitializeSpinLock(&Resource
->SpinLock
);
1592 /* Add it into the system list */
1593 KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock
, &LockHandle
);
1594 InsertTailList(&ExpSystemResourcesList
, &Resource
->SystemResourcesList
);
1595 KeReleaseInStackQueuedSpinLock(&LockHandle
);
1597 /* Return success */
1598 return STATUS_SUCCESS
;
1602 * @name ExIsResourceAcquiredExclusiveLite
1605 * The ExIsResourceAcquiredExclusiveLite routine returns whether the
1606 * current thread has exclusive access to a given resource.
1609 * Pointer to the resource to check.
1611 * @return TRUE if the caller already has exclusive access to the given resource.
1613 * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
1614 * IRQL <= DISPATCH_LEVEL.
1619 ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource
)
1621 BOOLEAN IsAcquired
= FALSE
;
1624 ExpVerifyResource(Resource
);
1626 /* Check if it's exclusively acquired */
1627 if ((IsOwnedExclusive(Resource
)) &&
1628 (Resource
->OwnerEntry
.OwnerThread
== ExGetCurrentResourceThread()))
1630 /* It is acquired */
1634 /* Return if it's acquired */
1639 * @name ExIsResourceAcquiredSharedLite
1642 * The ExIsResourceAcquiredSharedLite routine returns whether the
1643 * current thread has has access (either shared or exclusive) to a
1647 * Pointer to the resource to check.
1649 * @return Number of times the caller has acquired the given resource for
1650 * shared or exclusive access.
1652 * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
1653 * IRQL <= DISPATCH_LEVEL.
1658 ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource
)
1660 ERESOURCE_THREAD Thread
;
1663 KLOCK_QUEUE_HANDLE LockHandle
;
1667 ExpVerifyResource(Resource
);
1669 /* Check if nobody owns us */
1670 if (!Resource
->ActiveEntries
) return 0;
1672 /* Get the thread */
1673 Thread
= ExGetCurrentResourceThread();
1675 /* Check if we are in the thread list */
1676 if (Resource
->OwnerEntry
.OwnerThread
== Thread
)
1678 /* Found it, return count */
1679 Count
= Resource
->OwnerEntry
.OwnerCount
;
1683 /* We can't own an exclusive resource at this point */
1684 if (IsOwnedExclusive(Resource
)) return 0;
1686 /* Lock the resource */
1687 ExAcquireResourceLock(Resource
, &LockHandle
);
1689 /* Not in the list, do a full table look up */
1690 Owner
= Resource
->OwnerTable
;
1693 /* Get the resource index */
1694 i
= ((PKTHREAD
)Thread
)->ResourceIndex
;
1695 Size
= Owner
->TableSize
;
1697 /* Check if the index is valid and check if we don't match */
1698 if ((i
>= Size
) || (Owner
[i
].OwnerThread
!= Thread
))
1700 /* Sh*t! We need to do a full search */
1701 for (i
= 1; i
< Size
; i
++)
1703 /* Move to next owner */
1706 /* Try to find a match */
1707 if (Owner
->OwnerThread
== Thread
)
1710 Count
= Owner
->OwnerCount
;
1717 /* We found the match directlry */
1718 Count
= Owner
[i
].OwnerCount
;
1722 /* Release the lock */
1723 ExReleaseResourceLock(Resource
, &LockHandle
);
1731 * @name ExReinitializeResourceLite
1734 * The ExReinitializeResourceLite routine routine reinitializes
1735 * an existing resource variable.
1738 * Pointer to the resource to be reinitialized.
1740 * @return STATUS_SUCCESS.
1742 * @remarks With a single call to ExReinitializeResource, a driver writer can
1743 * replace three calls: one to ExDeleteResourceLite, another to
1744 * ExAllocatePool, and a third to ExInitializeResourceLite. As
1745 * contention for a resource variable increases, memory is dynamically
1746 * allocated and attached to the resource in order to track this
1747 * contention. As an optimization, ExReinitializeResourceLite retains
1748 * and zeroes this previously allocated memory.
1750 * Callers of ExReinitializeResourceLite must be running at
1751 * IRQL <= DISPATCH_LEVEL.
1756 ExReinitializeResourceLite(IN PERESOURCE Resource
)
1759 PKSEMAPHORE Semaphore
;
1763 /* Get the owner table */
1764 Owner
= Resource
->OwnerTable
;
1767 /* Get the size and loop it */
1768 Size
= Owner
->TableSize
;
1769 for (i
= 0; i
< Size
; i
++)
1771 /* Zero the table */
1772 Owner
[i
].OwnerThread
= 0;
1773 Owner
[i
].OwnerCount
= 0;
1777 /* Zero the flags and count */
1779 Resource
->ActiveCount
= 0;
1780 Resource
->ActiveEntries
= 0;
1782 /* Reset the semaphore */
1783 Semaphore
= Resource
->SharedWaiters
;
1784 if (Semaphore
) KeInitializeSemaphore(Semaphore
, 0, MAXLONG
);
1786 /* Reset the event */
1787 Event
= Resource
->ExclusiveWaiters
;
1788 if (Event
) KeInitializeEvent(Event
, SynchronizationEvent
, FALSE
);
1790 /* Clear the resource data */
1791 Resource
->OwnerEntry
.OwnerThread
= 0;
1792 Resource
->OwnerEntry
.OwnerCount
= 0;
1793 Resource
->ContentionCount
= 0;
1794 Resource
->NumberOfSharedWaiters
= 0;
1795 Resource
->NumberOfExclusiveWaiters
= 0;
1796 return STATUS_SUCCESS
;
1800 * @name ExReleaseResourceLite
1803 * The ExReleaseResourceLite routine routine releases
1804 * a specified executive resource owned by the current thread.
1807 * Pointer to the resource to be released.
1811 * @remarks Callers of ExReleaseResourceLite must be running at
1812 * IRQL <= DISPATCH_LEVEL.
1817 ExReleaseResourceLite(IN PERESOURCE Resource
)
1819 /* Just call the For-Thread function */
1820 ExReleaseResourceForThreadLite(Resource
, (ERESOURCE_THREAD
)PsGetCurrentThread());
1824 * @name ExReleaseResourceForThreadLite
1827 * The ExReleaseResourceForThreadLite routine routine releases
1828 * the input resource of the indicated thread.
1831 * Pointer to the resource to be released.
1834 * Identifies the thread that originally acquired the resource.
1838 * @remarks Callers of ExReleaseResourceForThreadLite must be running at
1839 * IRQL <= DISPATCH_LEVEL.
1844 ExReleaseResourceForThreadLite(IN PERESOURCE Resource
,
1845 IN ERESOURCE_THREAD Thread
)
1849 KLOCK_QUEUE_HANDLE LockHandle
;
1850 POWNER_ENTRY Owner
, Limit
;
1851 ASSERT(Thread
!= 0);
1853 /* Get the thread and lock the resource */
1854 ExAcquireResourceLock(Resource
, &LockHandle
);
1857 ExpVerifyResource(Resource
);
1858 ExpCheckForApcsDisabled(LockHandle
.OldIrql
, Resource
, (PKTHREAD
)Thread
);
1860 /* Check if it's exclusively owned */
1861 if (IsOwnedExclusive(Resource
))
1863 /* Decrement owner count and check if we're done */
1864 ASSERT(Resource
->OwnerEntry
.OwnerThread
== Thread
);
1865 if (--Resource
->OwnerEntry
.OwnerCount
)
1867 /* Done, release lock! */
1868 ExReleaseResourceLock(Resource
, &LockHandle
);
1872 /* Clear the owner */
1873 Resource
->OwnerEntry
.OwnerThread
= 0;
1875 /* Decrement the number of active entries */
1876 ASSERT(Resource
->ActiveEntries
== 1);
1877 Resource
->ActiveEntries
--;
1879 /* Check if there are shared waiters */
1880 if (IsSharedWaiting(Resource
))
1882 /* Remove the exclusive flag */
1883 Resource
->Flag
&= ~ResourceOwnedExclusive
;
1885 /* Give ownage to another thread */
1886 Count
= Resource
->NumberOfSharedWaiters
;
1887 Resource
->ActiveEntries
= Count
;
1888 Resource
->NumberOfSharedWaiters
= 0;
1890 /* Release lock and let someone else have it */
1891 ASSERT(Resource
->ActiveCount
== 1);
1892 ExReleaseResourceLock(Resource
, &LockHandle
);
1893 KeReleaseSemaphore(Resource
->SharedWaiters
, 0, Count
, FALSE
);
1896 else if (IsExclusiveWaiting(Resource
))
1898 /* Give exclusive access */
1899 Resource
->OwnerEntry
.OwnerThread
= 1;
1900 Resource
->OwnerEntry
.OwnerCount
= 1;
1901 Resource
->ActiveEntries
= 1;
1902 Resource
->NumberOfExclusiveWaiters
--;
1904 /* Release the lock and give it away */
1905 ASSERT(Resource
->ActiveCount
== 1);
1906 ExReleaseResourceLock(Resource
, &LockHandle
);
1907 KeSetEventBoostPriority(Resource
->ExclusiveWaiters
,
1908 (PKTHREAD
*)&Resource
->OwnerEntry
.OwnerThread
);
1912 /* Remove the exclusive flag */
1913 Resource
->Flag
&= ~ResourceOwnedExclusive
;
1914 Resource
->ActiveCount
= 0;
1918 /* Check if we are in the thread list */
1919 if (Resource
->OwnerEntry
.OwnerThread
== Thread
)
1921 /* Found it, get owner */
1922 Owner
= &Resource
->OwnerEntry
;
1926 /* Assume no valid index */
1929 /* If we got a valid pointer, try to get the resource index */
1930 if (!((ULONG
)Thread
& 3)) i
= ((PKTHREAD
)Thread
)->ResourceIndex
;
1932 /* Do a table lookup */
1933 Owner
= Resource
->OwnerTable
;
1934 ASSERT(Owner
!= NULL
);
1936 /* Check if we're out of the size and don't match */
1937 if ((i
>= Owner
->TableSize
) || (Owner
[i
].OwnerThread
!= Thread
))
1939 /* Get the last entry */
1940 Limit
= &Owner
[Owner
->TableSize
];
1943 /* Move to the next entry */
1946 /* Make sure we're not out of bounds */
1949 /* Bugcheck, nobody owns us */
1950 KeBugCheckEx(RESOURCE_NOT_OWNED
,
1951 (ULONG_PTR
)Resource
,
1953 (ULONG_PTR
)Resource
->OwnerTable
,
1957 /* Check for a match */
1958 if (Owner
->OwnerThread
== Thread
) break;
1963 /* Get the entry directly */
1969 ASSERT(Owner
->OwnerThread
== Thread
);
1970 ASSERT(Owner
->OwnerCount
> 0);
1972 /* Check if we are the last owner */
1973 if (--Owner
->OwnerCount
)
1975 /* There are other owners, release lock */
1976 ExReleaseResourceLock(Resource
, &LockHandle
);
1981 Owner
->OwnerThread
= 0;
1983 /* See if the resource isn't being owned anymore */
1984 ASSERT(Resource
->ActiveEntries
> 0);
1985 if (!(--Resource
->ActiveEntries
))
1987 /* Check if there's an exclusive waiter */
1988 if (IsExclusiveWaiting(Resource
))
1990 /* Give exclusive access */
1991 Resource
->Flag
|= ResourceOwnedExclusive
;
1992 Resource
->OwnerEntry
.OwnerThread
= 1;
1993 Resource
->OwnerEntry
.OwnerCount
= 1;
1994 Resource
->ActiveEntries
= 1;
1995 Resource
->NumberOfExclusiveWaiters
--;
1997 /* Release the lock and give it away */
1998 ASSERT(Resource
->ActiveCount
== 1);
1999 ExReleaseResourceLock(Resource
, &LockHandle
);
2000 KeSetEventBoostPriority(Resource
->ExclusiveWaiters
,
2001 (PKTHREAD
*)&Resource
->OwnerEntry
.OwnerThread
);
2005 /* Clear the active count */
2006 Resource
->ActiveCount
= 0;
2011 ExReleaseResourceLock(Resource
, &LockHandle
);
2015 * @name ExSetResourceOwnerPointer
2018 * The ExSetResourceOwnerPointer routine routine sets the owner thread
2019 * thread pointer for an executive resource.
2022 * Pointer to the resource whose owner to change.
2024 * @param OwnerPointer
2025 * Pointer to an owner thread pointer of type ERESOURCE_THREAD.
2029 * @remarks ExSetResourceOwnerPointer, used in conjunction with
2030 * ExReleaseResourceForThreadLite, provides a means for one thread
2031 * (acting as an resource manager thread) to acquire and release
2032 * resources for use by another thread (acting as a resource user
2035 * After calling ExSetResourceOwnerPointer for a specific resource,
2036 * the only other routine that can be called for that resource is
2037 * ExReleaseResourceForThreadLite.
2039 * Callers of ExSetResourceOwnerPointer must be running at
2040 * IRQL <= DISPATCH_LEVEL.
2045 ExSetResourceOwnerPointer(IN PERESOURCE Resource
,
2046 IN PVOID OwnerPointer
)
2048 ERESOURCE_THREAD Thread
;
2049 KLOCK_QUEUE_HANDLE LockHandle
;
2050 POWNER_ENTRY Owner
, ThisOwner
;
2053 ASSERT((OwnerPointer
!= 0) && (((ULONG_PTR
)OwnerPointer
& 3) == 3));
2055 /* Get the thread */
2056 Thread
= ExGetCurrentResourceThread();
2059 ExpVerifyResource(Resource
);
2061 /* Lock the resource */
2062 ExAcquireResourceLock(Resource
, &LockHandle
);
2064 /* Check if it's exclusive */
2065 if (IsOwnedExclusive(Resource
))
2067 /* If it's exclusive, set the first entry no matter what */
2068 ASSERT(Resource
->OwnerEntry
.OwnerThread
== Thread
);
2069 ASSERT(Resource
->OwnerEntry
.OwnerCount
> 0);
2070 Resource
->OwnerEntry
.OwnerThread
= (ULONG_PTR
)OwnerPointer
;
2074 /* Set the thread in both entries */
2075 ThisOwner
= ExpFindEntryForThread(Resource
,
2076 (ERESOURCE_THREAD
)OwnerPointer
,
2079 Owner
= ExpFindEntryForThread(Resource
, Thread
, 0, FALSE
);
2082 /* Nobody owns it, crash */
2083 KeBugCheckEx(RESOURCE_NOT_OWNED
,
2084 (ULONG_PTR
)Resource
,
2086 (ULONG_PTR
)Resource
->OwnerTable
,
2090 /* Set if we are the owner */
2094 ThisOwner
->OwnerCount
+= Owner
->OwnerCount
;
2095 Owner
->OwnerCount
= 0;
2096 Owner
->OwnerThread
= 0;
2097 ASSERT(Resource
->ActiveEntries
>= 2);
2098 Resource
->ActiveEntries
--;
2102 /* Update the owner entry instead */
2103 Owner
->OwnerThread
= (ERESOURCE_THREAD
)OwnerPointer
;
2107 /* Release the resource */
2108 ExReleaseResourceLock(Resource
, &LockHandle
);
2112 * @name ExTryToAcquireResourceExclusiveLite
2115 * The ExTryToAcquireResourceExclusiveLite routine routine attemps to
2116 * acquire the given resource for exclusive access.
2119 * Pointer to the resource to be acquired.
2121 * @return TRUE if the given resource has been acquired for the caller.
2123 * @remarks Callers of ExTryToAcquireResourceExclusiveLite must be running at
2124 * IRQL < DISPATCH_LEVEL.
2129 ExTryToAcquireResourceExclusiveLite(IN PERESOURCE Resource
)
2131 ERESOURCE_THREAD Thread
;
2132 KLOCK_QUEUE_HANDLE LockHandle
;
2133 BOOLEAN Acquired
= FALSE
;
2136 ASSERT((Resource
->Flag
& ResourceNeverExclusive
) == 0);
2138 /* Get the thread */
2139 Thread
= ExGetCurrentResourceThread();
2141 /* Sanity check and validation */
2142 ASSERT(KeIsExecutingDpc() == FALSE
);
2143 ExpVerifyResource(Resource
);
2145 /* Acquire the lock */
2146 ExAcquireResourceLock(Resource
, &LockHandle
);
2148 /* Check if there is an owner */
2149 if (!Resource
->ActiveCount
)
2151 /* No owner, give exclusive access */
2152 Resource
->Flag
|= ResourceOwnedExclusive
;
2153 Resource
->OwnerEntry
.OwnerThread
= Thread
;
2154 Resource
->OwnerEntry
.OwnerCount
= 1;
2155 Resource
->ActiveCount
= 1;
2156 Resource
->ActiveEntries
= 1;
2159 else if ((IsOwnedExclusive(Resource
)) &&
2160 (Resource
->OwnerEntry
.OwnerThread
== Thread
))
2162 /* Do a recursive acquire */
2163 Resource
->OwnerEntry
.OwnerCount
++;
2167 /* Release the resource */
2168 ExReleaseResourceLock(Resource
, &LockHandle
);
2173 * @name ExEnterCriticalRegionAndAcquireResourceExclusive
2174 * @implemented NT5.1
2176 * The ExEnterCriticalRegionAndAcquireResourceExclusive enters a critical
2177 * region and then exclusively acquires a resource.
2180 * Pointer to the resource to acquire.
2182 * @return Pointer to the Win32K thread pointer of the current thread.
2184 * @remarks See ExAcquireResourceExclusiveLite.
2189 ExEnterCriticalRegionAndAcquireResourceExclusive(IN PERESOURCE Resource
)
2191 /* Enter critical region */
2192 KeEnterCriticalRegion();
2194 /* Acquire the resource */
2195 ExAcquireResourceExclusiveLite(Resource
, TRUE
);
2197 /* Return the Win32 Thread */
2198 return KeGetCurrentThread()->Win32Thread
;
2202 * @name ExEnterCriticalRegionAndAcquireResourceShared
2203 * @implemented NT5.2
2205 * The ExEnterCriticalRegionAndAcquireResourceShared routine
2206 * enters a critical region and then acquires a resource shared.
2209 * Pointer to the resource to acquire.
2211 * @return Pointer to the Win32K thread pointer of the current thread.
2213 * @remarks See ExAcquireResourceSharedLite.
2218 ExEnterCriticalRegionAndAcquireResourceShared(IN PERESOURCE Resource
)
2220 /* Enter critical region */
2221 KeEnterCriticalRegion();
2223 /* Acquire the resource */
2224 ExAcquireResourceSharedLite(Resource
, TRUE
);
2226 /* Return the Win32 Thread */
2227 return KeGetCurrentThread()->Win32Thread
;
2231 * @name ExEnterCriticalRegionAndAcquireSharedWaitForExclusive
2232 * @implemented NT5.2
2234 * The ExEnterCriticalRegionAndAcquireSharedWaitForExclusive routine
2235 * enters a critical region and then acquires a resource shared if
2236 * shared access can be granted and there are no exclusive waiters.
2237 * It then acquires the resource exclusively.
2240 * Pointer to the resource to acquire.
2242 * @return Pointer to the Win32K thread pointer of the current thread.
2244 * @remarks See ExAcquireSharedWaitForExclusive.
2249 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(IN PERESOURCE Resource
)
2251 /* Enter critical region */
2252 KeEnterCriticalRegion();
2254 /* Acquire the resource */
2255 ExAcquireSharedWaitForExclusive(Resource
, TRUE
);
2257 /* Return the Win32 Thread */
2258 return KeGetCurrentThread()->Win32Thread
;
2262 * @name ExReleaseResourceAndLeaveCriticalRegion
2263 * @implemented NT5.1
2265 * The ExReleaseResourceAndLeaveCriticalRegion release a resource and
2266 * then leaves a critical region.
2269 * Pointer to the resource to release.
2273 * @remarks See ExReleaseResourceLite.
2278 ExReleaseResourceAndLeaveCriticalRegion(IN PERESOURCE Resource
)
2280 /* Release the resource */
2281 ExReleaseResourceLite(Resource
);
2283 /* Leave critical region */
2284 KeLeaveCriticalRegion();