Use free Windows DDK and compile with latest MinGW releases.
[reactos.git] / reactos / ntoskrnl / ex / resource.c
1 /* $Id: resource.c,v 1.20 2002/09/07 15:12:50 chorns Exp $
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 <ntoskrnl.h>
42
43 #define NDEBUG
44 #include <internal/debug.h>
45
46
47 /* GLOBALS *******************************************************************/
48
49 #define TAG_OWNER_TABLE TAG('R', 'O', 'W', 'N')
50 #define TAG_EXCLUSIVE_LOCK TAG('E', 'R', 'E', 'L')
51 #define TAG_SHARED_SEM TAG('E', 'R', 'S', 'S')
52
53 /* FUNCTIONS *****************************************************************/
54
55 BOOLEAN
56 STDCALL
57 ExAcquireResourceExclusiveLite (
58 PERESOURCE Resource,
59 BOOLEAN Wait
60 )
61 /*
62 * FUNCTION: Acquires a resource exclusively for the calling thread
63 * ARGUMENTS:
64 * Resource = Points to the resource to acquire
65 * Wait = Is set to TRUE if the caller should wait to acquire the
66 * resource if it can't be acquired immediately
67 * RETURNS: TRUE if the resource was acquired,
68 * FALSE otherwise
69 * NOTES: Must be called at IRQL < DISPATCH_LEVEL
70 */
71 {
72 KIRQL oldIrql;
73
74 DPRINT("ExAcquireResourceExclusiveLite(Resource %x, Wait %d)\n",
75 Resource, Wait);
76
77 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
78
79 /* resource already locked */
80 if((Resource->Flag & ResourceOwnedExclusive)
81 && Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
82 {
83 /* it's ok : same lock for same thread */
84 Resource->OwnerThreads[0].OwnerCount++;
85 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
86 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
87 return(TRUE);
88 }
89
90 if (Resource->ActiveCount && !Wait)
91 {
92 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
93 DPRINT("ExAcquireResourceExclusiveLite() = FALSE\n");
94 return(FALSE);
95 }
96
97 /*
98 * This is slightly better than it looks because other exclusive
99 * threads who are waiting won't be woken up but there is a race
100 * with new threads trying to grab the resource so we must have
101 * the spinlock, still normally this loop will only be executed
102 * once
103 * NOTE: We might want to set a timeout to detect deadlock
104 * (10 minutes?)
105 */
106 while (Resource->ActiveCount)
107 {
108 Resource->NumberOfExclusiveWaiters++;
109 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
110 KeWaitForSingleObject(Resource->ExclusiveWaiters,
111 Executive,
112 KernelMode,
113 FALSE,
114 NULL);
115 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
116 Resource->NumberOfExclusiveWaiters--;
117 }
118 Resource->Flag |= ResourceOwnedExclusive;
119 Resource->ActiveCount = 1;
120 Resource->OwnerThreads[0].OwnerThread = ExGetCurrentResourceThread();
121 Resource->OwnerThreads[0].OwnerCount = 1;
122 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
123 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
124 return(TRUE);
125 }
126
127 BOOLEAN
128 STDCALL
129 ExTryToAcquireResourceExclusiveLite (
130 PERESOURCE Resource
131 )
132 /*
133 * FUNCTION: Attempts to require the resource for exclusive access
134 * ARGUMENTS:
135 * Resource = Points to the resource of be acquired
136 * RETURNS: TRUE if the resource was acquired for the caller
137 * NOTES: Must be acquired at IRQL < DISPATCH_LEVEL
138 */
139 {
140 return(ExAcquireResourceExclusiveLite(Resource,FALSE));
141 }
142
143 #undef ExAcquireResourceExclusive
144
145 BOOLEAN
146 STDCALL
147 ExAcquireResourceExclusive (
148 PERESOURCE Resource,
149 BOOLEAN Wait
150 )
151 {
152 return(ExAcquireResourceExclusiveLite(Resource,Wait));
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].OwnerCount--;
170 if (Resource->OwnerThreads[1].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].TableSize; i++)
185 {
186 if (Resource->OwnerTable[i].OwnerThread == ResourceThreadId)
187 {
188 Resource->OwnerTable[i].OwnerCount--;
189 if (Resource->OwnerTable[i].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].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].TableSize = 3;
254
255 Resource->OwnerTable[1].OwnerThread = CurrentThread;
256 Resource->OwnerTable[1].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].TableSize);
266
267 freeEntry = NULL;
268 for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
269 {
270 if (Resource->OwnerTable[i].OwnerThread == CurrentThread)
271 {
272 DPRINT("Thread already owns resource\n");
273 Resource->OwnerTable[i].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].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].TableSize));
302 ExFreePool(Resource->OwnerTable);
303 Resource->OwnerTable=freeEntry;
304 freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].TableSize];
305 Resource->OwnerThreads[1].TableSize++;
306 }
307 DPRINT("Creating entry\n");
308 freeEntry->OwnerThread=ExGetCurrentResourceThread();
309 freeEntry->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].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].OwnerCount=Resource->OwnerThreads[0].OwnerCount;
428 Resource->OwnerThreads[0].OwnerThread=0;
429 Resource->OwnerThreads[0].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].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].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 #undef ExDeleteResource
545
546 NTSTATUS
547 STDCALL
548 ExDeleteResource (
549 PERESOURCE Resource
550 )
551 {
552 return(ExDeleteResourceLite(Resource));
553 }
554
555 NTSTATUS
556 STDCALL
557 ExDeleteResourceLite (
558 PERESOURCE Resource
559 )
560 {
561 DPRINT("ExDeleteResourceLite(Resource %x)\n", Resource);
562 if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
563 if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
564 if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
565 return(STATUS_SUCCESS);;
566 }
567
568 ULONG
569 STDCALL
570 ExGetSharedWaiterCount (
571 PERESOURCE Resource
572 )
573 {
574 return(Resource->NumberOfSharedWaiters);
575 }
576
577 #undef ExInitializeResource
578
579 NTSTATUS
580 STDCALL
581 ExInitializeResource (
582 PERESOURCE Resource
583 )
584 {
585 return(ExInitializeResourceLite(Resource));
586 }
587
588 NTSTATUS STDCALL
589 ExInitializeResourceLite (PERESOURCE Resource)
590 {
591 DPRINT("ExInitializeResourceLite(Resource %x)\n", Resource);
592 memset(Resource,0,sizeof(ERESOURCE));
593 Resource->NumberOfSharedWaiters = 0;
594 Resource->NumberOfExclusiveWaiters = 0;
595 KeInitializeSpinLock(&Resource->SpinLock);
596 Resource->Flag = 0;
597 Resource->ExclusiveWaiters =
598 ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_EXCLUSIVE_LOCK);
599 KeInitializeEvent(Resource->ExclusiveWaiters,
600 SynchronizationEvent,
601 FALSE);
602 Resource->SharedWaiters =
603 ExAllocatePoolWithTag(NonPagedPool ,sizeof(KSEMAPHORE), TAG_SHARED_SEM);
604 KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
605 Resource->ActiveCount = 0;
606 return(0);
607 }
608
609 BOOLEAN
610 STDCALL
611 ExIsResourceAcquiredExclusiveLite (
612 PERESOURCE Resource
613 )
614 /*
615 * FUNCTION: Returns whether the current thread has exclusive access to
616 * a given resource
617 * ARGUMENTS:
618 * Resource = Points to the resource to be queried
619 * RETURNS: TRUE if the caller has exclusive access to the resource,
620 * FALSE otherwise
621 */
622 {
623 return((Resource->Flag & ResourceOwnedExclusive)
624 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
625 }
626
627 USHORT
628 STDCALL
629 ExIsResourceAcquiredSharedLite (
630 PERESOURCE Resource
631 )
632 /*
633 * FUNCTION: Returns whether the current thread has shared access to a given
634 * resource
635 * ARGUMENTS:
636 * Resource = Points to the resource to be queried
637 * RETURNS: The number of times the caller has acquired shared access to the
638 * given resource
639 */
640 {
641 ULONG i;
642 if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
643 {
644 return(Resource->OwnerThreads[0].OwnerCount);
645 }
646 if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
647 {
648 return(Resource->OwnerThreads[1].OwnerCount);
649 }
650 if (!Resource->OwnerThreads[1].TableSize)
651 {
652 return(0);
653 }
654 for (i=0; i<Resource->OwnerThreads[1].TableSize; i++)
655 {
656 if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
657 {
658 return Resource->OwnerTable[i].OwnerCount;
659 }
660 }
661 return(0);
662 }
663
664 VOID
665 STDCALL
666 ExReinitializeResourceLite (
667 PERESOURCE Resource
668 )
669 {
670 Resource->NumberOfSharedWaiters = 0;
671 Resource->NumberOfExclusiveWaiters = 0;
672 KeInitializeSpinLock(&Resource->SpinLock);
673 Resource->Flag=0;
674 KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
675 FALSE);
676 KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
677 Resource->ActiveCount = 0;
678 if (Resource->OwnerTable)
679 {
680 ExFreePool(Resource->OwnerTable);
681 }
682 Resource->OwnerThreads[0].OwnerThread=0;
683 Resource->OwnerThreads[0].OwnerCount=0;
684 Resource->OwnerThreads[1].OwnerThread=0;
685 Resource->OwnerThreads[1].OwnerCount=0;
686 }
687
688 VOID
689 FASTCALL
690 ExReleaseResourceLite (
691 PERESOURCE Resource
692 )
693 {
694 ExReleaseResourceForThreadLite(Resource,
695 ExGetCurrentResourceThread());
696 }
697
698 #undef ExReleaseResourceForThread
699
700 VOID
701 STDCALL
702 ExReleaseResourceForThread (
703 PERESOURCE Resource,
704 ERESOURCE_THREAD ResourceThreadId
705 )
706 {
707 ExReleaseResourceForThreadLite(Resource,ResourceThreadId);
708 }
709
710 VOID
711 STDCALL
712 ExReleaseResourceForThreadLite (
713 PERESOURCE Resource,
714 ERESOURCE_THREAD ResourceThreadId
715 )
716 /*
717 * FUNCTION: Releases a resource for the given thread
718 * ARGUMENTS:
719 * Resource = Points to the release to release
720 * ResourceThreadId = Identifies the thread that originally acquired
721 * the resource
722 * NOTES: Must be running at IRQL < DISPATCH_LEVEL
723 * BUG: We don't support starving exclusive waiters
724 */
725 {
726 KIRQL oldIrql;
727
728 DPRINT("ExReleaseResourceForThreadLite(Resource %x, ResourceThreadId %x)\n",
729 Resource, ResourceThreadId);
730
731 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
732
733 if (Resource->Flag & ResourceOwnedExclusive)
734 {
735 DPRINT("Releasing from exclusive access\n");
736
737 Resource->OwnerThreads[0].OwnerCount--;
738 if (Resource->OwnerThreads[0].OwnerCount > 0)
739 {
740 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
741 DPRINT("ExReleaseResourceForThreadLite() finished\n");
742 return;
743 }
744
745 Resource->OwnerThreads[0].OwnerThread = 0;
746 Resource->ActiveCount--;
747 Resource->Flag &=(~ResourceOwnedExclusive);
748 assert(Resource->ActiveCount == 0);
749 DPRINT("Resource->NumberOfExclusiveWaiters %d\n",
750 Resource->NumberOfExclusiveWaiters);
751 if (Resource->NumberOfExclusiveWaiters)
752 {
753 /* get resource to first exclusive waiter */
754 KeSetEvent(Resource->ExclusiveWaiters,
755 IO_NO_INCREMENT,
756 FALSE);
757 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
758 DPRINT("ExReleaseResourceForThreadLite() finished\n");
759 return;
760 }
761 DPRINT("Resource->NumberOfSharedWaiters %d\n",
762 Resource->NumberOfSharedWaiters);
763 if (Resource->NumberOfSharedWaiters)
764 {
765 DPRINT("Releasing semaphore\n");
766 KeReleaseSemaphore(Resource->SharedWaiters,
767 IO_NO_INCREMENT,
768 Resource->NumberOfSharedWaiters,
769 FALSE);
770 }
771 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
772 DPRINT("ExReleaseResourceForThreadLite() finished\n");
773 return;
774 }
775
776 EiRemoveSharedOwner(Resource, ResourceThreadId);
777
778 if (Resource->ActiveCount == 0)
779 {
780 if (Resource->NumberOfExclusiveWaiters)
781 {
782 /* get resource to first exclusive waiter */
783 KeSetEvent(Resource->ExclusiveWaiters,
784 IO_NO_INCREMENT,
785 FALSE);
786 }
787 }
788
789 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
790 DPRINT("ExReleaseResourceForThreadLite() finished\n");
791 }
792
793
794 VOID
795 STDCALL
796 ExSetResourceOwnerPointer (
797 IN PERESOURCE Resource,
798 IN PVOID OwnerPointer
799 )
800 {
801
802 }
803
804 /* EOF */