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