Lots of changes to the kernel
[reactos.git] / reactos / ntoskrnl / ex / resource.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/resource.c
5 * PURPOSE: Resource synchronization construct
6 * PROGRAMMER: Unknown
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 */
10
11
12 /*
13 * Usage of ERESOURCE members is not documented.
14 * From names of members and functionnalities, we can assume :
15 *
16 * OwnerTable = list of threads who have shared access(if more than one)
17 * ActiveCount = number of threads who have access to the resource
18 * Flag = bits : ResourceOwnedExclusive=0x80
19 * ResourceNeverExclusive=0x10
20 * ResourceReleaseByOtherThread=0x20
21 * SharedWaiters = semaphore, used to manage wait list of shared waiters.
22 * ExclusiveWaiters = event, used to manage wait list of exclusive waiters.
23 * OwnerThreads[0]= thread who have exclusive access
24 * OwnerThreads[1]= if only one thread own the resource
25 * thread who have shared access
26 * else
27 * OwnerThread=0
28 * and TableSize = number of entries in the owner table
29 * NumberOfExclusiveWaiters = number of threads waiting for exclusive access.
30 * NumberOfSharedWaiters = number of threads waiting for exclusive access.
31 *
32 */
33
34 #define ResourceOwnedExclusive 0x80
35
36 /* INCLUDES *****************************************************************/
37
38 #include <ddk/ntddk.h>
39 #include <internal/ke.h>
40 #include <stddef.h>
41 #include <internal/string.h>
42
43 //#define NDEBUG
44 #include <internal/debug.h>
45
46 /* FUNCTIONS *****************************************************************/
47
48
49 BOOLEAN ExTryToAcquireResourceExclusiveLite(PERESOURCE Resource)
50 /*
51 * FUNCTION: Attempts to require the resource for exclusive access
52 * ARGUMENTS:
53 * Resource = Points to the resource of be acquired
54 * RETURNS: TRUE if the resource was acquired for the caller
55 * NOTES: Must be acquired at IRQL < DISPATCH_LEVEL
56 */
57 {
58 return(ExAcquireResourceExclusiveLite(Resource,FALSE));
59 }
60
61 BOOLEAN ExAcquireResourceExclusive(PERESOURCE Resource, BOOLEAN Wait)
62 {
63 return(ExAcquireResourceExclusiveLite(Resource,Wait));
64 }
65
66 BOOLEAN ExAcquireResourceExclusiveLite(PERESOURCE Resource, BOOLEAN Wait)
67 /*
68 * FUNCTION: Acquires a resource exclusively for the calling thread
69 * ARGUMENTS:
70 * Resource = Points to the resource to acquire
71 * Wait = Is set to TRUE if the caller should wait to acquire the
72 * resource if it can't be acquired immediately
73 * RETURNS: TRUE if the resource was acquired,
74 * FALSE otherwise
75 * NOTES: Must be called at IRQL < DISPATCH_LEVEL
76 */
77 {
78 KIRQL oldIrql;
79
80 DPRINT("ExAcquireResourceExclusiveLite(Resource %x, Wait %d)\n",
81 Resource, Wait);
82
83 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
84
85 /* resource already locked */
86 if((Resource->Flag & ResourceOwnedExclusive)
87 && Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
88 {
89 /* it's ok : same lock for same thread */
90 Resource->OwnerThreads[0].a.OwnerCount++;
91 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
92 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
93 return(TRUE);
94 }
95
96 if (Resource->ActiveCount && !Wait)
97 {
98 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
99 DPRINT("ExAcquireResourceExclusiveLite() = FALSE\n");
100 return(FALSE);
101 }
102
103 /*
104 * This is slightly better than it looks because other exclusive
105 * threads who are waiting won't be woken up but there is a race
106 * with new threads trying to grab the resource so we must have
107 * the spinlock, still normally this loop will only be executed
108 * once
109 * NOTE: We might want to set a timeout to detect deadlock
110 * (10 minutes?)
111 */
112 while (Resource->ActiveCount)
113 {
114 Resource->NumberOfExclusiveWaiters++;
115 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
116 KeWaitForSingleObject(Resource->ExclusiveWaiters,
117 Executive,
118 KernelMode,
119 FALSE,
120 NULL);
121 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
122 Resource->NumberOfExclusiveWaiters--;
123 }
124 Resource->Flag |= ResourceOwnedExclusive;
125 Resource->ActiveCount = 1;
126 Resource->OwnerThreads[0].OwnerThread = ExGetCurrentResourceThread();
127 Resource->OwnerThreads[0].a.OwnerCount = 1;
128 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
129 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
130 return(TRUE);
131 }
132
133 static BOOLEAN EiRemoveSharedOwner(PERESOURCE Resource,
134 ERESOURCE_THREAD ResourceThreadId)
135 /*
136 * FUNCTION: Removes the current thread from the shared owners of the resource
137 * ARGUMENTS:
138 * Resource = Pointer to the resource for which the thread is to be
139 * added
140 * NOTE: Must be called with the resource spinlock held
141 */
142 {
143 ULONG i;
144
145 if (Resource->OwnerThreads[1].OwnerThread == ResourceThreadId)
146 {
147 Resource->OwnerThreads[1].a.OwnerCount--;
148 Resource->ActiveCount--;
149 if (Resource->OwnerThreads[1].a.OwnerCount == 0)
150 {
151 Resource->OwnerThreads[1].OwnerThread = 0;
152 }
153 return(TRUE);
154 }
155
156 if (Resource->OwnerThreads[1].OwnerThread)
157 {
158 /* Oh dear, the caller didn't own the resource after all */
159 return(FALSE);;
160 }
161
162 for (i=0; i<Resource->OwnerThreads[1].a.TableSize; i++)
163 {
164 if (Resource->OwnerTable[i].OwnerThread == ResourceThreadId)
165 {
166 Resource->OwnerTable[1].a.OwnerCount--;
167 Resource->ActiveCount--;
168 if (Resource->OwnerTable[1].a.OwnerCount == 0)
169 {
170 Resource->OwnerTable[i].OwnerThread = 0;
171 }
172 }
173 return(TRUE);
174 }
175 return(FALSE);
176 }
177
178 static BOOLEAN EiAddSharedOwner(PERESOURCE Resource)
179 /*
180 * FUNCTION: Adds the current thread to the shared owners of the resource
181 * ARGUMENTS:
182 * Resource = Pointer to the resource for which the thread is to be
183 * added
184 * NOTE: Must be called with the resource spinlock held
185 */
186 {
187 ERESOURCE_THREAD CurrentThread = ExGetCurrentResourceThread();
188 POWNER_ENTRY freeEntry;
189 ULONG i;
190
191 /*
192 * now, we must search if this thread has already acquired this resource
193 * then increase ownercount if found, else create new entry or reuse free
194 * entry
195 */
196 if (!Resource->OwnerThreads[1].a.TableSize)
197 {
198 /* allocate ownertable,memset to 0, initialize first entry */
199 Resource->OwnerTable = ExAllocatePool(NonPagedPool,
200 sizeof(OWNER_ENTRY)*3);
201 if (Resource->OwnerTable == NULL)
202 {
203 KeBugCheck(0);
204 return(FALSE);
205 }
206 memset(Resource->OwnerTable,sizeof(OWNER_ENTRY)*3,0);
207 memcpy(&Resource->OwnerTable[0], &Resource->OwnerThreads[1],
208 sizeof(OWNER_ENTRY));
209
210 Resource->OwnerThreads[1].OwnerThread = 0;
211 Resource->OwnerThreads[1].a.TableSize = 3;
212
213 Resource->OwnerTable[1].OwnerThread = CurrentThread;
214 Resource->OwnerTable[1].a.OwnerCount = 1;
215
216 return(TRUE);
217 }
218
219 freeEntry = NULL;
220 for (i=0; i<Resource->OwnerThreads[1].a.TableSize; i++)
221 {
222 if (Resource->OwnerTable[i].OwnerThread == CurrentThread)
223 {
224 Resource->OwnerTable[i].a.OwnerCount++;
225 return(TRUE);
226 }
227 if (Resource->OwnerTable[i].OwnerThread == 0)
228 {
229 freeEntry = &Resource->OwnerTable[i];
230 }
231 }
232
233 if (!freeEntry)
234 {
235 /* reallocate ownertable with one more entry */
236 freeEntry = ExAllocatePool(NonPagedPool,
237 sizeof(OWNER_ENTRY)*
238 (Resource->OwnerThreads[1].a.TableSize+1));
239 if (freeEntry == NULL)
240 {
241 KeBugCheck(0);
242 return(FALSE);
243 }
244 memcpy(freeEntry,Resource->OwnerTable,
245 sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].a.TableSize));
246 ExFreePool(Resource->OwnerTable);
247 Resource->OwnerTable=freeEntry;
248 freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].a.TableSize];
249 Resource->OwnerThreads[1].a.TableSize ++;
250 }
251 freeEntry->OwnerThread=ExGetCurrentResourceThread();
252 freeEntry->a.OwnerCount=1;
253 Resource->ActiveCount++;
254 return(TRUE);
255 }
256
257 BOOLEAN ExAcquireResourceSharedLite(PERESOURCE Resource, BOOLEAN Wait)
258 /*
259 * FUNCTION: Acquires the given resource for shared access by the calling
260 * thread
261 * ARGUMENTS:
262 * Resource = Points to the resource to acquire
263 * Wait = Is set to TRUE if the caller should be put into wait state
264 * until the resource can be acquired if it cannot be acquired
265 * immediately
266 * RETURNS: TRUE, if the resource is acquire
267 * FALSE otherwise
268 */
269 {
270 KIRQL oldIrql;
271
272 DPRINT("ExAcquireResourceSharedLite(Resource %x, Wait %d)\n",
273 Resource, Wait);
274
275 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
276
277 /* first, resolve trivial cases */
278 if (Resource->ActiveCount == 0)
279 {
280 /* no owner, it's easy */
281 Resource->OwnerThreads[1].OwnerThread = ExGetCurrentResourceThread();
282 Resource->OwnerThreads[1].a.OwnerCount = 1;
283 Resource->ActiveCount = 1;
284 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
285 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
286 return(TRUE);
287 }
288
289 if ((Resource->Flag & ResourceOwnedExclusive)
290 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
291 {
292 /* exclusive, but by same thread : it's ok */
293 /*
294 * NOTE: Is this correct? Seems the same as ExConvertExclusiveToShared
295 */
296 Resource->OwnerThreads[0].a.OwnerCount++;
297 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
298 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
299 return(TRUE);
300 }
301
302 if ((Resource->Flag & ResourceOwnedExclusive)
303 || Resource->NumberOfExclusiveWaiters)
304 {
305 /* exclusive by another thread , or thread waiting for exclusive */
306 if (!Wait)
307 {
308 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
309 DPRINT("ExAcquireResourceExclusiveLite() = FALSE\n");
310 return(FALSE);
311 }
312 else
313 {
314 Resource->NumberOfSharedWaiters++;
315 /* wait for the semaphore */
316 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
317 KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0);
318 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
319 Resource->NumberOfSharedWaiters--;
320 }
321 }
322
323 EiAddSharedOwner(Resource);
324 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
325 DPRINT("ExAcquireResourceExclusiveLite() = TRUE\n");
326 return(TRUE);
327 }
328
329 VOID ExConvertExclusiveToSharedLite(PERESOURCE Resource)
330 /*
331 * FUNCTION: Converts a given resource from acquired for exclusive access
332 * to acquire for shared access
333 * ARGUMENTS:
334 * Resource = Points to the resource for which the access should be
335 * converted
336 * NOTES: Caller must be running at IRQL < DISPATCH_LEVEL
337 */
338 {
339 ULONG oldWaiters;
340 KIRQL oldIrql;
341
342 DPRINT("ExConvertExclusiveToSharedLite(Resource %x)\n", Resource);
343
344 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
345
346 oldWaiters = Resource->NumberOfSharedWaiters;
347
348 if (!(Resource->Flag & ResourceOwnedExclusive))
349 {
350 /* Might not be what the caller expects, better bug check */
351 KeBugCheck(0);
352 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
353 return;
354 }
355
356 //transfer infos from entry 0 to entry 1 and erase entry 0
357 Resource->OwnerThreads[1].OwnerThread=Resource->OwnerThreads[0].OwnerThread;
358 Resource->OwnerThreads[1].a.OwnerCount=Resource->OwnerThreads[0].a.OwnerCount;
359 Resource->OwnerThreads[0].OwnerThread=0;
360 Resource->OwnerThreads[0].a.OwnerCount=0;
361 /* erase exclusive flag */
362 Resource->Flag &= (~ResourceOwnedExclusive);
363 /* if no shared waiters, that's all */
364 if (!oldWaiters)
365 {
366 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
367 return;
368 }
369 /* else, awake the waiters */
370 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
371 KeReleaseSemaphore(Resource->SharedWaiters,0,oldWaiters,0);
372 DPRINT("ExConvertExclusiveToSharedLite() finished\n");
373 }
374
375 ULONG ExGetExclusiveWaiterCount(PERESOURCE Resource)
376 {
377 return(Resource->NumberOfExclusiveWaiters);
378 }
379
380 BOOLEAN ExAcquireSharedStarveExclusive(PERESOURCE Resource, BOOLEAN Wait)
381 /*
382 * FUNCTION: Acquires a given resource for shared access without waiting
383 * for any pending attempts to acquire exclusive access to the
384 * same resource
385 * ARGUMENTS:
386 * Resource = Points to the resource to be acquired for shared access
387 * Wait = Is set to TRUE if the caller will wait until the resource
388 * becomes available when access can't be granted immediately
389 * RETURNS: TRUE if the requested access is granted. The routine returns
390 * FALSE if the input Wait is FALSE and shared access can't be
391 * granted immediately
392 */
393 {
394 KIRQL oldIrql;
395
396 DPRINT("ExAcquireSharedStarveExclusive(Resource %x, Wait %d)\n",
397 Resource, Wait);
398
399 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
400
401 /* no owner, it's easy */
402 if (Resource->ActiveCount == 0)
403 {
404 Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread();
405 Resource->OwnerThreads[1].a.OwnerCount=1;
406 Resource->ActiveCount=1;
407 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
408 DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
409 return(TRUE);
410 }
411
412 if ((Resource->Flag & ResourceOwnedExclusive)
413 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread())
414 {
415 /* exclusive, but by same thread : it's ok */
416 Resource->OwnerThreads[0].a.OwnerCount++;
417 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
418 DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
419 return(TRUE);
420 }
421
422 if (Resource->Flag & ResourceOwnedExclusive)
423 {
424 /* exclusive by another thread */
425 if (!Wait)
426 {
427 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
428 DPRINT("ExAcquireSharedStarveExclusive() = FALSE\n");
429 return(FALSE);
430 }
431 else
432 {
433 Resource->NumberOfSharedWaiters++;
434 /* wait for the semaphore */
435 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
436 KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0);
437 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
438 Resource->NumberOfSharedWaiters--;
439 }
440 }
441 EiAddSharedOwner(Resource);
442 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
443 DPRINT("ExAcquireSharedStarveExclusive() = TRUE\n");
444 return(TRUE);
445 }
446
447 BOOLEAN ExAcquireSharedWaitForExclusive(PERESOURCE Resource, BOOLEAN Wait)
448 {
449 return(ExAcquireResourceSharedLite(Resource,Wait));
450 }
451
452 NTSTATUS ExDeleteResource(PERESOURCE Resource)
453 {
454 return(ExDeleteResourceLite(Resource));
455 }
456
457 NTSTATUS ExDeleteResourceLite(PERESOURCE Resource)
458 {
459 DPRINT("ExDeleteResourceLite(Resource %x)\n", Resource);
460 if (Resource->OwnerTable) ExFreePool(Resource->OwnerTable);
461 if (Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters);
462 if (Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters);
463 return(STATUS_SUCCESS);;
464 }
465
466 ERESOURCE_THREAD ExGetCurrentResourceThread()
467 {
468 return((ERESOURCE_THREAD)PsGetCurrentThread());
469 }
470
471 ULONG ExGetSharedWaiterCount(PERESOURCE Resource)
472 {
473 return(Resource->NumberOfSharedWaiters);
474 }
475
476 NTSTATUS ExInitializeResource(PERESOURCE Resource)
477 {
478 return(ExInitializeResourceLite(Resource));
479 }
480
481 NTSTATUS ExInitializeResourceLite(PERESOURCE Resource)
482 {
483 DPRINT("ExInitializeResourceLite(Resource %x)\n", Resource);
484 memset(Resource,0,sizeof(ERESOURCE));
485 Resource->NumberOfSharedWaiters = 0;
486 Resource->NumberOfExclusiveWaiters = 0;
487 KeInitializeSpinLock(&Resource->SpinLock);
488 Resource->Flag = 0;
489 Resource->ExclusiveWaiters = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
490 KeInitializeEvent(Resource->ExclusiveWaiters,
491 SynchronizationEvent,
492 FALSE);
493 Resource->SharedWaiters = ExAllocatePool(NonPagedPool ,sizeof(KSEMAPHORE));
494 KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
495 Resource->ActiveCount = 0;
496 return(0);
497 }
498
499 BOOLEAN ExIsResourceAcquiredExclusiveLite(PERESOURCE Resource)
500 /*
501 * FUNCTION: Returns whether the current thread has exclusive access to
502 * a given resource
503 * ARGUMENTS:
504 * Resource = Points to the resource to be queried
505 * RETURNS: TRUE if the caller has exclusive access to the resource,
506 * FALSE otherwise
507 */
508 {
509 return((Resource->Flag & ResourceOwnedExclusive)
510 && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread());
511 }
512
513 ULONG ExIsResourceAcquiredSharedLite(PERESOURCE Resource)
514 /*
515 * FUNCTION: Returns whether the current thread has shared access to a given
516 * resource
517 * ARGUMENTS:
518 * Resource = Points to the resource to be queried
519 * RETURNS: The number of times the caller has acquired shared access to the
520 * given resource
521 */
522 {
523 ULONG i;
524 if (Resource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread())
525 {
526 return(Resource->OwnerThreads[0].a.OwnerCount);
527 }
528 if (Resource->OwnerThreads[1].OwnerThread == ExGetCurrentResourceThread())
529 {
530 return(Resource->OwnerThreads[1].a.OwnerCount);
531 }
532 if (!Resource->OwnerThreads[1].a.TableSize)
533 {
534 return(0);
535 }
536 for (i=0; i<Resource->OwnerThreads[1].a.TableSize; i++)
537 {
538 if (Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread())
539 {
540 return Resource->OwnerTable[i].a.OwnerCount;
541 }
542 }
543 return(0);
544 }
545
546 VOID ExReinitializeResourceLite(PERESOURCE Resource)
547 {
548 Resource->NumberOfSharedWaiters = 0;
549 Resource->NumberOfExclusiveWaiters = 0;
550 KeInitializeSpinLock(&Resource->SpinLock);
551 Resource->Flag=0;
552 KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent,
553 FALSE);
554 KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff);
555 Resource->ActiveCount = 0;
556 if (Resource->OwnerTable)
557 {
558 ExFreePool(Resource->OwnerTable);
559 }
560 Resource->OwnerThreads[0].OwnerThread=0;
561 Resource->OwnerThreads[0].a.OwnerCount=0;
562 Resource->OwnerThreads[1].OwnerThread=0;
563 Resource->OwnerThreads[1].a.OwnerCount=0;
564 }
565
566 VOID ExReleaseResourceLite(PERESOURCE Resource)
567 {
568 return(ExReleaseResourceForThreadLite(Resource,
569 ExGetCurrentResourceThread()));
570 }
571
572 VOID ExReleaseResource(PERESOURCE Resource)
573 {
574 return ExReleaseResourceForThreadLite(Resource,ExGetCurrentResourceThread());
575 }
576
577 VOID ExReleaseResourceForThread(PERESOURCE Resource,
578 ERESOURCE_THREAD ResourceThreadId)
579 {
580 return(ExReleaseResourceForThreadLite(Resource,ResourceThreadId));
581 }
582
583 VOID ExReleaseResourceForThreadLite(PERESOURCE Resource,
584 ERESOURCE_THREAD ResourceThreadId)
585 /*
586 * FUNCTION: Releases a resource for the given thread
587 * ARGUMENTS:
588 * Resource = Points to the release to release
589 * ResourceThreadId = Identifies the thread that originally acquired
590 * the resource
591 * NOTES: Must be running at IRQL < DISPATCH_LEVEL
592 * BUG: We don't support starving exclusive waiters
593 */
594 {
595 KIRQL oldIrql;
596
597 DPRINT("ExReleaseResourceForThreadLite(Resource %x, ResourceThreadId %x)\n",
598 Resource, ResourceThreadId);
599
600 KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
601
602 if (Resource->Flag & ResourceOwnedExclusive)
603 {
604 Resource->OwnerThreads[0].a.OwnerCount--;
605 if (Resource->OwnerThreads[0].a.OwnerCount > 0)
606 {
607 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
608 DPRINT("ExReleaseResourceForThreadLite() finished\n");
609 return;
610 }
611
612 Resource->OwnerThreads[0].OwnerThread = 0;
613 Resource->ActiveCount--;
614 Resource->Flag &=(~ResourceOwnedExclusive);
615 assert(Resource->ActiveCount == 0);
616 if (Resource->NumberOfExclusiveWaiters)
617 {
618 /* get resource to first exclusive waiter */
619 KeSetEvent(Resource->ExclusiveWaiters,
620 IO_NO_INCREMENT,
621 FALSE);
622 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
623 DPRINT("ExReleaseResourceForThreadLite() finished\n");
624 return;
625 }
626 if (Resource->NumberOfSharedWaiters)
627 {
628 KeReleaseSemaphore(Resource->SharedWaiters,
629 IO_NO_INCREMENT,
630 Resource->ActiveCount,
631 FALSE);
632 }
633 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
634 DPRINT("ExReleaseResourceForThreadLite() finished\n");
635 return;
636 }
637
638 EiRemoveSharedOwner(Resource, ResourceThreadId);
639
640 if (Resource->ActiveCount == 0)
641 {
642 if (Resource->NumberOfExclusiveWaiters)
643 {
644 /* get resource to first exclusive waiter */
645 KeSetEvent(Resource->ExclusiveWaiters,
646 IO_NO_INCREMENT,
647 FALSE);
648 }
649 }
650
651 KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
652 DPRINT("ExReleaseResourceForThreadLite() finished\n");
653 }
654
655