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