[RSHELL]
[reactos.git] / ntoskrnl / ex / resource.c
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
23 FORCEINLINE
24 VOID
25 ExAcquireResourceLock(IN PERESOURCE Resource,
26 IN PKLOCK_QUEUE_HANDLE LockHandle)
27 {
28 UNREFERENCED_PARAMETER(Resource);
29 UNREFERENCED_PARAMETER(LockHandle);
30
31 /* Simply disable interrupts */
32 _disable();
33 }
34
35 FORCEINLINE
36 VOID
37 ExReleaseResourceLock(IN PERESOURCE Resource,
38 IN PKLOCK_QUEUE_HANDLE LockHandle)
39 {
40 UNREFERENCED_PARAMETER(Resource);
41 UNREFERENCED_PARAMETER(LockHandle);
42
43 /* Simply enable interrupts */
44 _enable();
45 }
46
47 #else
48
49 FORCEINLINE
50 VOID
51 ExAcquireResourceLock(IN PERESOURCE Resource,
52 IN PKLOCK_QUEUE_HANDLE LockHandle)
53 {
54 /* Acquire the lock */
55 KeAcquireInStackQueuedSpinLock(&Resource->SpinLock, LockHandle);
56 }
57
58 FORCEINLINE
59 VOID
60 ExReleaseResourceLock(IN PERESOURCE Resource,
61 IN PKLOCK_QUEUE_HANDLE LockHandle)
62 {
63 UNREFERENCED_PARAMETER(Resource);
64
65 /* Release the lock */
66 KeReleaseInStackQueuedSpinLock(LockHandle);
67 }
68 #endif
69
70 /* DATA***********************************************************************/
71
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;
78
79 /* PRIVATE FUNCTIONS *********************************************************/
80
81 #if DBG
82 /*++
83 * @name ExpVerifyResource
84 *
85 * The ExpVerifyResource routine verifies the correctness of an ERESOURCE
86 *
87 * @param Resource
88 * Pointer to the resource being verified.
89 *
90 * @return None.
91 *
92 * @remarks Only present on DBG builds.
93 *
94 *--*/
95 VOID
96 NTAPI
97 ExpVerifyResource(IN PERESOURCE Resource)
98 {
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)));
109 }
110
111 /*++
112 * @name ExpCheckForApcsDisabled
113 *
114 * The ExpCheckForApcsDisabled routine checks if Kernel APCs are still
115 * enabled when they should be disabled, and optionally breakpoints.
116 *
117 * @param Irql
118 * Specifies the IRQL during the acquire attempt.
119 *
120 * @param Resource
121 * Pointer to the resource being checked.
122 *
123 * @param Thread
124 * Pointer to the thread being checked.
125 *
126 * @return None.
127 *
128 * @remarks Only present on DBG builds. Depends on ExResourceStrict value.
129 *
130 *--*/
131 VOID
132 NTAPI
133 ExpCheckForApcsDisabled(IN KIRQL Irql,
134 IN PERESOURCE Resource,
135 IN PKTHREAD Thread)
136 {
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))
142 {
143 /* Bad! */
144 DPRINT1("EX: resource: APCs still enabled before resource %p acquire "
145 "!!!\n", Resource);
146 DbgBreakPoint();
147 }
148 }
149 #else
150 #define ExpVerifyResource(r)
151 #define ExpCheckForApcsDisabled(b,r,t)
152 #endif
153
154 /*++
155 * @name ExpResourceInitialization
156 *
157 * The ExpResourceInitialization routine initializes resources for use.
158 *
159 * @param None.
160 *
161 * @return None.
162 *
163 * @remarks This routine should only be called once, during system startup.
164 *
165 *--*/
166 VOID
167 NTAPI
168 INIT_FUNCTION
169 ExpResourceInitialization(VOID)
170 {
171 /* Setup the timeout */
172 ExpTimeout.QuadPart = Int32x32To64(4, -10000000);
173 InitializeListHead(&ExpSystemResourcesList);
174 KeInitializeSpinLock(&ExpResourceSpinLock);
175 }
176
177 /*++
178 * @name ExpAllocateExclusiveWaiterEvent
179 *
180 * The ExpAllocateExclusiveWaiterEvent routine creates the event that will
181 * be used by exclusive waiters on the resource.
182 *
183 * @param Resource
184 * Pointer to the resource.
185 *
186 * @param LockHandle
187 * Pointer to in-stack queued spinlock.
188 *
189 * @return None.
190 *
191 * @remarks The pointer to the event must be atomically set.
192 *
193 *--*/
194 VOID
195 NTAPI
196 ExpAllocateExclusiveWaiterEvent(IN PERESOURCE Resource,
197 IN PKLOCK_QUEUE_HANDLE LockHandle)
198 {
199 PKEVENT Event;
200
201 /* Release the lock */
202 ExReleaseResourceLock(Resource, LockHandle);
203
204 /* Loop as long as we keep running out of memory */
205 do
206 {
207 /* Allocate the event */
208 Event = ExAllocatePoolWithTag(NonPagedPool,
209 sizeof(KEVENT),
210 TAG_RESOURCE_EVENT);
211 if (Event)
212 {
213 /* Initialize it */
214 KeInitializeEvent(Event, SynchronizationEvent, FALSE);
215
216 /* Set it */
217 if (InterlockedCompareExchangePointer((PVOID*)&Resource->ExclusiveWaiters,
218 Event,
219 NULL))
220 {
221 /* Someone already set it, free our event */
222 DPRINT1("WARNING: Handling race condition\n");
223 ExFreePoolWithTag(Event, TAG_RESOURCE_EVENT);
224 }
225
226 break;
227 }
228
229 /* Wait a bit before trying again */
230 KeDelayExecutionThread(KernelMode, FALSE, &ExShortTime);
231 } while (TRUE);
232
233 /* Re-acquire the lock */
234 ExAcquireResourceLock(Resource, LockHandle);
235 }
236
237 /*++
238 * @name ExpAllocateSharedWaiterSemaphore
239 *
240 * The ExpAllocateSharedWaiterSemaphore routine creates the semaphore that
241 * will be used by shared waiters on the resource.
242 *
243 * @param Resource
244 * Pointer to the resource.
245 *
246 * @param LockHandle
247 * Pointer to in-stack queued spinlock.
248 *
249 * @return None.
250 *
251 * @remarks The pointer to the semaphore must be atomically set.
252 *
253 *--*/
254 VOID
255 NTAPI
256 ExpAllocateSharedWaiterSemaphore(IN PERESOURCE Resource,
257 IN PKLOCK_QUEUE_HANDLE LockHandle)
258 {
259 PKSEMAPHORE Semaphore;
260
261 /* Release the lock */
262 ExReleaseResourceLock(Resource, LockHandle);
263
264 /* Loop as long as we keep running out of memory */
265 do
266 {
267 /* Allocate the semaphore */
268 Semaphore = ExAllocatePoolWithTag(NonPagedPool,
269 sizeof(KSEMAPHORE),
270 TAG_RESOURCE_SEMAPHORE);
271 if (Semaphore)
272 {
273 /* Initialize it */
274 KeInitializeSemaphore(Semaphore, 0, MAXLONG);
275
276 /* Set it */
277 if (InterlockedCompareExchangePointer((PVOID*)&Resource->SharedWaiters,
278 Semaphore,
279 NULL))
280 {
281 /* Someone already set it, free our semaphore */
282 DPRINT1("WARNING: Handling race condition\n");
283 ExFreePoolWithTag(Semaphore, TAG_RESOURCE_SEMAPHORE);
284 }
285
286 break;
287 }
288
289 /* Wait a bit before trying again */
290 KeDelayExecutionThread(KernelMode, FALSE, &ExShortTime);
291 } while (TRUE);
292
293 /* Re-acquire the lock */
294 ExAcquireResourceLock(Resource, LockHandle);
295 }
296
297 /*++
298 * @name ExpExpandResourceOwnerTable
299 *
300 * The ExpExpandResourceOwnerTable routine expands the owner table of the
301 * specified resource.
302 *
303 * @param Resource
304 * Pointer to the resource.
305 *
306 * @param LockHandle
307 * Pointer to in-stack queued spinlock.
308 *
309 * @return None.
310 *
311 * @remarks None.
312 *
313 *--*/
314 VOID
315 NTAPI
316 ExpExpandResourceOwnerTable(IN PERESOURCE Resource,
317 IN PKLOCK_QUEUE_HANDLE LockHandle)
318 {
319 POWNER_ENTRY Owner, Table;
320 KIRQL OldIrql;
321 ULONG NewSize, OldSize;
322
323 /* Get the owner table */
324 Owner = Resource->OwnerTable;
325 if (!Owner)
326 {
327 /* Start with the default size of 3 */
328 OldSize = 0;
329 NewSize = 3;
330 }
331 else
332 {
333 /* Add 4 more entries */
334 OldSize = Owner->TableSize;
335 NewSize = OldSize + 4;
336 }
337
338 /* Release the lock */
339 ExReleaseResourceLock(Resource, LockHandle);
340
341 /* Allocate memory for the table */
342 Table = ExAllocatePoolWithTag(NonPagedPool,
343 NewSize * sizeof(OWNER_ENTRY),
344 TAG_RESOURCE_TABLE);
345
346 /* Zero the table */
347 RtlZeroMemory(Table + OldSize,
348 (NewSize - OldSize) * sizeof(OWNER_ENTRY));
349
350 /* Lock the resource */
351 ExAcquireResourceLock(Resource, LockHandle);
352
353 /* Make sure nothing has changed */
354 if ((Owner != Resource->OwnerTable) ||
355 ((Owner) && (OldSize != Owner->TableSize)))
356 {
357 /* Resource changed while we weren't holding the lock; bail out */
358 ExReleaseResourceLock(Resource, LockHandle);
359 ExFreePoolWithTag(Table, TAG_RESOURCE_TABLE);
360 }
361 else
362 {
363 /* Copy the table */
364 if (Owner) RtlCopyMemory(Table, Owner, OldSize * sizeof(OWNER_ENTRY));
365
366 /* Acquire dispatcher lock to prevent thread boosting */
367 OldIrql = KiAcquireDispatcherLock();
368
369 /* Set the new table data */
370 Table->TableSize = NewSize;
371 Resource->OwnerTable = Table;
372
373 /* Release dispatcher lock */
374 KiReleaseDispatcherLock(OldIrql);
375
376 /* Sanity check */
377 ExpVerifyResource(Resource);
378
379 /* Release lock */
380 ExReleaseResourceLock(Resource, LockHandle);
381
382 /* Free the old table */
383 if (Owner) ExFreePoolWithTag(Owner, TAG_RESOURCE_TABLE);
384
385 /* Set the resource index */
386 if (!OldSize) OldSize = 1;
387 }
388
389 /* Set the resource index */
390 KeGetCurrentThread()->ResourceIndex = (UCHAR)OldSize;
391
392 /* Lock the resource again */
393 ExAcquireResourceLock(Resource, LockHandle);
394 }
395
396 /*++
397 * @name ExpFindFreeEntry
398 *
399 * The ExpFindFreeEntry routine locates an empty owner entry in the
400 * specified resource. If none was found, then the owner table is
401 * expanded.
402 *
403 * @param Resource
404 * Pointer to the resource.
405 *
406 * @param LockHandle
407 * Pointer to in-stack queued spinlock.
408 *
409 * @return Pointer to an empty OWNER_ENTRY structure.
410 *
411 * @remarks None.
412 *
413 *--*/
414 POWNER_ENTRY
415 FASTCALL
416 ExpFindFreeEntry(IN PERESOURCE Resource,
417 IN PKLOCK_QUEUE_HANDLE LockHandle)
418 {
419 POWNER_ENTRY Owner, Limit;
420
421 /* Sanity check */
422 ASSERT(LockHandle != 0);
423 ASSERT(Resource->OwnerEntry.OwnerThread != 0);
424
425 /* Get the current table pointer */
426 Owner = Resource->OwnerTable;
427 if (Owner)
428 {
429 /* Set the limit, move to the next owner and loop owner entries */
430 Limit = &Owner[Owner->TableSize];
431 Owner++;
432 while (Owner->OwnerThread)
433 {
434 /* Move to the next one */
435 Owner++;
436
437 /* Check if the entry is free */
438 if (Owner == Limit) goto Expand;
439 }
440
441 /* Update the resource entry */
442 KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner - Resource->OwnerTable);
443 }
444 else
445 {
446 Expand:
447 /* No free entry, expand the table */
448 ExpExpandResourceOwnerTable(Resource, LockHandle);
449 Owner = NULL;
450 }
451
452 /* Return the entry found */
453 return Owner;
454 }
455
456 /*++
457 * @name ExpFindEntryForThread
458 *
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.
462 *
463 * @param Resource
464 * Pointer to the resource.
465 *
466 * @param Thread
467 * Pointer to the thread to find.
468 *
469 * @param LockHandle
470 * Pointer to in-stack queued spinlock.
471 *
472 * @return Pointer to an empty OWNER_ENTRY structure.
473 *
474 * @remarks None.
475 *
476 *--*/
477 POWNER_ENTRY
478 FASTCALL
479 ExpFindEntryForThread(IN PERESOURCE Resource,
480 IN ERESOURCE_THREAD Thread,
481 IN PKLOCK_QUEUE_HANDLE LockHandle,
482 IN BOOLEAN FirstEntryInelligible)
483 {
484 POWNER_ENTRY FreeEntry, Owner, Limit;
485
486 /* Start by looking in the static array */
487 Owner = &Resource->OwnerEntry;
488 if (Owner->OwnerThread == Thread) return Owner;
489
490 /* Check if this is a free entry */
491 if ((FirstEntryInelligible) || (Owner->OwnerThread))
492 {
493 /* No free entry */
494 FreeEntry = NULL;
495 }
496 else
497 {
498 /* Use the first entry as our free entry */
499 FreeEntry = Owner;
500 }
501
502 /* Get the current table pointer */
503 Owner = Resource->OwnerTable;
504 if (Owner)
505 {
506 /* Set the limit, move to the next owner and loop owner entries */
507 Limit = &Owner[Owner->TableSize];
508 Owner++;
509 while (Owner->OwnerThread != Thread)
510 {
511 /* Check if we don't have a free entry */
512 if (!FreeEntry)
513 {
514 /* Check if this entry is free */
515 if (!Owner->OwnerThread)
516 {
517 /* Save it as our free entry */
518 FreeEntry = Owner;
519 }
520 }
521
522 /* Move to the next one */
523 Owner++;
524
525 /* Check if the entry is free */
526 if (Owner == Limit) goto Expand;
527 }
528
529 /* Update the resource entry */
530 KeGetCurrentThread()->ResourceIndex = (UCHAR)(Owner - Resource->OwnerTable);
531 return Owner;
532 }
533 else
534 {
535 Expand:
536 /* Check if it's OK to do an expansion */
537 if (!LockHandle) return NULL;
538
539 /* If we found a free entry by now, return it */
540 if (FreeEntry)
541 {
542 /* Set the resource index */
543 KeGetCurrentThread()->ResourceIndex = (UCHAR)(FreeEntry - Resource->OwnerTable);
544 return FreeEntry;
545 }
546
547 /* No free entry, expand the table */
548 ExpExpandResourceOwnerTable(Resource, LockHandle);
549 return NULL;
550 }
551 }
552
553 /*++
554 * @name ExpBoostOwnerThread
555 *
556 * The ExpBoostOwnerThread routine increases the priority of a waiting
557 * thread in an attempt to fight a possible deadlock.
558 *
559 * @param Thread
560 * Pointer to the current thread.
561 *
562 * @param OwnerThread
563 * Pointer to thread that owns the resource.
564 *
565 * @return None.
566 *
567 * @remarks None.
568 *
569 *--*/
570 VOID
571 FASTCALL
572 ExpBoostOwnerThread(IN PKTHREAD Thread,
573 IN PKTHREAD OwnerThread)
574 {
575 /* Make sure the owner thread is a pointer, not an ID */
576 if (!((ULONG_PTR)OwnerThread & 0x3))
577 {
578 /* Check if we can actually boost it */
579 if ((OwnerThread->Priority < Thread->Priority) &&
580 (OwnerThread->Priority < 14))
581 {
582 /* Acquire the thread lock */
583 KiAcquireThreadLock(Thread);
584
585 /* Set the new priority */
586 OwnerThread->PriorityDecrement += 14 - OwnerThread->Priority;
587
588 /* Update quantum */
589 OwnerThread->Quantum = OwnerThread->QuantumReset;
590
591 /* Update the kernel state */
592 KiSetPriorityThread(OwnerThread, 14);
593
594 /* Release the thread lock */
595 KiReleaseThreadLock(Thread);
596 }
597 }
598 }
599
600 /*++
601 * @name ExpWaitForResource
602 *
603 * The ExpWaitForResource routine performs a wait on the specified resource.
604 *
605 * @param Resource
606 * Pointer to the resource to wait on.
607 *
608 * @param OwnerThread
609 * Pointer to object (exclusive event or shared semaphore) to wait on.
610 *
611 * @return None.
612 *
613 * @remarks None.
614 *
615 *--*/
616 VOID
617 FASTCALL
618 ExpWaitForResource(IN PERESOURCE Resource,
619 IN PVOID Object)
620 {
621 ULONG i;
622 ULONG Size;
623 POWNER_ENTRY Owner;
624 ULONG WaitCount = 0;
625 NTSTATUS Status;
626 LARGE_INTEGER Timeout;
627 PKTHREAD Thread, OwnerThread;
628 #if DBG
629 KLOCK_QUEUE_HANDLE LockHandle;
630 #endif
631
632 /* Increase contention count and use a 5 second timeout */
633 Resource->ContentionCount++;
634 Timeout.QuadPart = 500 * -10000;
635 for (;;)
636 {
637 /* Wait for ownership */
638 Status = KeWaitForSingleObject(Object,
639 WrResource,
640 KernelMode,
641 FALSE,
642 &Timeout);
643 if (Status != STATUS_TIMEOUT) break;
644
645 /* Increase wait count */
646 WaitCount++;
647 Timeout = ExpTimeout;
648
649 /* Check if we've exceeded the limit */
650 if (WaitCount > ExpResourceTimeoutCount)
651 {
652 /* Reset wait count */
653 WaitCount = 0;
654 #if DBG
655 /* Lock the resource */
656 ExAcquireResourceLock(Resource, &LockHandle);
657
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);
670
671 /* Dump out the table too */
672 Owner = Resource->OwnerTable;
673 if (Owner)
674 {
675 /* Loop every entry */
676 Size = Owner->TableSize;
677 for (i = 1; i < Size; i++)
678 {
679 /* Print the data */
680 Owner++;
681 DPRINT1(" Thread = %08lx, Count = %02x\n",
682 Owner->OwnerThread,
683 Owner->OwnerCount);
684 }
685 }
686
687 /* Break */
688 DbgBreakPoint();
689 DPRINT1("EX - Rewaiting\n");
690 ExReleaseResourceLock(Resource, &LockHandle);
691 #endif
692 }
693
694 /* Check if we can boost */
695 if (IsBoostAllowed(Resource))
696 {
697 /* Get the current kernel thread and lock the dispatcher */
698 Thread = KeGetCurrentThread();
699 Thread->WaitIrql = KiAcquireDispatcherLock();
700 Thread->WaitNext = TRUE;
701
702 /* Get the owner thread and boost it */
703 OwnerThread = (PKTHREAD)Resource->OwnerEntry.OwnerThread;
704 if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
705
706 /* If it's a shared resource */
707 if (!IsOwnedExclusive(Resource))
708 {
709 /* Get the table */
710 Owner = Resource->OwnerTable;
711 if (Owner)
712 {
713 /* Loop every entry */
714 Size = Owner->TableSize;
715 for (i = 1; i < Size; i++)
716 {
717 /* Move to next entry */
718 Owner++;
719
720 /* Get the thread */
721 OwnerThread = (PKTHREAD)Owner->OwnerThread;
722
723 /* Boost it */
724 if (OwnerThread) ExpBoostOwnerThread(Thread, OwnerThread);
725 }
726 }
727 }
728 }
729 }
730 }
731
732 /* FUNCTIONS *****************************************************************/
733
734 /*++
735 * @name ExAcquireResourceExclusiveLite
736 * @implemented NT4
737 *
738 * The ExAcquireResourceExclusiveLite routine acquires the given resource
739 * for exclusive access by the calling thread.
740 *
741 * @param Resource
742 * Pointer to the resource to acquire.
743 *
744 * @param Wait
745 * Specifies the routine's behavior whenever the resource cannot be
746 * acquired immediately.
747 *
748 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
749 * and exclusive access cannot be granted immediately.
750 *
751 * @remarks The caller can release the resource by calling either
752 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
753 *
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.
759 *
760 * For better performance, call ExTryToAcquireResourceExclusiveLite,
761 * rather than calling ExAcquireResourceExclusiveLite with Wait set
762 * to FALSE.
763 *
764 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
765 * DISPATCH_LEVEL.
766 *
767 *--*/
768 BOOLEAN
769 NTAPI
770 ExAcquireResourceExclusiveLite(IN PERESOURCE Resource,
771 IN BOOLEAN Wait)
772 {
773 KLOCK_QUEUE_HANDLE LockHandle;
774 ERESOURCE_THREAD Thread;
775 BOOLEAN Success;
776
777 /* Sanity check */
778 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
779
780 /* Get the thread */
781 Thread = ExGetCurrentResourceThread();
782
783 /* Sanity check and validation */
784 ASSERT(KeIsExecutingDpc() == FALSE);
785 ExpVerifyResource(Resource);
786
787 /* Acquire the lock */
788 ExAcquireResourceLock(Resource, &LockHandle);
789 ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread);
790
791 /* Check if there is a shared owner or exclusive owner */
792 TryAcquire:
793 if (Resource->ActiveEntries)
794 {
795 /* Check if it's exclusively owned, and we own it */
796 if ((IsOwnedExclusive(Resource)) &&
797 (Resource->OwnerEntry.OwnerThread == Thread))
798 {
799 /* Increase the owning count */
800 Resource->OwnerEntry.OwnerCount++;
801 Success = TRUE;
802 }
803 else
804 {
805 /*
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,
808 * then we'll wait.
809 */
810 if (!Wait)
811 {
812 Success = FALSE;
813 }
814 else
815 {
816 /* Check if it has exclusive waiters */
817 if (!Resource->ExclusiveWaiters)
818 {
819 /* It doesn't, allocate the event and try acquiring again */
820 ExpAllocateExclusiveWaiterEvent(Resource, &LockHandle);
821 goto TryAcquire;
822 }
823
824 /* Has exclusive waiters, wait on it */
825 Resource->NumberOfExclusiveWaiters++;
826 ExReleaseResourceLock(Resource, &LockHandle);
827 ExpWaitForResource(Resource, Resource->ExclusiveWaiters);
828
829 /* Set owner and return success */
830 Resource->OwnerEntry.OwnerThread = ExGetCurrentResourceThread();
831 return TRUE;
832 }
833 }
834 }
835 else
836 {
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;
845 Success = TRUE;
846 }
847
848 /* Release the lock and return */
849 ExReleaseResourceLock(Resource, &LockHandle);
850 return Success;
851 }
852
853 /*++
854 * @name ExAcquireResourceSharedLite
855 * @implemented NT4
856 *
857 * The ExAcquireResourceSharedLite routine acquires the given resource
858 * for shared access by the calling thread.
859 *
860 * @param Resource
861 * Pointer to the resource to acquire.
862 *
863 * @param Wait
864 * Specifies the routine's behavior whenever the resource cannot be
865 * acquired immediately.
866 *
867 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
868 * and exclusive access cannot be granted immediately.
869 *
870 * @remarks The caller can release the resource by calling either
871 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
872 *
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.
878 *
879 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
880 * DISPATCH_LEVEL.
881 *
882 *--*/
883 BOOLEAN
884 NTAPI
885 ExAcquireResourceSharedLite(IN PERESOURCE Resource,
886 IN BOOLEAN Wait)
887 {
888 KLOCK_QUEUE_HANDLE LockHandle;
889 ERESOURCE_THREAD Thread;
890 POWNER_ENTRY Owner = NULL;
891 BOOLEAN FirstEntryBusy;
892
893 /* Get the thread */
894 Thread = ExGetCurrentResourceThread();
895
896 /* Sanity check and validation */
897 ASSERT(KeIsExecutingDpc() == FALSE);
898 ExpVerifyResource(Resource);
899
900 /* Acquire the lock */
901 ExAcquireResourceLock(Resource, &LockHandle);
902 ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread);
903
904 /* Check how many active entries we've got */
905 while (Resource->ActiveEntries != 0)
906 {
907 /* Check if it's exclusively owned */
908 if (IsOwnedExclusive(Resource))
909 {
910 /* Check if we own it */
911 if (Resource->OwnerEntry.OwnerThread == Thread)
912 {
913 /* Increase the owning count */
914 Resource->OwnerEntry.OwnerCount++;
915
916 /* Release the lock and return */
917 ExReleaseResourceLock(Resource, &LockHandle);
918 return TRUE;
919 }
920
921 /* Find a free entry */
922 Owner = ExpFindFreeEntry(Resource, &LockHandle);
923 if (!Owner) continue;
924 }
925 else
926 {
927 /* Resource is shared, find who owns it */
928 FirstEntryBusy = IsExclusiveWaiting(Resource);
929 Owner = ExpFindEntryForThread(Resource,
930 Thread,
931 &LockHandle,
932 FirstEntryBusy);
933 if (!Owner) continue;
934
935 /* Is it us? */
936 if (Owner->OwnerThread == Thread)
937 {
938 /* Increase acquire count and return */
939 Owner->OwnerCount++;
940 ASSERT(Owner->OwnerCount != 0);
941
942 /* Release the lock and return */
943 ExReleaseResourceLock(Resource, &LockHandle);
944 return TRUE;
945 }
946
947 /* Try to find if there are exclusive waiters */
948 if (!FirstEntryBusy)
949 {
950 /* There are none, so acquire it */
951 Owner->OwnerThread = Thread;
952 Owner->OwnerCount = 1;
953
954 /* Check how many active entries we had */
955 if (Resource->ActiveEntries == 0)
956 {
957 /* Set initial counts */
958 ASSERT(Resource->ActiveCount == 0);
959 Resource->ActiveEntries = 1;
960 Resource->ActiveCount = 1;
961 }
962 else
963 {
964 /* Increase active entries */
965 ASSERT(Resource->ActiveCount == 1);
966 Resource->ActiveEntries++;
967 }
968
969 /* Release the lock and return */
970 ExReleaseResourceLock(Resource, &LockHandle);
971 return TRUE;
972 }
973 }
974
975 /* If we got here, then we need to wait. Are we allowed? */
976 if (!Wait)
977 {
978 /* Release the lock and return */
979 ExReleaseResourceLock(Resource, &LockHandle);
980 return FALSE;
981 }
982
983 /* Check if we have a shared waiters semaphore */
984 if (!Resource->SharedWaiters)
985 {
986 /* Allocate it and try another acquire */
987 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle);
988 }
989 else
990 {
991 /* We have shared waiters, wait for it */
992 break;
993 }
994 }
995
996 /* Did we get here because we don't have active entries? */
997 if (Resource->ActiveEntries == 0)
998 {
999 /* Acquire it */
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;
1006
1007 /* Release the lock and return */
1008 ExReleaseResourceLock(Resource, &LockHandle);
1009 return TRUE;
1010 }
1011
1012 /* Now wait for the resource */
1013 Owner->OwnerThread = Thread;
1014 Owner->OwnerCount = 1;
1015 Resource->NumberOfSharedWaiters++;
1016
1017 /* Release the lock and return */
1018 ExReleaseResourceLock(Resource, &LockHandle);
1019 ExpWaitForResource(Resource, Resource->SharedWaiters);
1020 return TRUE;
1021 }
1022
1023 /*++
1024 * @name ExAcquireSharedStarveExclusive
1025 * @implemented NT4
1026 *
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.
1030 *
1031 * @param Resource
1032 * Pointer to the resource to acquire.
1033 *
1034 * @param Wait
1035 * Specifies the routine's behavior whenever the resource cannot be
1036 * acquired immediately.
1037 *
1038 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
1039 * and exclusive access cannot be granted immediately.
1040 *
1041 * @remarks The caller can release the resource by calling either
1042 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
1043 *
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.
1049 *
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.
1056 *
1057 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
1058 * DISPATCH_LEVEL.
1059 *
1060 *--*/
1061 BOOLEAN
1062 NTAPI
1063 ExAcquireSharedStarveExclusive(IN PERESOURCE Resource,
1064 IN BOOLEAN Wait)
1065 {
1066 KLOCK_QUEUE_HANDLE LockHandle;
1067 ERESOURCE_THREAD Thread;
1068 POWNER_ENTRY Owner;
1069
1070 /* Get the thread */
1071 Thread = ExGetCurrentResourceThread();
1072
1073 /* Sanity check and validation */
1074 ASSERT(KeIsExecutingDpc() == FALSE);
1075 ExpVerifyResource(Resource);
1076
1077 /* Acquire the lock */
1078 ExAcquireResourceLock(Resource, &LockHandle);
1079
1080 /* See if anyone owns it */
1081 TryAcquire:
1082 if (Resource->ActiveEntries == 0)
1083 {
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;
1091
1092 /* Release the lock and return */
1093 ExReleaseResourceLock(Resource, &LockHandle);
1094 return TRUE;
1095 }
1096
1097 /* Check if it's exclusively owned */
1098 if (IsOwnedExclusive(Resource))
1099 {
1100 /* Check if we own it */
1101 if (Resource->OwnerEntry.OwnerThread == Thread)
1102 {
1103 /* Increase the owning count */
1104 Resource->OwnerEntry.OwnerCount++;
1105
1106 /* Release the lock and return */
1107 ExReleaseResourceLock(Resource, &LockHandle);
1108 return TRUE;
1109 }
1110
1111 /* Find a free entry */
1112 Owner = ExpFindFreeEntry(Resource, &LockHandle);
1113 if (!Owner) goto TryAcquire;
1114 }
1115 else
1116 {
1117 /* Resource is shared, find who owns it */
1118 Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, FALSE);
1119 if (!Owner) goto TryAcquire;
1120
1121 /* Is it us? */
1122 if (Owner->OwnerThread == Thread)
1123 {
1124 /* Increase acquire count and return */
1125 Owner->OwnerCount++;
1126 ASSERT(Owner->OwnerCount != 0);
1127
1128 /* Release the lock and return */
1129 ExReleaseResourceLock(Resource, &LockHandle);
1130 return TRUE;
1131 }
1132
1133 /* Acquire it */
1134 Owner->OwnerThread = Thread;
1135 Owner->OwnerCount = 1;
1136
1137 /* Check how many active entries we had */
1138 if (Resource->ActiveEntries == 0)
1139 {
1140 /* Set initial counts */
1141 ASSERT(Resource->ActiveCount == 0);
1142 Resource->ActiveEntries = 1;
1143 Resource->ActiveCount = 1;
1144 }
1145 else
1146 {
1147 /* Increase active entries */
1148 ASSERT(Resource->ActiveCount == 1);
1149 Resource->ActiveEntries++;
1150 }
1151
1152 /* Release the lock and return */
1153 ExReleaseResourceLock(Resource, &LockHandle);
1154 return TRUE;
1155 }
1156
1157 /* If we got here, then we need to wait. Are we allowed? */
1158 if (!Wait)
1159 {
1160 /* Release the lock and return */
1161 ExReleaseResourceLock(Resource, &LockHandle);
1162 return FALSE;
1163 }
1164
1165 /* Check if we have a shared waiters semaphore */
1166 if (!Resource->SharedWaiters)
1167 {
1168 /* Allocate it and try another acquire */
1169 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle);
1170 goto TryAcquire;
1171 }
1172
1173 /* Now wait for the resource */
1174 Owner->OwnerThread = Thread;
1175 Owner->OwnerCount = 1;
1176 Resource->NumberOfSharedWaiters++;
1177
1178 /* Release the lock and return */
1179 ExReleaseResourceLock(Resource, &LockHandle);
1180 ExpWaitForResource(Resource, Resource->SharedWaiters);
1181 return TRUE;
1182 }
1183
1184 /*++
1185 * @name ExAcquireSharedWaitForExclusive
1186 * @implemented NT4
1187 *
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.
1191 *
1192 * @param Resource
1193 * Pointer to the resource to acquire.
1194 *
1195 * @param Wait
1196 * Specifies the routine's behavior whenever the resource cannot be
1197 * acquired immediately.
1198 *
1199 * @return TRUE if the resource is acquired. FALSE if the input Wait is FALSE
1200 * and exclusive access cannot be granted immediately.
1201 *
1202 * @remarks The caller can release the resource by calling either
1203 * ExReleaseResourceLite or ExReleaseResourceForThreadLite.
1204 *
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.
1210 *
1211 * Callers of ExAcquireResourceExclusiveLite must be running at IRQL <
1212 * DISPATCH_LEVEL.
1213 *
1214 *--*/
1215 BOOLEAN
1216 NTAPI
1217 ExAcquireSharedWaitForExclusive(IN PERESOURCE Resource,
1218 IN BOOLEAN Wait)
1219 {
1220 KLOCK_QUEUE_HANDLE LockHandle;
1221 ERESOURCE_THREAD Thread;
1222 POWNER_ENTRY Owner;
1223
1224 /* Get the thread */
1225 Thread = ExGetCurrentResourceThread();
1226
1227 /* Sanity check and validation */
1228 ASSERT(KeIsExecutingDpc() == FALSE);
1229 ExpVerifyResource(Resource);
1230
1231 /* Acquire the lock */
1232 ExAcquireResourceLock(Resource, &LockHandle);
1233
1234 /* See if nobody owns us */
1235 TryAcquire:
1236 if (!Resource->ActiveEntries)
1237 {
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;
1245
1246 /* Release the lock and return */
1247 ExReleaseResourceLock(Resource, &LockHandle);
1248 return TRUE;
1249 }
1250
1251 /* Check if it's exclusively owned */
1252 if (IsOwnedExclusive(Resource))
1253 {
1254 /* Check if we own it */
1255 if (Resource->OwnerEntry.OwnerThread == Thread)
1256 {
1257 /* Increase the owning count */
1258 Resource->OwnerEntry.OwnerCount++;
1259
1260 /* Release the lock and return */
1261 ExReleaseResourceLock(Resource, &LockHandle);
1262 return TRUE;
1263 }
1264
1265 /* Find a free entry */
1266 Owner = ExpFindFreeEntry(Resource, &LockHandle);
1267 if (!Owner) goto TryAcquire;
1268 }
1269 else
1270 {
1271 /* Try to find if there are exclusive waiters */
1272 if (IsExclusiveWaiting(Resource))
1273 {
1274 /* We have to wait for the exclusive waiter to be done */
1275 if (!Wait)
1276 {
1277 /* So bail out if we're not allowed */
1278 ExReleaseResourceLock(Resource, &LockHandle);
1279 return FALSE;
1280 }
1281
1282 /* Check if we have a shared waiters semaphore */
1283 if (!Resource->SharedWaiters)
1284 {
1285 /* Allocate one and try again */
1286 ExpAllocateSharedWaiterSemaphore(Resource, &LockHandle);
1287 goto TryAcquire;
1288 }
1289
1290 /* Now wait for the resource */
1291 Resource->NumberOfSharedWaiters++;
1292 ExReleaseResourceLock(Resource, &LockHandle);
1293 ExpWaitForResource(Resource, Resource->SharedWaiters);
1294
1295 /* Get the lock back */
1296 ExAcquireResourceLock(Resource, &LockHandle);
1297
1298 /* Find who owns it now */
1299 while (!(Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, TRUE)));
1300
1301 /* Sanity checks */
1302 ASSERT(IsOwnedExclusive(Resource) == FALSE);
1303 ASSERT(Resource->ActiveEntries > 0);
1304 ASSERT(Owner->OwnerThread != Thread);
1305
1306 /* Take control */
1307 Owner->OwnerThread = Thread;
1308 Owner->OwnerCount = 1;
1309
1310 /* Release the lock and return */
1311 ExReleaseResourceLock(Resource, &LockHandle);
1312 return TRUE;
1313 }
1314 else
1315 {
1316 /* Resource is shared, find who owns it */
1317 Owner = ExpFindEntryForThread(Resource, Thread, &LockHandle, FALSE);
1318 if (!Owner) goto TryAcquire;
1319
1320 /* Is it us? */
1321 if (Owner->OwnerThread == Thread)
1322 {
1323 /* Increase acquire count and return */
1324 Owner->OwnerCount++;
1325 ASSERT(Owner->OwnerCount != 0);
1326
1327 /* Release the lock and return */
1328 ExReleaseResourceLock(Resource, &LockHandle);
1329 return TRUE;
1330 }
1331
1332 /* No exclusive waiters, so acquire it */
1333 Owner->OwnerThread = Thread;
1334 Owner->OwnerCount = 1;
1335
1336 /* Check how many active entries we had */
1337 if (Resource->ActiveEntries == 0)
1338 {
1339 /* Set initial counts */
1340 ASSERT(Resource->ActiveCount == 0);
1341 Resource->ActiveEntries = 1;
1342 Resource->ActiveCount = 1;
1343 }
1344 else
1345 {
1346 /* Increase active entries */
1347 ASSERT(Resource->ActiveCount == 1);
1348 Resource->ActiveEntries++;
1349 }
1350
1351 /* Release the lock and return */
1352 ExReleaseResourceLock(Resource, &LockHandle);
1353 return TRUE;
1354 }
1355 }
1356
1357 /* We have to wait for the exclusive waiter to be done */
1358 if (!Wait)
1359 {
1360 /* So bail out if we're not allowed */
1361 ExReleaseResourceLock(Resource, &LockHandle);
1362 return FALSE;
1363 }
1364
1365 /* Check if we have a shared waiters semaphore */
1366 if (!Resource->SharedWaiters)
1367 {
1368 /* Allocate one and try again */
1369 ExpAllocateSharedWaiterSemaphore(Resource,&LockHandle);
1370 goto TryAcquire;
1371 }
1372
1373 /* Take control */
1374 Owner->OwnerThread = Thread;
1375 Owner->OwnerCount = 1;
1376 Resource->NumberOfSharedWaiters++;
1377
1378 /* Release the lock and return */
1379 ExReleaseResourceLock(Resource, &LockHandle);
1380 ExpWaitForResource(Resource, Resource->SharedWaiters);
1381 return TRUE;
1382 }
1383
1384 /*++
1385 * @name ExConvertExclusiveToSharedLite
1386 * @implemented NT4
1387 *
1388 * The ExConvertExclusiveToSharedLite routine converts an exclusively
1389 * acquired resource into a resource that can be acquired shared.
1390 *
1391 * @param Resource
1392 * Pointer to the resource to convert.
1393 *
1394 * @return None.
1395 *
1396 * @remarks Callers of ExConvertExclusiveToSharedLite must be running at IRQL <
1397 * DISPATCH_LEVEL.
1398 *
1399 *--*/
1400 VOID
1401 NTAPI
1402 ExConvertExclusiveToSharedLite(IN PERESOURCE Resource)
1403 {
1404 ULONG OldWaiters;
1405 KLOCK_QUEUE_HANDLE LockHandle;
1406
1407 /* Sanity checks */
1408 ASSERT(KeIsExecutingDpc() == FALSE);
1409 ExpVerifyResource(Resource);
1410 ASSERT(IsOwnedExclusive(Resource));
1411 ASSERT(Resource->OwnerEntry.OwnerThread == (ERESOURCE_THREAD)PsGetCurrentThread());
1412
1413 /* Lock the resource */
1414 ExAcquireResourceLock(Resource, &LockHandle);
1415
1416 /* Erase the exclusive flag */
1417 Resource->Flag &= ~ResourceOwnedExclusive;
1418
1419 /* Check if we have shared waiters */
1420 if (IsSharedWaiting(Resource))
1421 {
1422 /* Make the waiters active owners */
1423 OldWaiters = Resource->NumberOfSharedWaiters;
1424 Resource->ActiveEntries += OldWaiters;
1425 Resource->NumberOfSharedWaiters = 0;
1426
1427 /* Release lock and wake the waiters */
1428 ExReleaseResourceLock(Resource, &LockHandle);
1429 KeReleaseSemaphore(Resource->SharedWaiters, 0, OldWaiters, FALSE);
1430 }
1431 else
1432 {
1433 /* Release lock */
1434 ExReleaseResourceLock(Resource, &LockHandle);
1435 }
1436 }
1437
1438 /*++
1439 * @name ExDeleteResourceLite
1440 * @implemented NT4
1441 *
1442 * The ExConvertExclusiveToSharedLite routine deletes a given resource
1443 * from the system\92s resource list.
1444 *
1445 * @param Resource
1446 * Pointer to the resource to delete.
1447 *
1448 * @return STATUS_SUCCESS if the resource was deleted.
1449 *
1450 * @remarks Callers of ExDeleteResourceLite must be running at IRQL <
1451 * DISPATCH_LEVEL.
1452 *
1453 *--*/
1454 NTSTATUS
1455 NTAPI
1456 ExDeleteResourceLite(IN PERESOURCE Resource)
1457 {
1458 KLOCK_QUEUE_HANDLE LockHandle;
1459
1460 /* Sanity checks */
1461 ASSERT(IsSharedWaiting(Resource) == FALSE);
1462 ASSERT(IsExclusiveWaiting(Resource) == FALSE);
1463 ASSERT(KeIsExecutingDpc() == FALSE);
1464 ExpVerifyResource(Resource);
1465
1466 /* Lock the resource */
1467 KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock, &LockHandle);
1468
1469 /* Remove the resource */
1470 RemoveEntryList(&Resource->SystemResourcesList);
1471
1472 /* Release the lock */
1473 KeReleaseInStackQueuedSpinLock(&LockHandle);
1474
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);
1479
1480 /* Return success */
1481 return STATUS_SUCCESS;
1482 }
1483
1484 /*++
1485 * @name ExDisableResourceBoostLite
1486 * @implemented NT4
1487 *
1488 * The ExDisableResourceBoostLite routine disables thread boosting for
1489 * the given resource.
1490 *
1491 * @param Resource
1492 * Pointer to the resource whose thread boosting will be disabled.
1493 *
1494 * @return None.
1495 *
1496 * @remarks None.
1497 *
1498 *--*/
1499 VOID
1500 NTAPI
1501 ExDisableResourceBoostLite(IN PERESOURCE Resource)
1502 {
1503 KLOCK_QUEUE_HANDLE LockHandle;
1504
1505 /* Sanity check */
1506 ExpVerifyResource(Resource);
1507
1508 /* Lock the resource */
1509 ExAcquireResourceLock(Resource, &LockHandle);
1510
1511 /* Remove the flag */
1512 Resource->Flag |= ResourceHasDisabledPriorityBoost;
1513
1514 /* Release the lock */
1515 ExReleaseResourceLock(Resource, &LockHandle);
1516 }
1517
1518 /*++
1519 * @name ExGetExclusiveWaiterCount
1520 * @implemented NT4
1521 *
1522 * The ExGetExclusiveWaiterCount routine returns the number of exclusive
1523 * waiters for the given resource.
1524 *
1525 * @param Resource
1526 * Pointer to the resource to check.
1527 *
1528 * @return The number of exclusive waiters.
1529 *
1530 * @remarks None.
1531 *
1532 *--*/
1533 ULONG
1534 NTAPI
1535 ExGetExclusiveWaiterCount(IN PERESOURCE Resource)
1536 {
1537 /* Return the count */
1538 return Resource->NumberOfExclusiveWaiters;
1539 }
1540
1541 /*++
1542 * @name ExGetSharedWaiterCount
1543 * @implemented NT4
1544 *
1545 * The ExGetSharedWaiterCount routine returns the number of shared
1546 * waiters for the given resource.
1547 *
1548 * @param Resource
1549 * Pointer to the resource to check.
1550 *
1551 * @return The number of shared waiters.
1552 *
1553 * @remarks None.
1554 *
1555 *--*/
1556 ULONG
1557 NTAPI
1558 ExGetSharedWaiterCount(IN PERESOURCE Resource)
1559 {
1560 /* Return the count */
1561 return Resource->NumberOfSharedWaiters;
1562 }
1563
1564 /*++
1565 * @name ExInitializeResourceLite
1566 * @implemented NT4
1567 *
1568 * The ExInitializeResourceLite routine initializes a resource variable.
1569 *
1570 * @param Resource
1571 * Pointer to the resource to check.
1572 *
1573 * @return STATUS_SUCCESS.
1574 *
1575 * @remarks The storage for ERESOURCE must not be allocated from paged pool.
1576 *
1577 * The storage must be 8-byte aligned.
1578 *
1579 *--*/
1580 NTSTATUS
1581 NTAPI
1582 ExInitializeResourceLite(IN PERESOURCE Resource)
1583 {
1584 KLOCK_QUEUE_HANDLE LockHandle;
1585
1586 /* Clear the structure */
1587 RtlZeroMemory(Resource, sizeof(ERESOURCE));
1588
1589 /* Initialize the lock */
1590 KeInitializeSpinLock(&Resource->SpinLock);
1591
1592 /* Add it into the system list */
1593 KeAcquireInStackQueuedSpinLock(&ExpResourceSpinLock, &LockHandle);
1594 InsertTailList(&ExpSystemResourcesList, &Resource->SystemResourcesList);
1595 KeReleaseInStackQueuedSpinLock(&LockHandle);
1596
1597 /* Return success */
1598 return STATUS_SUCCESS;
1599 }
1600
1601 /*++
1602 * @name ExIsResourceAcquiredExclusiveLite
1603 * @implemented NT4
1604 *
1605 * The ExIsResourceAcquiredExclusiveLite routine returns whether the
1606 * current thread has exclusive access to a given resource.
1607 *
1608 * @param Resource
1609 * Pointer to the resource to check.
1610 *
1611 * @return TRUE if the caller already has exclusive access to the given resource.
1612 *
1613 * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
1614 * IRQL <= DISPATCH_LEVEL.
1615 *
1616 *--*/
1617 BOOLEAN
1618 NTAPI
1619 ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
1620 {
1621 BOOLEAN IsAcquired = FALSE;
1622
1623 /* Sanity check */
1624 ExpVerifyResource(Resource);
1625
1626 /* Check if it's exclusively acquired */
1627 if ((IsOwnedExclusive(Resource)) &&
1628 (Resource->OwnerEntry.OwnerThread == ExGetCurrentResourceThread()))
1629 {
1630 /* It is acquired */
1631 IsAcquired = TRUE;
1632 }
1633
1634 /* Return if it's acquired */
1635 return IsAcquired;
1636 }
1637
1638 /*++
1639 * @name ExIsResourceAcquiredSharedLite
1640 * @implemented NT4
1641 *
1642 * The ExIsResourceAcquiredSharedLite routine returns whether the
1643 * current thread has has access (either shared or exclusive) to a
1644 * given resource.
1645 *
1646 * @param Resource
1647 * Pointer to the resource to check.
1648 *
1649 * @return Number of times the caller has acquired the given resource for
1650 * shared or exclusive access.
1651 *
1652 * @remarks Callers of ExIsResourceAcquiredExclusiveLite must be running at
1653 * IRQL <= DISPATCH_LEVEL.
1654 *
1655 *--*/
1656 ULONG
1657 NTAPI
1658 ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
1659 {
1660 ERESOURCE_THREAD Thread;
1661 ULONG i, Size;
1662 ULONG Count = 0;
1663 KLOCK_QUEUE_HANDLE LockHandle;
1664 POWNER_ENTRY Owner;
1665
1666 /* Sanity check */
1667 ExpVerifyResource(Resource);
1668
1669 /* Check if nobody owns us */
1670 if (!Resource->ActiveEntries) return 0;
1671
1672 /* Get the thread */
1673 Thread = ExGetCurrentResourceThread();
1674
1675 /* Check if we are in the thread list */
1676 if (Resource->OwnerEntry.OwnerThread == Thread)
1677 {
1678 /* Found it, return count */
1679 Count = Resource->OwnerEntry.OwnerCount;
1680 }
1681 else
1682 {
1683 /* We can't own an exclusive resource at this point */
1684 if (IsOwnedExclusive(Resource)) return 0;
1685
1686 /* Lock the resource */
1687 ExAcquireResourceLock(Resource, &LockHandle);
1688
1689 /* Not in the list, do a full table look up */
1690 Owner = Resource->OwnerTable;
1691 if (Owner)
1692 {
1693 /* Get the resource index */
1694 i = ((PKTHREAD)Thread)->ResourceIndex;
1695 Size = Owner->TableSize;
1696
1697 /* Check if the index is valid and check if we don't match */
1698 if ((i >= Size) || (Owner[i].OwnerThread != Thread))
1699 {
1700 /* Sh*t! We need to do a full search */
1701 for (i = 1; i < Size; i++)
1702 {
1703 /* Move to next owner */
1704 Owner++;
1705
1706 /* Try to find a match */
1707 if (Owner->OwnerThread == Thread)
1708 {
1709 /* Finally! */
1710 Count = Owner->OwnerCount;
1711 break;
1712 }
1713 }
1714 }
1715 else
1716 {
1717 /* We found the match directlry */
1718 Count = Owner[i].OwnerCount;
1719 }
1720 }
1721
1722 /* Release the lock */
1723 ExReleaseResourceLock(Resource, &LockHandle);
1724 }
1725
1726 /* Return count */
1727 return Count;
1728 }
1729
1730 /*++
1731 * @name ExReinitializeResourceLite
1732 * @implemented NT4
1733 *
1734 * The ExReinitializeResourceLite routine routine reinitializes
1735 * an existing resource variable.
1736 *
1737 * @param Resource
1738 * Pointer to the resource to be reinitialized.
1739 *
1740 * @return STATUS_SUCCESS.
1741 *
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.
1749 *
1750 * Callers of ExReinitializeResourceLite must be running at
1751 * IRQL <= DISPATCH_LEVEL.
1752 *
1753 *--*/
1754 NTSTATUS
1755 NTAPI
1756 ExReinitializeResourceLite(IN PERESOURCE Resource)
1757 {
1758 PKEVENT Event;
1759 PKSEMAPHORE Semaphore;
1760 ULONG i, Size;
1761 POWNER_ENTRY Owner;
1762
1763 /* Get the owner table */
1764 Owner = Resource->OwnerTable;
1765 if (Owner)
1766 {
1767 /* Get the size and loop it */
1768 Size = Owner->TableSize;
1769 for (i = 0; i < Size; i++)
1770 {
1771 /* Zero the table */
1772 Owner[i].OwnerThread = 0;
1773 Owner[i].OwnerCount = 0;
1774 }
1775 }
1776
1777 /* Zero the flags and count */
1778 Resource->Flag = 0;
1779 Resource->ActiveCount = 0;
1780 Resource->ActiveEntries = 0;
1781
1782 /* Reset the semaphore */
1783 Semaphore = Resource->SharedWaiters;
1784 if (Semaphore) KeInitializeSemaphore(Semaphore, 0, MAXLONG);
1785
1786 /* Reset the event */
1787 Event = Resource->ExclusiveWaiters;
1788 if (Event) KeInitializeEvent(Event, SynchronizationEvent, FALSE);
1789
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;
1797 }
1798
1799 /*++
1800 * @name ExReleaseResourceLite
1801 * @implemented NT4
1802 *
1803 * The ExReleaseResourceLite routine routine releases
1804 * a specified executive resource owned by the current thread.
1805 *
1806 * @param Resource
1807 * Pointer to the resource to be released.
1808 *
1809 * @return None.
1810 *
1811 * @remarks Callers of ExReleaseResourceLite must be running at
1812 * IRQL <= DISPATCH_LEVEL.
1813 *
1814 *--*/
1815 VOID
1816 FASTCALL
1817 ExReleaseResourceLite(IN PERESOURCE Resource)
1818 {
1819 /* Just call the For-Thread function */
1820 ExReleaseResourceForThreadLite(Resource, (ERESOURCE_THREAD)PsGetCurrentThread());
1821 }
1822
1823 /*++
1824 * @name ExReleaseResourceForThreadLite
1825 * @implemented NT4
1826 *
1827 * The ExReleaseResourceForThreadLite routine routine releases
1828 * the input resource of the indicated thread.
1829 *
1830 * @param Resource
1831 * Pointer to the resource to be released.
1832 *
1833 * @param Thread
1834 * Identifies the thread that originally acquired the resource.
1835 *
1836 * @return None.
1837 *
1838 * @remarks Callers of ExReleaseResourceForThreadLite must be running at
1839 * IRQL <= DISPATCH_LEVEL.
1840 *
1841 *--*/
1842 VOID
1843 NTAPI
1844 ExReleaseResourceForThreadLite(IN PERESOURCE Resource,
1845 IN ERESOURCE_THREAD Thread)
1846 {
1847 ULONG i;
1848 ULONG Count;
1849 KLOCK_QUEUE_HANDLE LockHandle;
1850 POWNER_ENTRY Owner, Limit;
1851 ASSERT(Thread != 0);
1852
1853 /* Get the thread and lock the resource */
1854 ExAcquireResourceLock(Resource, &LockHandle);
1855
1856 /* Sanity checks */
1857 ExpVerifyResource(Resource);
1858 ExpCheckForApcsDisabled(LockHandle.OldIrql, Resource, (PKTHREAD)Thread);
1859
1860 /* Check if it's exclusively owned */
1861 if (IsOwnedExclusive(Resource))
1862 {
1863 /* Decrement owner count and check if we're done */
1864 ASSERT(Resource->OwnerEntry.OwnerThread == Thread);
1865 if (--Resource->OwnerEntry.OwnerCount)
1866 {
1867 /* Done, release lock! */
1868 ExReleaseResourceLock(Resource, &LockHandle);
1869 return;
1870 }
1871
1872 /* Clear the owner */
1873 Resource->OwnerEntry.OwnerThread = 0;
1874
1875 /* Decrement the number of active entries */
1876 ASSERT(Resource->ActiveEntries == 1);
1877 Resource->ActiveEntries--;
1878
1879 /* Check if there are shared waiters */
1880 if (IsSharedWaiting(Resource))
1881 {
1882 /* Remove the exclusive flag */
1883 Resource->Flag &= ~ResourceOwnedExclusive;
1884
1885 /* Give ownage to another thread */
1886 Count = Resource->NumberOfSharedWaiters;
1887 Resource->ActiveEntries = Count;
1888 Resource->NumberOfSharedWaiters = 0;
1889
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);
1894 return;
1895 }
1896 else if (IsExclusiveWaiting(Resource))
1897 {
1898 /* Give exclusive access */
1899 Resource->OwnerEntry.OwnerThread = 1;
1900 Resource->OwnerEntry.OwnerCount = 1;
1901 Resource->ActiveEntries = 1;
1902 Resource->NumberOfExclusiveWaiters--;
1903
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);
1909 return;
1910 }
1911
1912 /* Remove the exclusive flag */
1913 Resource->Flag &= ~ResourceOwnedExclusive;
1914 Resource->ActiveCount = 0;
1915 }
1916 else
1917 {
1918 /* Check if we are in the thread list */
1919 if (Resource->OwnerEntry.OwnerThread == Thread)
1920 {
1921 /* Found it, get owner */
1922 Owner = &Resource->OwnerEntry;
1923 }
1924 else
1925 {
1926 /* Assume no valid index */
1927 i = 1;
1928
1929 /* If we got a valid pointer, try to get the resource index */
1930 if (!((ULONG)Thread & 3)) i = ((PKTHREAD)Thread)->ResourceIndex;
1931
1932 /* Do a table lookup */
1933 Owner = Resource->OwnerTable;
1934 ASSERT(Owner != NULL);
1935
1936 /* Check if we're out of the size and don't match */
1937 if ((i >= Owner->TableSize) || (Owner[i].OwnerThread != Thread))
1938 {
1939 /* Get the last entry */
1940 Limit = &Owner[Owner->TableSize];
1941 for (;;)
1942 {
1943 /* Move to the next entry */
1944 Owner++;
1945
1946 /* Make sure we're not out of bounds */
1947 if (Owner >= Limit)
1948 {
1949 /* Bugcheck, nobody owns us */
1950 KeBugCheckEx(RESOURCE_NOT_OWNED,
1951 (ULONG_PTR)Resource,
1952 (ULONG_PTR)Thread,
1953 (ULONG_PTR)Resource->OwnerTable,
1954 (ULONG_PTR)3);
1955 }
1956
1957 /* Check for a match */
1958 if (Owner->OwnerThread == Thread) break;
1959 }
1960 }
1961 else
1962 {
1963 /* Get the entry directly */
1964 Owner = &Owner[i];
1965 }
1966 }
1967
1968 /* Sanity checks */
1969 ASSERT(Owner->OwnerThread == Thread);
1970 ASSERT(Owner->OwnerCount > 0);
1971
1972 /* Check if we are the last owner */
1973 if (--Owner->OwnerCount)
1974 {
1975 /* There are other owners, release lock */
1976 ExReleaseResourceLock(Resource, &LockHandle);
1977 return;
1978 }
1979
1980 /* Clear owner */
1981 Owner->OwnerThread = 0;
1982
1983 /* See if the resource isn't being owned anymore */
1984 ASSERT(Resource->ActiveEntries > 0);
1985 if (!(--Resource->ActiveEntries))
1986 {
1987 /* Check if there's an exclusive waiter */
1988 if (IsExclusiveWaiting(Resource))
1989 {
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--;
1996
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);
2002 return;
2003 }
2004
2005 /* Clear the active count */
2006 Resource->ActiveCount = 0;
2007 }
2008 }
2009
2010 /* Release lock */
2011 ExReleaseResourceLock(Resource, &LockHandle);
2012 }
2013
2014 /*++
2015 * @name ExSetResourceOwnerPointer
2016 * @implemented NT4
2017 *
2018 * The ExSetResourceOwnerPointer routine routine sets the owner thread
2019 * thread pointer for an executive resource.
2020 *
2021 * @param Resource
2022 * Pointer to the resource whose owner to change.
2023 *
2024 * @param OwnerPointer
2025 * Pointer to an owner thread pointer of type ERESOURCE_THREAD.
2026 *
2027 * @return None.
2028 *
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
2033 * thread).
2034 *
2035 * After calling ExSetResourceOwnerPointer for a specific resource,
2036 * the only other routine that can be called for that resource is
2037 * ExReleaseResourceForThreadLite.
2038 *
2039 * Callers of ExSetResourceOwnerPointer must be running at
2040 * IRQL <= DISPATCH_LEVEL.
2041 *
2042 *--*/
2043 VOID
2044 NTAPI
2045 ExSetResourceOwnerPointer(IN PERESOURCE Resource,
2046 IN PVOID OwnerPointer)
2047 {
2048 ERESOURCE_THREAD Thread;
2049 KLOCK_QUEUE_HANDLE LockHandle;
2050 POWNER_ENTRY Owner, ThisOwner;
2051
2052 /* Sanity check */
2053 ASSERT((OwnerPointer != 0) && (((ULONG_PTR)OwnerPointer & 3) == 3));
2054
2055 /* Get the thread */
2056 Thread = ExGetCurrentResourceThread();
2057
2058 /* Sanity check */
2059 ExpVerifyResource(Resource);
2060
2061 /* Lock the resource */
2062 ExAcquireResourceLock(Resource, &LockHandle);
2063
2064 /* Check if it's exclusive */
2065 if (IsOwnedExclusive(Resource))
2066 {
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;
2071 }
2072 else
2073 {
2074 /* Set the thread in both entries */
2075 ThisOwner = ExpFindEntryForThread(Resource,
2076 (ERESOURCE_THREAD)OwnerPointer,
2077 0,
2078 FALSE);
2079 Owner = ExpFindEntryForThread(Resource, Thread, 0, FALSE);
2080 if (!Owner)
2081 {
2082 /* Nobody owns it, crash */
2083 KeBugCheckEx(RESOURCE_NOT_OWNED,
2084 (ULONG_PTR)Resource,
2085 Thread,
2086 (ULONG_PTR)Resource->OwnerTable,
2087 3);
2088 }
2089
2090 /* Set if we are the owner */
2091 if (ThisOwner)
2092 {
2093 /* Update data */
2094 ThisOwner->OwnerCount += Owner->OwnerCount;
2095 Owner->OwnerCount = 0;
2096 Owner->OwnerThread = 0;
2097 ASSERT(Resource->ActiveEntries >= 2);
2098 Resource->ActiveEntries--;
2099 }
2100 else
2101 {
2102 /* Update the owner entry instead */
2103 Owner->OwnerThread = (ERESOURCE_THREAD)OwnerPointer;
2104 }
2105 }
2106
2107 /* Release the resource */
2108 ExReleaseResourceLock(Resource, &LockHandle);
2109 }
2110
2111 /*++
2112 * @name ExTryToAcquireResourceExclusiveLite
2113 * @implemented NT4
2114 *
2115 * The ExTryToAcquireResourceExclusiveLite routine routine attemps to
2116 * acquire the given resource for exclusive access.
2117 *
2118 * @param Resource
2119 * Pointer to the resource to be acquired.
2120 *
2121 * @return TRUE if the given resource has been acquired for the caller.
2122 *
2123 * @remarks Callers of ExTryToAcquireResourceExclusiveLite must be running at
2124 * IRQL < DISPATCH_LEVEL.
2125 *
2126 *--*/
2127 BOOLEAN
2128 NTAPI
2129 ExTryToAcquireResourceExclusiveLite(IN PERESOURCE Resource)
2130 {
2131 ERESOURCE_THREAD Thread;
2132 KLOCK_QUEUE_HANDLE LockHandle;
2133 BOOLEAN Acquired = FALSE;
2134
2135 /* Sanity check */
2136 ASSERT((Resource->Flag & ResourceNeverExclusive) == 0);
2137
2138 /* Get the thread */
2139 Thread = ExGetCurrentResourceThread();
2140
2141 /* Sanity check and validation */
2142 ASSERT(KeIsExecutingDpc() == FALSE);
2143 ExpVerifyResource(Resource);
2144
2145 /* Acquire the lock */
2146 ExAcquireResourceLock(Resource, &LockHandle);
2147
2148 /* Check if there is an owner */
2149 if (!Resource->ActiveCount)
2150 {
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;
2157 Acquired = TRUE;
2158 }
2159 else if ((IsOwnedExclusive(Resource)) &&
2160 (Resource->OwnerEntry.OwnerThread == Thread))
2161 {
2162 /* Do a recursive acquire */
2163 Resource->OwnerEntry.OwnerCount++;
2164 Acquired = TRUE;
2165 }
2166
2167 /* Release the resource */
2168 ExReleaseResourceLock(Resource, &LockHandle);
2169 return Acquired;
2170 }
2171
2172 /*++
2173 * @name ExEnterCriticalRegionAndAcquireResourceExclusive
2174 * @implemented NT5.1
2175 *
2176 * The ExEnterCriticalRegionAndAcquireResourceExclusive enters a critical
2177 * region and then exclusively acquires a resource.
2178 *
2179 * @param Resource
2180 * Pointer to the resource to acquire.
2181 *
2182 * @return Pointer to the Win32K thread pointer of the current thread.
2183 *
2184 * @remarks See ExAcquireResourceExclusiveLite.
2185 *
2186 *--*/
2187 PVOID
2188 NTAPI
2189 ExEnterCriticalRegionAndAcquireResourceExclusive(IN PERESOURCE Resource)
2190 {
2191 /* Enter critical region */
2192 KeEnterCriticalRegion();
2193
2194 /* Acquire the resource */
2195 ExAcquireResourceExclusiveLite(Resource, TRUE);
2196
2197 /* Return the Win32 Thread */
2198 return KeGetCurrentThread()->Win32Thread;
2199 }
2200
2201 /*++
2202 * @name ExEnterCriticalRegionAndAcquireResourceShared
2203 * @implemented NT5.2
2204 *
2205 * The ExEnterCriticalRegionAndAcquireResourceShared routine
2206 * enters a critical region and then acquires a resource shared.
2207 *
2208 * @param Resource
2209 * Pointer to the resource to acquire.
2210 *
2211 * @return Pointer to the Win32K thread pointer of the current thread.
2212 *
2213 * @remarks See ExAcquireResourceSharedLite.
2214 *
2215 *--*/
2216 PVOID
2217 NTAPI
2218 ExEnterCriticalRegionAndAcquireResourceShared(IN PERESOURCE Resource)
2219 {
2220 /* Enter critical region */
2221 KeEnterCriticalRegion();
2222
2223 /* Acquire the resource */
2224 ExAcquireResourceSharedLite(Resource, TRUE);
2225
2226 /* Return the Win32 Thread */
2227 return KeGetCurrentThread()->Win32Thread;
2228 }
2229
2230 /*++
2231 * @name ExEnterCriticalRegionAndAcquireSharedWaitForExclusive
2232 * @implemented NT5.2
2233 *
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.
2238 *
2239 * @param Resource
2240 * Pointer to the resource to acquire.
2241 *
2242 * @return Pointer to the Win32K thread pointer of the current thread.
2243 *
2244 * @remarks See ExAcquireSharedWaitForExclusive.
2245 *
2246 *--*/
2247 PVOID
2248 NTAPI
2249 ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(IN PERESOURCE Resource)
2250 {
2251 /* Enter critical region */
2252 KeEnterCriticalRegion();
2253
2254 /* Acquire the resource */
2255 ExAcquireSharedWaitForExclusive(Resource, TRUE);
2256
2257 /* Return the Win32 Thread */
2258 return KeGetCurrentThread()->Win32Thread;
2259 }
2260
2261 /*++
2262 * @name ExReleaseResourceAndLeaveCriticalRegion
2263 * @implemented NT5.1
2264 *
2265 * The ExReleaseResourceAndLeaveCriticalRegion release a resource and
2266 * then leaves a critical region.
2267 *
2268 * @param Resource
2269 * Pointer to the resource to release.
2270 *
2271 * @return None
2272 *
2273 * @remarks See ExReleaseResourceLite.
2274 *
2275 *--*/
2276 VOID
2277 FASTCALL
2278 ExReleaseResourceAndLeaveCriticalRegion(IN PERESOURCE Resource)
2279 {
2280 /* Release the resource */
2281 ExReleaseResourceLite(Resource);
2282
2283 /* Leave critical region */
2284 KeLeaveCriticalRegion();
2285 }