+ExGetExclusiveWaiterCount()
[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 VOID
399 STDCALL
400 ExConvertExclusiveToSharedLite (
401         PERESOURCE      Resource
402         )
403 /*
404  * FUNCTION: Converts a given resource from acquired for exclusive access
405  *           to acquire for shared access
406  * ARGUMENTS:
407  *      Resource = Points to the resource for which the access should be
408  *                 converted
409  * NOTES: Caller must be running at IRQL < DISPATCH_LEVEL
410  */
411 {
412    ULONG oldWaiters;
413    KIRQL oldIrql;
414    
415    DPRINT("ExConvertExclusiveToSharedLite(Resource %x)\n", Resource);
416    
417    KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
418    
419    oldWaiters = Resource->NumberOfSharedWaiters;
420    
421    if (!(Resource->Flag & ResourceOwnedExclusive))
422      {
423         /* Might not be what the caller expects, better bug check */
424         KeBugCheck(0);
425         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
426         return;
427      }
428    
429    //transfer infos from entry 0 to entry 1 and erase entry 0
430    Resource->OwnerThreads[1].OwnerThread=Resource->OwnerThreads[0].OwnerThread;
431    Resource->OwnerThreads[1].a.OwnerCount=Resource->OwnerThreads[0].a.OwnerCount;
432    Resource->OwnerThreads[0].OwnerThread=0;
433    Resource->OwnerThreads[0].a.OwnerCount=0;
434    /* erase exclusive flag */
435    Resource->Flag &= (~ResourceOwnedExclusive);
436    /* if no shared waiters, that's all */
437    if (!oldWaiters) 
438      {
439         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
440         return;
441      }
442 #ifndef LIBCAPTIVE
443    /* else, awake the waiters */
444    KeReleaseSemaphore(Resource->SharedWaiters,0,oldWaiters,0);
445    KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
446    DPRINT("ExConvertExclusiveToSharedLite() finished\n");
447 #else /* !LIBCAPTIVE */
448    /* no waiters allower for libcaptive */
449    KeBugCheck(0);
450 #endif /* LIBCAPTIVE */
451 }
452
453 #ifndef LIBCAPTIVE
454
455 VOID
456 STDCALL
457 ExDisableResourceBoostLite (
458         PERESOURCE      Resource
459         )
460 {
461    Resource->Flag |= ResourceDisableBoost;
462 }
463
464 #endif /* LIBCAPTIVE */
465
466 ULONG
467 STDCALL
468 ExGetExclusiveWaiterCount (
469         PERESOURCE      Resource
470         )
471 {
472   return(Resource->NumberOfExclusiveWaiters);
473 }
474
475
476 BOOLEAN
477 STDCALL
478 ExAcquireSharedStarveExclusive (
479         PERESOURCE      Resource,
480         BOOLEAN         Wait
481         )
482 /*
483  * FUNCTION: Acquires a given resource for shared access without waiting
484  *           for any pending attempts to acquire exclusive access to the
485  *           same resource
486  * ARGUMENTS:
487  *       Resource = Points to the resource to be acquired for shared access
488  *       Wait = Is set to TRUE if the caller will wait until the resource
489  *              becomes available when access can't be granted immediately
490  * RETURNS: TRUE if the requested access is granted. The routine returns
491  *          FALSE if the input Wait is FALSE and shared access can't be
492  *          granted immediately
493  */
494 {
495    KIRQL oldIrql;
496    
497    DPRINT("ExAcquireSharedStarveExclusive(Resource %x, Wait %d)\n",
498           Resource, Wait);
499    
500    KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
501    
502    /* no owner, it's easy */
503    if (Resource->ActiveCount == 0) 
504      {
505         Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread();
506         Resource->OwnerThreads[1].a.OwnerCount=1;
507         Resource->ActiveCount=1;
508         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
509         DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
510         return(TRUE);
511      }
512    
513    if ((Resource->Flag & ResourceOwnedExclusive)
514        &&  Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
515      { 
516         /* exclusive, but by same thread : it's ok */
517         Resource->OwnerThreads[0].a.OwnerCount++;
518         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
519         DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
520         return(TRUE);
521      }
522    
523    if (Resource->Flag & ResourceOwnedExclusive)
524      { 
525         /* exclusive by another thread */
526         if (!Wait) 
527           {
528              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
529              DPRINT("ExAcquireSharedStarveExclusive() = FALSE\n");
530              return(FALSE);
531           }
532         else
533           {
534              Resource->NumberOfSharedWaiters++;
535              /* wait for the semaphore */
536              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
537              KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0);
538              KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
539              Resource->NumberOfSharedWaiters--;
540           }
541      }
542    EiAddSharedOwner(Resource);
543    KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
544    DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
545    return(TRUE);
546 }
547
548 #ifndef LIBCAPTIVE
549
550 BOOLEAN
551 STDCALL
552 ExAcquireSharedWaitForExclusive (
553         PERESOURCE      Resource,
554         BOOLEAN         Wait
555         )
556 {
557   return(ExAcquireResourceSharedLite(Resource,Wait));
558 }
559
560 NTSTATUS
561 STDCALL
562 ExDeleteResource (
563         PERESOURCE      Resource
564         )
565 {
566    return(ExDeleteResourceLite(Resource));
567 }
568
569 #endif /* LIBCAPTIVE */
570
571 NTSTATUS
572 STDCALL
573 ExDeleteResourceLite (
574         PERESOURCE      Resource
575         )
576 {
577    DPRINT("ExDeleteResourceLite(Resource %x)\n", Resource);
578    if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
579    if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
580    if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
581    return(STATUS_SUCCESS);;
582 }
583
584
585 ULONG
586 STDCALL
587 ExGetSharedWaiterCount (
588         PERESOURCE      Resource
589         )
590 {
591    return(Resource->NumberOfSharedWaiters);
592 }
593
594 #ifndef LIBCAPTIVE
595
596 NTSTATUS
597 STDCALL
598 ExInitializeResource (
599         PERESOURCE      Resource
600         )
601 {
602    return(ExInitializeResourceLite(Resource));
603 }
604
605 #endif /* LIBCAPTIVE */
606
607 NTSTATUS STDCALL
608 ExInitializeResourceLite (PERESOURCE    Resource)
609 {
610    DPRINT("ExInitializeResourceLite(Resource %x)\n", Resource);
611    memset(Resource,0,sizeof(ERESOURCE));
612    Resource->NumberOfSharedWaiters = 0;
613    Resource->NumberOfExclusiveWaiters = 0;
614    KeInitializeSpinLock(&Resource->SpinLock);
615    Resource->Flag = 0;
616    Resource->ExclusiveWaiters = 
617      ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_EXCLUSIVE_LOCK);
618    KeInitializeEvent(Resource->ExclusiveWaiters,
619                      SynchronizationEvent,
620                      FALSE);
621    Resource->SharedWaiters = 
622      ExAllocatePoolWithTag(NonPagedPool ,sizeof(KSEMAPHORE), TAG_SHARED_SEM);
623    KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
624    Resource->ActiveCount = 0;
625    return(0);
626 }
627
628 BOOLEAN
629 STDCALL
630 ExIsResourceAcquiredExclusiveLite (
631         PERESOURCE      Resource
632         )
633 /*
634  * FUNCTION: Returns whether the current thread has exclusive access to
635  * a given resource
636  * ARGUMENTS:
637  *        Resource = Points to the resource to be queried
638  * RETURNS: TRUE if the caller has exclusive access to the resource,
639  *          FALSE otherwise
640  */
641 {
642    return((Resource->Flag & ResourceOwnedExclusive)
643           && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
644 }
645
646 ULONG
647 STDCALL
648 ExIsResourceAcquiredSharedLite (
649         PERESOURCE      Resource
650         )
651 /*
652  * FUNCTION: Returns whether the current thread has shared access to a given
653  *           resource
654  * ARGUMENTS:
655  *      Resource = Points to the resource to be queried
656  * RETURNS: The number of times the caller has acquired shared access to the
657  *          given resource
658  */ 
659 {
660    ULONG i;
661    if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
662      {
663         return(Resource->OwnerThreads[0].a.OwnerCount);
664      }
665    if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
666      {
667         return(Resource->OwnerThreads[1].a.OwnerCount);
668      }
669    if (!Resource->OwnerThreads[1].a.TableSize) 
670      {
671         return(0);
672      }
673    for (i=0; i<Resource->OwnerThreads[1].a.TableSize; i++)
674      {
675         if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
676           {
677              return Resource->OwnerTable[i].a.OwnerCount;
678           }
679      }
680    return(0);
681 }
682
683
684 VOID
685 STDCALL
686 ExReinitializeResourceLite (
687         PERESOURCE      Resource
688         )
689 {
690    Resource->NumberOfSharedWaiters = 0;
691    Resource->NumberOfExclusiveWaiters = 0;
692    KeInitializeSpinLock(&Resource->SpinLock);
693    Resource->Flag=0;
694    KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
695                      FALSE);
696    KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
697    Resource->ActiveCount = 0;
698    if (Resource->OwnerTable) 
699      {
700         ExFreePool(Resource->OwnerTable);
701      }
702    Resource->OwnerThreads[0].OwnerThread=0;
703    Resource->OwnerThreads[0].a.OwnerCount=0;
704    Resource->OwnerThreads[1].OwnerThread=0;
705    Resource->OwnerThreads[1].a.OwnerCount=0;
706 }
707
708
709 VOID
710 FASTCALL
711 ExReleaseResourceLite (
712         PERESOURCE      Resource
713         )
714 {
715   return(ExReleaseResourceForThreadLite(Resource,
716                                         ExGetCurrentResourceThread()));
717 }
718
719 #ifndef LIBCAPTIVE
720
721 VOID
722 STDCALL
723 ExReleaseResourceForThread (
724         PERESOURCE              Resource,
725         ERESOURCE_THREAD        ResourceThreadId
726         )
727 {
728   return(ExReleaseResourceForThreadLite(Resource,ResourceThreadId));
729 }
730
731 #endif /* LIBCAPTIVE */
732
733 VOID
734 STDCALL
735 ExReleaseResourceForThreadLite (
736         PERESOURCE              Resource,
737         ERESOURCE_THREAD        ResourceThreadId
738         )
739 /*
740  * FUNCTION: Releases a resource for the given thread
741  * ARGUMENTS:
742  *         Resource = Points to the release to release
743  *         ResourceThreadId = Identifies the thread that originally acquired
744  *                            the resource
745  * NOTES: Must be running at IRQL < DISPATCH_LEVEL
746  * BUG: We don't support starving exclusive waiters
747  */
748 {
749    KIRQL oldIrql;
750    
751    DPRINT("ExReleaseResourceForThreadLite(Resource %x, ResourceThreadId %x)\n",
752           Resource, ResourceThreadId);
753    
754    KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
755    
756    if (Resource->Flag & ResourceOwnedExclusive)
757      {
758         DPRINT("Releasing from exclusive access\n");
759         
760         Resource->OwnerThreads[0].a.OwnerCount--;
761         if (Resource->OwnerThreads[0].a.OwnerCount > 0)
762           {
763              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
764              DPRINT("ExReleaseResourceForThreadLite() finished\n");
765              return;
766           }
767         
768         Resource->OwnerThreads[0].OwnerThread = 0;
769         Resource->ActiveCount--;
770         Resource->Flag &=(~ResourceOwnedExclusive);
771         assert(Resource->ActiveCount == 0);
772         DPRINT("Resource->NumberOfExclusiveWaiters %d\n",
773                Resource->NumberOfExclusiveWaiters);
774         if (Resource->NumberOfExclusiveWaiters)
775           {
776              /* get resource to first exclusive waiter */
777              KeSetEvent(Resource->ExclusiveWaiters, 
778                         IO_NO_INCREMENT, 
779                         FALSE);
780              KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
781              DPRINT("ExReleaseResourceForThreadLite() finished\n");
782              return;
783           }
784         DPRINT("Resource->NumberOfSharedWaiters %d\n",
785                Resource->NumberOfSharedWaiters);
786         if (Resource->NumberOfSharedWaiters)
787           {
788 #ifndef LIBCAPTIVE
789              DPRINT("Releasing semaphore\n");
790              KeReleaseSemaphore(Resource->SharedWaiters,
791                                 IO_NO_INCREMENT,
792                                 Resource->NumberOfSharedWaiters,
793                                 FALSE);
794 #else /* !LIBCAPTIVE */
795              KeBugCheck(0);
796 #endif /* !LIBCAPTIVE */
797           }
798         KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
799         DPRINT("ExReleaseResourceForThreadLite() finished\n");
800         return;
801      }
802   
803    EiRemoveSharedOwner(Resource, ResourceThreadId);
804    
805    if (Resource->ActiveCount == 0)
806      {
807         if (Resource->NumberOfExclusiveWaiters)
808           { 
809              /* get resource to first exclusive waiter */
810              KeSetEvent(Resource->ExclusiveWaiters,
811                         IO_NO_INCREMENT,
812                         FALSE);
813           }
814      }
815      
816    KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
817    DPRINT("ExReleaseResourceForThreadLite() finished\n");
818 }
819
820 #ifndef LIBCAPTIVE
821
822 VOID
823 STDCALL
824 ExSetResourceOwnerPointer (
825         IN      PERESOURCE      Resource,
826         IN      PVOID           OwnerPointer
827         )
828 {
829
830 }
831
832 #endif /* LIBCAPTIVE */
833
834 /* EOF */