1d6732616801b18514502c703b9790e56e01cf17
[reactos.git] / reactos / ntoskrnl / ex / resource.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ex/resource.c
6 * PURPOSE: Resource synchronization construct
7 *
8 * PROGRAMMERS: No programmer listed.
9 */
10
11
12 /*
13 * Usage of ERESOURCE members is not documented.
14 * From names of members and functionnalities, we can assume :
15 *
16 * OwnerTable = list of threads who have shared access(if more than one)
17 * ActiveCount = number of threads who have access to the resource
18 * Flag = bits : ResourceOwnedExclusive=0x80
19 * ResourceNeverExclusive=0x10
20 * ResourceReleaseByOtherThread=0x20
21 * ResourceDisableBoost=0x08
22 * SharedWaiters = semaphore, used to manage wait list of shared waiters.
23 * ExclusiveWaiters = event, used to manage wait list of exclusive waiters.
24 * OwnerThreads[0]= thread who have exclusive access
25 * OwnerThreads[1]= if only one thread own the resource
26 * thread who have shared access
27 * else
28 * OwnerThread=0
29 * and TableSize = number of entries in the owner table
30 * NumberOfExclusiveWaiters = number of threads waiting for exclusive access.
31 * NumberOfSharedWaiters = number of threads waiting for exclusive access.
32 *
33 */
34
35 #define ResourceDisableBoost 0x08
36
37 /* INCLUDES *****************************************************************/
38
39 #include <ntoskrnl.h>
40 #define NDEBUG
41 #include <internal/debug.h>
42
43 /* FUNCTIONS *****************************************************************/
44
45
46 BOOLEAN
47 STDCALL
48 ExTryToAcquireResourceExclusiveLite (
49 PERESOURCE Resource
50 )
51 /*
52 * FUNCTION: Attempts to require the resource for exclusive access
53 * ARGUMENTS:
54 * Resource = Points to the resource of be acquired
55 * RETURNS: TRUE if the resource was acquired for the caller
56 * NOTES: Must be acquired at IRQL < DISPATCH_LEVEL
57 */
58 {
59 return(ExAcquireResourceExclusiveLite(Resource,FALSE));
60 }
61
62 #ifdef ExAcquireResourceExclusive
63 #undef ExAcquireResourceExclusive
64 #endif
65
66 /*
67 * @implemented
68 */
69 BOOLEAN
70 STDCALL
71 ExAcquireResourceExclusive (
72 PERESOURCE Resource,
73 BOOLEAN Wait
74 )
75 {
76 return(ExAcquireResourceExclusiveLite(Resource,Wait));
77 }
78
79
80 /*
81 * @implemented
82 */
83 BOOLEAN
84 STDCALL
85 ExAcquireResourceExclusiveLite (
86 PERESOURCE Resource,
87 BOOLEAN Wait
88 )
89 /*
90 * FUNCTION: Acquires a resource exclusively for the calling thread
91 * ARGUMENTS:
92 * Resource = Points to the resource to acquire
93 * Wait = Is set to TRUE if the caller should wait to acquire the
94 * resource if it can't be acquired immediately
95 * RETURNS: TRUE if the resource was acquired,
96 * FALSE otherwise
97 * NOTES: Must be called at IRQL < DISPATCH_LEVEL
98 */
99 {
100 KIRQL oldIrql;
101
102 DPRINT("ExAcquireResourceExclusiveLite(Resource 0x%p, Wait %d)\n",
103 Resource, Wait);
104
105 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
106
107 /* undefed for now, since cdfs must be fixed first */
108 #if 0
109 /* At least regular kmode APC's must be disabled
110 * Note that this requirement is missing in old DDK's */
111 ASSERT(KeGetCurrentThread() == NULL || /* <-Early in the boot process the current thread is obseved to be NULL */
112 KeGetCurrentThread()->KernelApcDisable ||
113 KeGetCurrentIrql() == APC_LEVEL);
114 #endif
115
116 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
117
118 /* resource already locked */
119 if((Resource->Flag & ResourceOwnedExclusive)
120 && Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
121 {
122 /* it's ok : same lock for same thread */
123 Resource->OwnerThreads[0].OwnerCount++;
124 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
125 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
126 return(TRUE);
127 }
128
129 if (Resource->ActiveCount && !Wait)
130 {
131 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
132 DPRINT("ExAcquireResourceExclusiveLite() = FALSE\n");
133 return(FALSE);
134 }
135
136 /*
137 * This is slightly better than it looks because other exclusive
138 * threads who are waiting won't be woken up but there is a race
139 * with new threads trying to grab the resource so we must have
140 * the spinlock, still normally this loop will only be executed
141 * once
142 * NOTE: We might want to set a timeout to detect deadlock
143 * (10 minutes?)
144 */
145 while (Resource->ActiveCount)
146 {
147 Resource->NumberOfExclusiveWaiters++;
148 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
149 KeWaitForSingleObject(Resource->ExclusiveWaiters,
150 Executive,
151 KernelMode,
152 FALSE,
153 NULL);
154 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
155 Resource->NumberOfExclusiveWaiters--;
156 }
157 Resource->Flag |= ResourceOwnedExclusive;
158 Resource->ActiveCount = 1;
159 Resource->OwnerThreads[0].OwnerThread = ExGetCurrentResourceThread();
160 Resource->OwnerThreads[0].OwnerCount = 1;
161 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
162 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
163 return(TRUE);
164 }
165
166 static BOOLEAN EiRemoveSharedOwner(PERESOURCE Resource,
167 ERESOURCE_THREAD ResourceThreadId)
168 /*
169 * FUNCTION: Removes the current thread from the shared owners of the resource
170 * ARGUMENTS:
171 * Resource = Pointer to the resource for which the thread is to be
172 * added
173 * NOTE: Must be called with the resource spinlock held
174 */
175 {
176 ULONG i;
177
178 if (Resource->OwnerThreads[1].OwnerThread == ResourceThreadId)
179 {
180 Resource->OwnerThreads[1].OwnerCount--;
181 if (Resource->OwnerThreads[1].OwnerCount == 0)
182 {
183 Resource->ActiveCount--;
184 Resource->OwnerThreads[1].OwnerThread = 0;
185 }
186 return(TRUE);
187 }
188
189 if (Resource->OwnerThreads[1].OwnerThread)
190 {
191 /* Oh dear, the caller didn't own the resource after all */
192 return(FALSE);
193 }
194
195 for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
196 {
197 if (Resource->OwnerTable[i].OwnerThread == ResourceThreadId)
198 {
199 Resource->OwnerTable[i].OwnerCount--;
200 if (Resource->OwnerTable[i].OwnerCount == 0)
201 {
202 Resource->ActiveCount--;
203 Resource->OwnerTable[i].OwnerThread = 0;
204 }
205 return TRUE;
206 }
207 }
208 return(FALSE);
209 }
210
211 static BOOLEAN EiAddSharedOwner(PERESOURCE Resource)
212 /*
213 * FUNCTION: Adds the current thread to the shared owners of the resource
214 * ARGUMENTS:
215 * Resource = Pointer to the resource for which the thread is to be
216 * added
217 * NOTE: Must be called with the resource spinlock held
218 */
219 {
220 ERESOURCE_THREAD CurrentThread = ExGetCurrentResourceThread();
221 POWNER_ENTRY freeEntry;
222 ULONG i = 0;
223
224 DPRINT("EiAddSharedOwner(Resource 0x%p)\n", Resource);
225
226 if (Resource->ActiveCount == 0)
227 {
228 /* no owner, it's easy */
229 Resource->OwnerThreads[1].OwnerThread = ExGetCurrentResourceThread();
230 Resource->OwnerThreads[1].OwnerCount = 1;
231 if (Resource->OwnerTable != NULL)
232 {
233 ExFreePool(Resource->OwnerTable);
234 }
235 Resource->OwnerTable = NULL;
236 Resource->ActiveCount = 1;
237 DPRINT("EiAddSharedOwner() = TRUE\n");
238 return(TRUE);
239 }
240
241 /*
242 * now, we must search if this thread has already acquired this resource
243 * then increase ownercount if found, else create new entry or reuse free
244 * entry
245 */
246 if (Resource->OwnerTable == NULL)
247 {
248 DPRINT("Creating owner table\n");
249
250 /* allocate ownertable,memset to 0, initialize first entry */
251 Resource->OwnerTable =
252 ExAllocatePoolWithTag(NonPagedPool, sizeof(OWNER_ENTRY)*3,
253 TAG_OWNER_TABLE);
254 if (Resource->OwnerTable == NULL)
255 {
256 KEBUGCHECK(0);
257 return(FALSE);
258 }
259 memset(Resource->OwnerTable,0,sizeof(OWNER_ENTRY)*3);
260 memcpy(&Resource->OwnerTable[0], &Resource->OwnerThreads[1],
261 sizeof(OWNER_ENTRY));
262
263 Resource->OwnerThreads[1].OwnerThread = 0;
264 Resource->OwnerThreads[1].TableSize = 3;
265
266 Resource->OwnerTable[1].OwnerThread = CurrentThread;
267 Resource->OwnerTable[1].OwnerCount = 1;
268 Resource->ActiveCount++;
269
270 return(TRUE);
271 }
272
273 DPRINT("Search free entries\n");
274
275 DPRINT("Number of entries %d\n",
276 Resource->OwnerThreads[1].TableSize);
277
278 freeEntry = NULL;
279 for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
280 {
281 if (Resource->OwnerTable[i].OwnerThread == CurrentThread)
282 {
283 DPRINT("Thread already owns resource\n");
284 Resource->OwnerTable[i].OwnerCount++;
285 return(TRUE);
286 }
287 if (Resource->OwnerTable[i].OwnerThread == 0)
288 {
289 freeEntry = &Resource->OwnerTable[i];
290 break;
291 }
292 }
293
294 DPRINT("Found free entry 0x%p\n", freeEntry);
295
296 if (!freeEntry)
297 {
298 DPRINT("Allocating new entry\n");
299
300 /* reallocate ownertable with one more entry */
301 freeEntry =
302 ExAllocatePoolWithTag(NonPagedPool,
303 sizeof(OWNER_ENTRY)*
304 (Resource->OwnerThreads[1].TableSize+1),
305 TAG_OWNER_TABLE);
306 if (freeEntry == NULL)
307 {
308 KEBUGCHECK(0);
309 return(FALSE);
310 }
311 memcpy(freeEntry,Resource->OwnerTable,
312 sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].TableSize));
313 ExFreePool(Resource->OwnerTable);
314 Resource->OwnerTable=freeEntry;
315 freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].TableSize];
316 Resource->OwnerThreads[1].TableSize++;
317 }
318 DPRINT("Creating entry\n");
319 freeEntry->OwnerThread=ExGetCurrentResourceThread();
320 freeEntry->OwnerCount=1;
321 Resource->ActiveCount++;
322 return(TRUE);
323 }
324
325 /*
326 * @implemented
327 */
328 BOOLEAN
329 STDCALL
330 ExAcquireResourceSharedLite (
331 PERESOURCE Resource,
332 BOOLEAN Wait
333 )
334 /*
335 * FUNCTION: Acquires the given resource for shared access by the calling
336 * thread
337 * ARGUMENTS:
338 * Resource = Points to the resource to acquire
339 * Wait = Is set to TRUE if the caller should be put into wait state
340 * until the resource can be acquired if it cannot be acquired
341 * immediately
342 * RETURNS: TRUE, if the resource is acquire
343 * FALSE otherwise
344 */
345 {
346 KIRQL oldIrql;
347
348 DPRINT("ExAcquireResourceSharedLite(Resource 0x%p, Wait %d)\n",
349 Resource, Wait);
350
351 ASSERT_IRQL_LESS(DISPATCH_LEVEL);
352
353 /* undefed for now, since cdfs must be fixed first */
354 #if 0
355 /* At least regular kmode APC's must be disabled
356 * Note that this requirement is missing in old DDK's
357 */
358 ASSERT(KeGetCurrentThread() == NULL || /* <-Early in the boot process the current thread is obseved to be NULL */
359 KeGetCurrentThread()->KernelApcDisable ||
360 KeGetCurrentIrql() == APC_LEVEL);
361 #endif
362
363 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
364
365 /* first, resolve trivial cases */
366 if (Resource->ActiveCount == 0)
367 {
368 EiAddSharedOwner(Resource);
369 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
370 DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
371 return(TRUE);
372 }
373
374 if ((Resource->Flag & ResourceOwnedExclusive)
375 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
376 {
377 /* exclusive, but by same thread : it's ok */
378 /*
379 * NOTE: Is this correct? Seems the same as ExConvertExclusiveToShared
380 */
381 Resource->OwnerThreads[0].OwnerCount++;
382 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
383 DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
384 return(TRUE);
385 }
386
387 if ((Resource->Flag & ResourceOwnedExclusive)
388 || Resource->NumberOfExclusiveWaiters)
389 {
390 /* exclusive by another thread , or thread waiting for exclusive */
391 if (!Wait)
392 {
393 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
394 DPRINT("ExAcquireResourceSharedLite() = FALSE\n");
395 return(FALSE);
396 }
397 else
398 {
399 Resource->NumberOfSharedWaiters++;
400 do
401 {
402 /* wait for the semaphore */
403 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
404 KeWaitForSingleObject(Resource->SharedWaiters,0, KernelMode, FALSE, NULL);
405 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
406 /* the spin lock was released we must check again */
407 }
408 while ((Resource->Flag & ResourceOwnedExclusive)
409 || Resource->NumberOfExclusiveWaiters);
410 Resource->NumberOfSharedWaiters--;
411 }
412 }
413
414 EiAddSharedOwner(Resource);
415 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
416 DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
417 return(TRUE);
418 }
419
420 /*
421 * @implemented
422 */
423 VOID
424 STDCALL
425 ExConvertExclusiveToSharedLite (
426 PERESOURCE Resource
427 )
428 /*
429 * FUNCTION: Converts a given resource from acquired for exclusive access
430 * to acquire for shared access
431 * ARGUMENTS:
432 * Resource = Points to the resource for which the access should be
433 * converted
434 * NOTES: Caller must be running at IRQL < DISPATCH_LEVEL
435 */
436 {
437 ULONG oldWaiters;
438 KIRQL oldIrql;
439
440 DPRINT("ExConvertExclusiveToSharedLite(Resource 0x%p)\n", Resource);
441
442 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
443
444 oldWaiters = Resource->NumberOfSharedWaiters;
445
446 if (!(Resource->Flag & ResourceOwnedExclusive))
447 {
448 /* Might not be what the caller expects, better bug check */
449 KEBUGCHECK(0);
450 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
451 return;
452 }
453
454 //transfer infos from entry 0 to entry 1 and erase entry 0
455 Resource->OwnerThreads[1].OwnerThread=Resource->OwnerThreads[0].OwnerThread;
456 Resource->OwnerThreads[1].OwnerCount=Resource->OwnerThreads[0].OwnerCount;
457 Resource->OwnerThreads[0].OwnerThread=0;
458 Resource->OwnerThreads[0].OwnerCount=0;
459 /* erase exclusive flag */
460 Resource->Flag &= (~ResourceOwnedExclusive);
461 /* if no shared waiters, that's all */
462 if (!oldWaiters)
463 {
464 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
465 return;
466 }
467 /* else, awake the waiters */
468 KeReleaseSemaphore(Resource->SharedWaiters,0,oldWaiters,0);
469 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
470 DPRINT("ExConvertExclusiveToSharedLite() finished\n");
471 }
472
473 /*
474 * @implemented
475 */
476 VOID
477 STDCALL
478 ExDisableResourceBoostLite (
479 PERESOURCE Resource
480 )
481 {
482 Resource->Flag |= ResourceDisableBoost;
483 }
484
485 /*
486 * @implemented
487 */
488 ULONG
489 STDCALL
490 ExGetExclusiveWaiterCount (
491 PERESOURCE Resource
492 )
493 {
494 return(Resource->NumberOfExclusiveWaiters);
495 }
496
497 /*
498 * @implemented
499 */
500 BOOLEAN
501 STDCALL
502 ExAcquireSharedStarveExclusive (
503 PERESOURCE Resource,
504 BOOLEAN Wait
505 )
506 /*
507 * FUNCTION: Acquires a given resource for shared access without waiting
508 * for any pending attempts to acquire exclusive access to the
509 * same resource
510 * ARGUMENTS:
511 * Resource = Points to the resource to be acquired for shared access
512 * Wait = Is set to TRUE if the caller will wait until the resource
513 * becomes available when access can't be granted immediately
514 * RETURNS: TRUE if the requested access is granted. The routine returns
515 * FALSE if the input Wait is FALSE and shared access can't be
516 * granted immediately
517 */
518 {
519 KIRQL oldIrql;
520
521 DPRINT("ExAcquireSharedStarveExclusive(Resource 0x%p, Wait %d)\n",
522 Resource, Wait);
523
524 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
525
526 /* no owner, it's easy */
527 if (Resource->ActiveCount == 0)
528 {
529 Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread();
530 Resource->OwnerThreads[1].OwnerCount=1;
531 Resource->ActiveCount=1;
532 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
533 DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
534 return(TRUE);
535 }
536
537 if ((Resource->Flag & ResourceOwnedExclusive)
538 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
539 {
540 /* exclusive, but by same thread : it's ok */
541 Resource->OwnerThreads[0].OwnerCount++;
542 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
543 DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
544 return(TRUE);
545 }
546
547 if (Resource->Flag & ResourceOwnedExclusive)
548 {
549 /* exclusive by another thread */
550 if (!Wait)
551 {
552 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
553 DPRINT("ExAcquireSharedStarveExclusive() = FALSE\n");
554 return(FALSE);
555 }
556 else
557 {
558 Resource->NumberOfSharedWaiters++;
559 /* wait for the semaphore */
560 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
561 KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0);
562 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
563 Resource->NumberOfSharedWaiters--;
564 }
565 }
566 EiAddSharedOwner(Resource);
567 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
568 DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
569 return(TRUE);
570 }
571
572 /*
573 * @implemented
574 */
575 BOOLEAN
576 STDCALL
577 ExAcquireSharedWaitForExclusive (
578 PERESOURCE Resource,
579 BOOLEAN Wait
580 )
581 {
582 return(ExAcquireResourceSharedLite(Resource,Wait));
583 }
584
585
586 #ifdef ExDeleteResource
587 #undef ExDeleteResource
588 #endif
589
590
591 /*
592 * @implemented
593 */
594 NTSTATUS
595 STDCALL
596 ExDeleteResource (
597 PERESOURCE Resource
598 )
599 {
600 return(ExDeleteResourceLite(Resource));
601 }
602
603 /*
604 * @implemented
605 */
606 NTSTATUS
607 STDCALL
608 ExDeleteResourceLite (
609 PERESOURCE Resource
610 )
611 {
612 DPRINT("ExDeleteResourceLite(Resource 0x%p)\n", Resource);
613 if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
614 if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
615 if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
616 return(STATUS_SUCCESS);
617 }
618
619 /*
620 * @implemented
621 */
622 ULONG
623 STDCALL
624 ExGetSharedWaiterCount (
625 PERESOURCE Resource
626 )
627 {
628 return(Resource->NumberOfSharedWaiters);
629 }
630
631
632 #ifdef ExInitializeResource
633 #undef ExInitializeResource
634 #endif
635
636 /*
637 * @implemented
638 */
639 NTSTATUS
640 STDCALL
641 ExInitializeResource (
642 PERESOURCE Resource
643 )
644 {
645 return(ExInitializeResourceLite(Resource));
646 }
647
648 /*
649 * @implemented
650 */
651 NTSTATUS STDCALL
652 ExInitializeResourceLite (PERESOURCE Resource)
653 {
654 DPRINT("ExInitializeResourceLite(Resource 0x%p)\n", Resource);
655 memset(Resource,0,sizeof(ERESOURCE));
656 Resource->NumberOfSharedWaiters = 0;
657 Resource->NumberOfExclusiveWaiters = 0;
658 KeInitializeSpinLock(&Resource->SpinLock);
659 Resource->Flag = 0;
660 Resource->ExclusiveWaiters =
661 ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_EXCLUSIVE_LOCK);
662 KeInitializeEvent(Resource->ExclusiveWaiters,
663 SynchronizationEvent,
664 FALSE);
665 Resource->SharedWaiters =
666 ExAllocatePoolWithTag(NonPagedPool ,sizeof(KSEMAPHORE), TAG_SHARED_SEM);
667 KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
668 Resource->ActiveCount = 0;
669 return(0);
670 }
671
672 /*
673 * @implemented
674 */
675 BOOLEAN
676 STDCALL
677 ExIsResourceAcquiredExclusiveLite (
678 PERESOURCE Resource
679 )
680 /*
681 * FUNCTION: Returns whether the current thread has exclusive access to
682 * a given resource
683 * ARGUMENTS:
684 * Resource = Points to the resource to be queried
685 * RETURNS: TRUE if the caller has exclusive access to the resource,
686 * FALSE otherwise
687 */
688 {
689 return((Resource->Flag & ResourceOwnedExclusive)
690 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
691 }
692
693
694
695 #ifdef ExIsResourceAcquiredSharedLite
696 #undef ExIsResourceAcquiredSharedLite
697 #endif
698
699
700 /*
701 * @implemented
702 */
703
704
705 //NTOSAPI
706 //DDKAPI
707 USHORT STDCALL
708 ExIsResourceAcquiredSharedLite(
709 IN PERESOURCE Resource)
710 /*
711 * FUNCTION: Returns whether the current thread has shared access to a given
712 * resource
713 * ARGUMENTS:
714 * Resource = Points to the resource to be queried
715 * RETURNS: The number of times the caller has acquired shared access to the
716 * given resource
717 */
718 {
719 ULONG i;
720 if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
721 {
722 return (USHORT)(Resource->OwnerThreads[0].OwnerCount);
723 }
724 if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
725 {
726 return (USHORT)(Resource->OwnerThreads[1].OwnerCount);
727 }
728 if (!Resource->OwnerThreads[1].TableSize)
729 {
730 return(0);
731 }
732 for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
733 {
734 if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
735 {
736 return (USHORT)Resource->OwnerTable[i].OwnerCount;
737 }
738 }
739 return(0);
740 }
741
742 /*
743 * @implemented
744 */
745 VOID
746 STDCALL
747 ExReinitializeResourceLite (
748 PERESOURCE Resource
749 )
750 {
751 Resource->NumberOfSharedWaiters = 0;
752 Resource->NumberOfExclusiveWaiters = 0;
753 KeInitializeSpinLock(&Resource->SpinLock);
754 Resource->Flag=0;
755 KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
756 FALSE);
757 KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
758 Resource->ActiveCount = 0;
759 if (Resource->OwnerTable)
760 {
761 ExFreePool(Resource->OwnerTable);
762 }
763 Resource->OwnerThreads[0].OwnerThread=0;
764 Resource->OwnerThreads[0].OwnerCount=0;
765 Resource->OwnerThreads[1].OwnerThread=0;
766 Resource->OwnerThreads[1].OwnerCount=0;
767 }
768
769 /*
770 * @implemented
771 */
772 VOID
773 FASTCALL
774 ExReleaseResourceLite (
775 PERESOURCE Resource
776 )
777 {
778 ExReleaseResourceForThreadLite(Resource,
779 ExGetCurrentResourceThread());
780 }
781
782
783
784 #ifdef ExReleaseResourceForThread
785 #undef ExReleaseResourceForThread
786 #endif
787
788
789 /*
790 * @implemented
791 */
792 VOID
793 STDCALL
794 ExReleaseResourceForThread (
795 PERESOURCE Resource,
796 ERESOURCE_THREAD ResourceThreadId
797 )
798 {
799 ExReleaseResourceForThreadLite(Resource,ResourceThreadId);
800 }
801
802
803 /*
804 * @implemented
805 */
806 VOID
807 STDCALL
808 ExReleaseResourceForThreadLite (
809 PERESOURCE Resource,
810 ERESOURCE_THREAD ResourceThreadId
811 )
812 /*
813 * FUNCTION: Releases a resource for the given thread
814 * ARGUMENTS:
815 * Resource = Points to the release to release
816 * ResourceThreadId = Identifies the thread that originally acquired
817 * the resource
818 * NOTES: Must be running at IRQL < DISPATCH_LEVEL
819 * BUG: We don't support starving exclusive waiters
820 */
821 {
822 KIRQL oldIrql;
823
824 DPRINT("ExReleaseResourceForThreadLite(Resource 0x%p, ResourceThreadId 0x%p)\n",
825 Resource, ResourceThreadId);
826
827 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
828
829 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
830
831 if (Resource->Flag & ResourceOwnedExclusive)
832 {
833 DPRINT("Releasing from exclusive access\n");
834
835 Resource->OwnerThreads[0].OwnerCount--;
836 if (Resource->OwnerThreads[0].OwnerCount > 0)
837 {
838 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
839 DPRINT("ExReleaseResourceForThreadLite() finished\n");
840 return;
841 }
842
843 Resource->OwnerThreads[0].OwnerThread = 0;
844 Resource->ActiveCount--;
845 Resource->Flag &=(~ResourceOwnedExclusive);
846 ASSERT(Resource->ActiveCount == 0);
847 DPRINT("Resource->NumberOfExclusiveWaiters %d\n",
848 Resource->NumberOfExclusiveWaiters);
849 if (Resource->NumberOfExclusiveWaiters)
850 {
851 /* get resource to first exclusive waiter */
852 KeSetEvent(Resource->ExclusiveWaiters,
853 IO_NO_INCREMENT,
854 FALSE);
855 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
856 DPRINT("ExReleaseResourceForThreadLite() finished\n");
857 return;
858 }
859 DPRINT("Resource->NumberOfSharedWaiters %d\n",
860 Resource->NumberOfSharedWaiters);
861 if (Resource->NumberOfSharedWaiters)
862 {
863 DPRINT("Releasing semaphore\n");
864 KeReleaseSemaphore(Resource->SharedWaiters,
865 IO_NO_INCREMENT,
866 Resource->NumberOfSharedWaiters,
867 FALSE);
868 }
869 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
870 DPRINT("ExReleaseResourceForThreadLite() finished\n");
871 return;
872 }
873
874 EiRemoveSharedOwner(Resource, ResourceThreadId);
875
876 if (Resource->ActiveCount == 0)
877 {
878 if (Resource->NumberOfExclusiveWaiters)
879 {
880 /* get resource to first exclusive waiter */
881 KeSetEvent(Resource->ExclusiveWaiters,
882 IO_NO_INCREMENT,
883 FALSE);
884 }
885 }
886
887 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
888 DPRINT("ExReleaseResourceForThreadLite() finished\n");
889 }
890
891
892 /*
893 * @implemented
894 */
895 VOID
896 STDCALL
897 ExSetResourceOwnerPointer (
898 IN PERESOURCE Resource,
899 IN PVOID OwnerPointer
900 )
901 {
902 PKTHREAD CurrentThread;
903 KIRQL OldIrql;
904 POWNER_ENTRY OwnerEntry;
905
906 CurrentThread = KeGetCurrentThread();
907
908 /* Lock the resource */
909 KeAcquireSpinLock(&Resource->SpinLock, &OldIrql);
910
911 /* Check if it's exclusive */
912 if (Resource->Flag & ResourceOwnedExclusive) {
913
914 /* If it's exclusive, set the first entry no matter what */
915 Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer;
916
917 } else {
918
919 /* Check both entries and see which one matches the current thread */
920 if (Resource->OwnerThreads[0].OwnerThread == (ULONG_PTR)CurrentThread) {
921
922 Resource->OwnerThreads[0].OwnerThread = (ULONG_PTR)OwnerPointer;
923
924 } else if (Resource->OwnerThreads[1].OwnerThread == (ULONG_PTR)CurrentThread) {
925
926 Resource->OwnerThreads[1].OwnerThread = (ULONG_PTR)OwnerPointer;
927
928 } else { /* None of the entries match, so we need to do a lookup */
929
930 /* Get the first Entry */
931 OwnerEntry = Resource->OwnerTable;
932
933 /* Check if the Current Thread is in the Resource Table Entry */
934 if ((CurrentThread->ResourceIndex >= OwnerEntry->TableSize) ||
935 (OwnerEntry[CurrentThread->ResourceIndex].OwnerThread != (ULONG_PTR)CurrentThread)) {
936
937 /* Loop until we find the current thread in an entry */
938 for (;OwnerEntry->OwnerThread == (ULONG_PTR)CurrentThread;OwnerEntry++);
939
940 } else {
941
942 /* It's in the current RTE, so set it */
943 OwnerEntry = &OwnerEntry[CurrentThread->ResourceIndex];
944 }
945
946 /* Now that we went to the right entry, set the Owner Pointer */
947 OwnerEntry->OwnerThread = (ULONG_PTR)OwnerPointer;
948 }
949 }
950
951 /* Release the resource */
952 KeReleaseSpinLock(&Resource->SpinLock, OldIrql);
953 }
954
955 /* EOF */