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