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