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