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