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