+ExAcquireSharedStarveExclusive()
[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 #ifndef LIBCAPTIVE
319
320 BOOLEAN
321 STDCALL
322 ExAcquireResourceSharedLite (
323         PERESOURCE      Resource,
324         BOOLEAN         Wait
325         )
326 /*
327  * FUNCTION: Acquires the given resource for shared access by the calling
328  *           thread
329  * ARGUMENTS:
330  *       Resource = Points to the resource to acquire
331  *       Wait = Is set to TRUE if the caller should be put into wait state
332  *              until the resource can be acquired if it cannot be acquired
333  *              immediately
334  * RETURNS: TRUE, if the resource is acquire
335  *          FALSE otherwise
336  */
337 {
338    KIRQL oldIrql;
339    
340    DPRINT("ExAcquireResourceSharedLite(Resource %x, Wait %d)\n",
341           Resource, Wait);
342    
343    KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
344    
345    /* first, resolve trivial cases */
346    if (Resource->ActiveCount == 0) 
347      {
348         EiAddSharedOwner(Resource);
349         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
350         DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
351         return(TRUE);
352      }
353    
354    if ((Resource->Flag & ResourceOwnedExclusive)
355        && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
356      {
357         /* exclusive, but by same thread : it's ok */
358         /* 
359          * NOTE: Is this correct? Seems the same as ExConvertExclusiveToShared 
360          */
361         Resource->OwnerThreads[0].a.OwnerCount++;
362         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
363         DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
364         return(TRUE);
365      }
366    
367    if ((Resource->Flag & ResourceOwnedExclusive)
368        || Resource->NumberOfExclusiveWaiters)
369      { 
370         /* exclusive by another thread , or thread waiting for exclusive */
371         if (!Wait) 
372           {
373              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
374              DPRINT("ExAcquireResourceSharedLite() = FALSE\n");
375              return(FALSE);
376           }
377         else
378           {
379             Resource->NumberOfSharedWaiters++;
380             do
381             {
382                /* wait for the semaphore */
383                KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
384                KeWaitForSingleObject(Resource->SharedWaiters,0, KernelMode, FALSE, NULL);
385                KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
386                /* the spin lock was released we must check again */
387             }
388             while ((Resource->Flag & ResourceOwnedExclusive)
389                 || Resource->NumberOfExclusiveWaiters);
390             Resource->NumberOfSharedWaiters--;
391           }
392      }
393    
394    EiAddSharedOwner(Resource);
395    KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
396    DPRINT("ExAcquireResourceSharedLite() = TRUE\n");
397    return(TRUE);
398 }
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 NTSTATUS
564 STDCALL
565 ExDeleteResourceLite (
566         PERESOURCE      Resource
567         )
568 {
569    DPRINT("ExDeleteResourceLite(Resource %x)\n", Resource);
570    if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
571    if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
572    if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
573    return(STATUS_SUCCESS);;
574 }
575
576 ULONG
577 STDCALL
578 ExGetSharedWaiterCount (
579         PERESOURCE      Resource
580         )
581 {
582    return(Resource->NumberOfSharedWaiters);
583 }
584
585 NTSTATUS
586 STDCALL
587 ExInitializeResource (
588         PERESOURCE      Resource
589         )
590 {
591    return(ExInitializeResourceLite(Resource));
592 }
593
594 #endif /* LIBCAPTIVE */
595
596 NTSTATUS STDCALL
597 ExInitializeResourceLite (PERESOURCE    Resource)
598 {
599    DPRINT("ExInitializeResourceLite(Resource %x)\n", Resource);
600    memset(Resource,0,sizeof(ERESOURCE));
601    Resource->NumberOfSharedWaiters = 0;
602    Resource->NumberOfExclusiveWaiters = 0;
603    KeInitializeSpinLock(&Resource->SpinLock);
604    Resource->Flag = 0;
605    Resource->ExclusiveWaiters = 
606      ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_EXCLUSIVE_LOCK);
607    KeInitializeEvent(Resource->ExclusiveWaiters,
608                      SynchronizationEvent,
609                      FALSE);
610    Resource->SharedWaiters = 
611      ExAllocatePoolWithTag(NonPagedPool ,sizeof(KSEMAPHORE), TAG_SHARED_SEM);
612    KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
613    Resource->ActiveCount = 0;
614    return(0);
615 }
616
617 #ifndef LIBCAPTIVE
618
619 BOOLEAN
620 STDCALL
621 ExIsResourceAcquiredExclusiveLite (
622         PERESOURCE      Resource
623         )
624 /*
625  * FUNCTION: Returns whether the current thread has exclusive access to
626  * a given resource
627  * ARGUMENTS:
628  *        Resource = Points to the resource to be queried
629  * RETURNS: TRUE if the caller has exclusive access to the resource,
630  *          FALSE otherwise
631  */
632 {
633    return((Resource->Flag & ResourceOwnedExclusive)
634           && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
635 }
636
637 ULONG
638 STDCALL
639 ExIsResourceAcquiredSharedLite (
640         PERESOURCE      Resource
641         )
642 /*
643  * FUNCTION: Returns whether the current thread has shared access to a given
644  *           resource
645  * ARGUMENTS:
646  *      Resource = Points to the resource to be queried
647  * RETURNS: The number of times the caller has acquired shared access to the
648  *          given resource
649  */ 
650 {
651    ULONG i;
652    if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
653      {
654         return(Resource->OwnerThreads[0].a.OwnerCount);
655      }
656    if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
657      {
658         return(Resource->OwnerThreads[1].a.OwnerCount);
659      }
660    if (!Resource->OwnerThreads[1].a.TableSize) 
661      {
662         return(0);
663      }
664    for (i=0; i<Resource->OwnerThreads[1].a.TableSize; i++)
665      {
666         if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
667           {
668              return Resource->OwnerTable[i].a.OwnerCount;
669           }
670      }
671    return(0);
672 }
673
674 VOID
675 STDCALL
676 ExReinitializeResourceLite (
677         PERESOURCE      Resource
678         )
679 {
680    Resource->NumberOfSharedWaiters = 0;
681    Resource->NumberOfExclusiveWaiters = 0;
682    KeInitializeSpinLock(&Resource->SpinLock);
683    Resource->Flag=0;
684    KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
685                      FALSE);
686    KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
687    Resource->ActiveCount = 0;
688    if (Resource->OwnerTable) 
689      {
690         ExFreePool(Resource->OwnerTable);
691      }
692    Resource->OwnerThreads[0].OwnerThread=0;
693    Resource->OwnerThreads[0].a.OwnerCount=0;
694    Resource->OwnerThreads[1].OwnerThread=0;
695    Resource->OwnerThreads[1].a.OwnerCount=0;
696 }
697
698 #endif /* LIBCAPTIVE */
699
700 VOID
701 FASTCALL
702 ExReleaseResourceLite (
703         PERESOURCE      Resource
704         )
705 {
706   return(ExReleaseResourceForThreadLite(Resource,
707                                         ExGetCurrentResourceThread()));
708 }
709
710 #ifndef LIBCAPTIVE
711
712 VOID
713 STDCALL
714 ExReleaseResourceForThread (
715         PERESOURCE              Resource,
716         ERESOURCE_THREAD        ResourceThreadId
717         )
718 {
719   return(ExReleaseResourceForThreadLite(Resource,ResourceThreadId));
720 }
721
722 #endif /* LIBCAPTIVE */
723
724 VOID
725 STDCALL
726 ExReleaseResourceForThreadLite (
727         PERESOURCE              Resource,
728         ERESOURCE_THREAD        ResourceThreadId
729         )
730 /*
731  * FUNCTION: Releases a resource for the given thread
732  * ARGUMENTS:
733  *         Resource = Points to the release to release
734  *         ResourceThreadId = Identifies the thread that originally acquired
735  *                            the resource
736  * NOTES: Must be running at IRQL < DISPATCH_LEVEL
737  * BUG: We don't support starving exclusive waiters
738  */
739 {
740    KIRQL oldIrql;
741    
742    DPRINT("ExReleaseResourceForThreadLite(Resource %x, ResourceThreadId %x)\n",
743           Resource, ResourceThreadId);
744    
745    KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
746    
747    if (Resource->Flag & ResourceOwnedExclusive)
748      {
749         DPRINT("Releasing from exclusive access\n");
750         
751         Resource->OwnerThreads[0].a.OwnerCount--;
752         if (Resource->OwnerThreads[0].a.OwnerCount > 0)
753           {
754              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
755              DPRINT("ExReleaseResourceForThreadLite() finished\n");
756              return;
757           }
758         
759         Resource->OwnerThreads[0].OwnerThread = 0;
760         Resource->ActiveCount--;
761         Resource->Flag &=(~ResourceOwnedExclusive);
762         assert(Resource->ActiveCount == 0);
763         DPRINT("Resource->NumberOfExclusiveWaiters %d\n",
764                Resource->NumberOfExclusiveWaiters);
765         if (Resource->NumberOfExclusiveWaiters)
766           {
767              /* get resource to first exclusive waiter */
768              KeSetEvent(Resource->ExclusiveWaiters, 
769                         IO_NO_INCREMENT, 
770                         FALSE);
771              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
772              DPRINT("ExReleaseResourceForThreadLite() finished\n");
773              return;
774           }
775         DPRINT("Resource->NumberOfSharedWaiters %d\n",
776                Resource->NumberOfSharedWaiters);
777         if (Resource->NumberOfSharedWaiters)
778           {
779 #ifndef LIBCAPTIVE
780              DPRINT("Releasing semaphore\n");
781              KeReleaseSemaphore(Resource->SharedWaiters,
782                                 IO_NO_INCREMENT,
783                                 Resource->NumberOfSharedWaiters,
784                                 FALSE);
785 #else /* !LIBCAPTIVE */
786              KeBugCheck(0);
787 #endif /* !LIBCAPTIVE */
788           }
789         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
790         DPRINT("ExReleaseResourceForThreadLite() finished\n");
791         return;
792      }
793   
794    EiRemoveSharedOwner(Resource, ResourceThreadId);
795    
796    if (Resource->ActiveCount == 0)
797      {
798         if (Resource->NumberOfExclusiveWaiters)
799           { 
800              /* get resource to first exclusive waiter */
801              KeSetEvent(Resource->ExclusiveWaiters,
802                         IO_NO_INCREMENT,
803                         FALSE);
804           }
805      }
806      
807    KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
808    DPRINT("ExReleaseResourceForThreadLite() finished\n");
809 }
810
811 #ifndef LIBCAPTIVE
812
813 VOID
814 STDCALL
815 ExSetResourceOwnerPointer (
816         IN      PERESOURCE      Resource,
817         IN      PVOID           OwnerPointer
818         )
819 {
820
821 }
822
823 #endif /* LIBCAPTIVE */
824
825 /* EOF */