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