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