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