- Fix handle close bug. The ExDestroyHandleEntry API was only killing entries unless...
[reactos.git] / reactos / ntoskrnl / include / internal / ex.h
1 #ifndef __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
2 #define __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
3
4 /* GLOBAL VARIABLES *********************************************************/
5
6 extern TIME_ZONE_INFORMATION ExpTimeZoneInfo;
7 extern LARGE_INTEGER ExpTimeZoneBias;
8 extern ULONG ExpTimeZoneId;
9 extern ULONG ExpTickCountMultiplier;
10 extern ULONG ExpLastTimeZoneBias;
11 extern POBJECT_TYPE ExEventPairObjectType;
12 extern POBJECT_TYPE _ExEventObjectType, _ExSemaphoreObjectType;
13 extern ULONG NtBuildNumber;
14 extern ULONG NtMajorVersion;
15 extern ULONG NtMinorVersion;
16 extern FAST_MUTEX ExpEnvironmentLock;
17 extern ERESOURCE ExpFirmwareTableResource;
18 extern LIST_ENTRY ExpFirmwareTableProviderListHead;
19 extern BOOLEAN ExpIsWinPEMode;
20 ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
21 ULONG ExpUnicodeCaseTableDataOffset;
22 PVOID ExpNlsSectionPointer;
23
24 typedef struct _ETIMER
25 {
26 KTIMER KeTimer;
27 KAPC TimerApc;
28 KDPC TimerDpc;
29 LIST_ENTRY ActiveTimerListEntry;
30 KSPIN_LOCK Lock;
31 LONG Period;
32 BOOLEAN ApcAssociated;
33 BOOLEAN WakeTimer;
34 LIST_ENTRY WakeTimerListEntry;
35 } ETIMER, *PETIMER;
36
37 #define MAX_FAST_REFS 7
38
39 #define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
40 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
41 EX_HANDLE_ENTRY_AUDITONCLOSE)))
42 #define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->Object) & \
43 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
44 EX_HANDLE_ENTRY_AUDITONCLOSE)))
45
46 /* Note: we only use a spinlock on SMP. On UP, we cli/sti intead */
47 #ifndef CONFIG_SMP
48 #define ExAcquireResourceLock(l, i) { \
49 (void)i; \
50 _disable(); \
51 }
52 #define ExReleaseResourceLock(l, i) _enable();
53 #else
54 #define ExAcquireResourceLock(l, i) KeAcquireSpinLock(l, i);
55 #define ExReleaseResourceLock(l, i) KeReleaseSpinLock(l, i);
56 #endif
57
58 #define ExAcquireRundownProtection _ExAcquireRundownProtection
59 #define ExReleaseRundownProtection _ExReleaseRundownProtection
60 #define ExInitializeRundownProtection _ExInitializeRundownProtection
61 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
62 #define ExRundownCompleted _ExRundownCompleted
63 #define ExGetPreviousMode KeGetPreviousMode
64
65 /* INITIALIZATION FUNCTIONS *************************************************/
66
67 VOID
68 NTAPI
69 ExpWin32kInit(VOID);
70
71 VOID
72 NTAPI
73 ExInit2(VOID);
74
75 VOID
76 NTAPI
77 ExPhase2Init(
78 IN PVOID Context
79 );
80
81 VOID
82 NTAPI
83 ExpInitializePushLocks(VOID);
84
85 BOOLEAN
86 NTAPI
87 ExRefreshTimeZoneInformation(
88 IN PLARGE_INTEGER SystemBootTime
89 );
90
91 VOID
92 NTAPI
93 ExpInitializeWorkerThreads(VOID);
94
95 VOID
96 NTAPI
97 ExpInitLookasideLists(VOID);
98
99 VOID
100 NTAPI
101 ExInitializeSystemLookasideList(
102 IN PGENERAL_LOOKASIDE List,
103 IN POOL_TYPE Type,
104 IN ULONG Size,
105 IN ULONG Tag,
106 IN USHORT MaximumDepth,
107 IN PLIST_ENTRY ListHead
108 );
109
110 VOID
111 NTAPI
112 ExpInitializeCallbacks(VOID);
113
114 VOID
115 NTAPI
116 ExpInitUuids(VOID);
117
118 VOID
119 NTAPI
120 ExpInitializeExecutive(
121 IN ULONG Cpu,
122 IN PLOADER_PARAMETER_BLOCK LoaderBlock
123 );
124
125 VOID
126 NTAPI
127 ExpInitializeEventImplementation(VOID);
128
129 VOID
130 NTAPI
131 ExpInitializeEventImplementation(VOID);
132
133 VOID
134 NTAPI
135 ExpInitializeEventPairImplementation(VOID);
136
137 VOID
138 NTAPI
139 ExpInitializeSemaphoreImplementation(VOID);
140
141 VOID
142 NTAPI
143 ExpInitializeMutantImplementation(VOID);
144
145 VOID
146 NTAPI
147 ExpInitializeTimerImplementation(VOID);
148
149 VOID
150 NTAPI
151 ExpInitializeProfileImplementation(VOID);
152
153 VOID
154 NTAPI
155 ExpResourceInitialization(VOID);
156
157 VOID
158 NTAPI
159 ExInitPoolLookasidePointers(VOID);
160
161 /* Callback Functions ********************************************************/
162
163 VOID
164 NTAPI
165 ExInitializeCallBack(
166 IN PEX_CALLBACK Callback
167 );
168
169 /* Rundown Functions ********************************************************/
170
171 VOID
172 FASTCALL
173 ExfInitializeRundownProtection(
174 OUT PEX_RUNDOWN_REF RunRef
175 );
176
177 VOID
178 FASTCALL
179 ExfReInitializeRundownProtection(
180 OUT PEX_RUNDOWN_REF RunRef
181 );
182
183 BOOLEAN
184 FASTCALL
185 ExfAcquireRundownProtection(
186 IN OUT PEX_RUNDOWN_REF RunRef
187 );
188
189 BOOLEAN
190 FASTCALL
191 ExfAcquireRundownProtectionEx(
192 IN OUT PEX_RUNDOWN_REF RunRef,
193 IN ULONG Count
194 );
195
196 VOID
197 FASTCALL
198 ExfReleaseRundownProtection(
199 IN OUT PEX_RUNDOWN_REF RunRef
200 );
201
202 VOID
203 FASTCALL
204 ExfReleaseRundownProtectionEx(
205 IN OUT PEX_RUNDOWN_REF RunRef,
206 IN ULONG Count
207 );
208
209 VOID
210 FASTCALL
211 ExfRundownCompleted(
212 OUT PEX_RUNDOWN_REF RunRef
213 );
214
215 VOID
216 FASTCALL
217 ExfWaitForRundownProtectionRelease(
218 IN OUT PEX_RUNDOWN_REF RunRef
219 );
220
221 /* HANDLE TABLE FUNCTIONS ***************************************************/
222
223 #define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1))
224 #define EX_HANDLE_ENTRY_PROTECTFROMCLOSE (1 << 0)
225 #define EX_HANDLE_ENTRY_INHERITABLE (1 << 1)
226 #define EX_HANDLE_ENTRY_AUDITONCLOSE (1 << 2)
227
228 #define EX_HANDLE_TABLE_CLOSING 0x1
229
230 #define EX_HANDLE_ENTRY_FLAGSMASK (EX_HANDLE_ENTRY_LOCKED | \
231 EX_HANDLE_ENTRY_PROTECTFROMCLOSE | \
232 EX_HANDLE_ENTRY_INHERITABLE | \
233 EX_HANDLE_ENTRY_AUDITONCLOSE)
234
235 typedef VOID (NTAPI PEX_SWEEP_HANDLE_CALLBACK)(
236 PHANDLE_TABLE_ENTRY HandleTableEntry,
237 HANDLE Handle,
238 PVOID Context
239 );
240
241 typedef BOOLEAN (NTAPI PEX_DUPLICATE_HANDLE_CALLBACK)(
242 PHANDLE_TABLE HandleTable,
243 PHANDLE_TABLE_ENTRY HandleTableEntry,
244 PVOID Context
245 );
246
247 typedef BOOLEAN (NTAPI PEX_CHANGE_HANDLE_CALLBACK)(
248 PHANDLE_TABLE HandleTable,
249 PHANDLE_TABLE_ENTRY HandleTableEntry,
250 PVOID Context
251 );
252
253 VOID
254 ExpInitializeHandleTables(VOID);
255
256 PHANDLE_TABLE
257 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL);
258
259 VOID
260 ExDestroyHandleTable(
261 IN PHANDLE_TABLE HandleTable
262 );
263
264 VOID
265 ExSweepHandleTable(
266 IN PHANDLE_TABLE HandleTable,
267 IN PEX_SWEEP_HANDLE_CALLBACK SweepHandleCallback OPTIONAL,
268 IN PVOID Context OPTIONAL
269 );
270
271 PHANDLE_TABLE
272 ExDupHandleTable(
273 IN PEPROCESS QuotaProcess OPTIONAL,
274 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL,
275 IN PVOID Context OPTIONAL,
276 IN PHANDLE_TABLE SourceHandleTable
277 );
278
279 BOOLEAN
280 ExLockHandleTableEntry(
281 IN PHANDLE_TABLE HandleTable,
282 IN PHANDLE_TABLE_ENTRY Entry
283 );
284
285 VOID
286 ExUnlockHandleTableEntry(
287 IN PHANDLE_TABLE HandleTable,
288 IN PHANDLE_TABLE_ENTRY Entry
289 );
290
291 HANDLE
292 ExCreateHandle(
293 IN PHANDLE_TABLE HandleTable,
294 IN PHANDLE_TABLE_ENTRY Entry
295 );
296
297 BOOLEAN
298 ExDestroyHandle(
299 IN PHANDLE_TABLE HandleTable,
300 IN HANDLE Handle
301 );
302
303 VOID
304 ExDestroyHandleByEntry(
305 IN PHANDLE_TABLE HandleTable,
306 IN PHANDLE_TABLE_ENTRY Entry,
307 IN HANDLE Handle
308 );
309
310 PHANDLE_TABLE_ENTRY
311 ExMapHandleToPointer(
312 IN PHANDLE_TABLE HandleTable,
313 IN HANDLE Handle
314 );
315
316 BOOLEAN
317 ExChangeHandle(
318 IN PHANDLE_TABLE HandleTable,
319 IN HANDLE Handle,
320 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback,
321 IN PVOID Context
322 );
323
324 /* PSEH EXCEPTION HANDLING **************************************************/
325
326 LONG
327 NTAPI
328 ExSystemExceptionFilter(VOID);
329
330 static __inline _SEH_FILTER(_SEH_ExSystemExceptionFilter)
331 {
332 return ExSystemExceptionFilter();
333 }
334
335 /* RUNDOWN *******************************************************************/
336
337 #ifdef _WIN64
338 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
339 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
340 #else
341 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z))
342 #define ExpChangePushlock(x, y, z) LongToPtr(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
343 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
344 #endif
345
346 /*++
347 * @name ExfAcquireRundownProtection
348 * INTERNAL MACRO
349 *
350 * The ExfAcquireRundownProtection routine acquires rundown protection for
351 * the specified descriptor.
352 *
353 * @param RunRef
354 * Pointer to a rundown reference descriptor.
355 *
356 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
357 *
358 * @remarks This is the internal macro for system use only.In case the rundown
359 * was active, then the slow-path will be called through the exported
360 * function.
361 *
362 *--*/
363 BOOLEAN
364 FORCEINLINE
365 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
366 {
367 ULONG_PTR Value, NewValue, OldValue;
368
369 /* Get the current value and mask the active bit */
370 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
371
372 /* Add a reference */
373 NewValue = Value + EX_RUNDOWN_COUNT_INC;
374
375 /* Change the value */
376 OldValue = ExpChangeRundown(RunRef, NewValue, Value);
377 if (OldValue != Value)
378 {
379 /* Rundown was active, use long path */
380 return ExfAcquireRundownProtection(RunRef);
381 }
382
383 /* Success */
384 return TRUE;
385 }
386
387 /*++
388 * @name ExReleaseRundownProtection
389 * INTERNAL MACRO
390 *
391 * The ExReleaseRundownProtection routine releases rundown protection for
392 * the specified descriptor.
393 *
394 * @param RunRef
395 * Pointer to a rundown reference descriptor.
396 *
397 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
398 *
399 * @remarks This is the internal macro for system use only.In case the rundown
400 * was active, then the slow-path will be called through the exported
401 * function.
402 *
403 *--*/
404 VOID
405 FORCEINLINE
406 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
407 {
408 ULONG_PTR Value, NewValue, OldValue;
409
410 /* Get the current value and mask the active bit */
411 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
412
413 /* Remove a reference */
414 NewValue = Value - EX_RUNDOWN_COUNT_INC;
415
416 /* Change the value */
417 OldValue = ExpChangeRundown(RunRef, NewValue, Value);
418
419 /* Check if the rundown was active */
420 if (OldValue != Value)
421 {
422 /* Rundown was active, use long path */
423 ExfReleaseRundownProtection(RunRef);
424 }
425 else
426 {
427 /* Sanity check */
428 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
429 }
430 }
431
432 /*++
433 * @name ExInitializeRundownProtection
434 * INTERNAL MACRO
435 *
436 * The ExInitializeRundownProtection routine initializes a rundown
437 * protection descriptor.
438 *
439 * @param RunRef
440 * Pointer to a rundown reference descriptor.
441 *
442 * @return None.
443 *
444 * @remarks This is the internal macro for system use only.
445 *
446 *--*/
447 VOID
448 FORCEINLINE
449 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
450 {
451 /* Set the count to zero */
452 RunRef->Count = 0;
453 }
454
455 /*++
456 * @name ExWaitForRundownProtectionRelease
457 * INTERNAL MACRO
458 *
459 * The ExWaitForRundownProtectionRelease routine waits until the specified
460 * rundown descriptor has been released.
461 *
462 * @param RunRef
463 * Pointer to a rundown reference descriptor.
464 *
465 * @return None.
466 *
467 * @remarks This is the internal macro for system use only. If a wait is actually
468 * necessary, then the slow path is taken through the exported function.
469 *
470 *--*/
471 VOID
472 FORCEINLINE
473 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
474 {
475 ULONG_PTR Value;
476
477 /* Set the active bit */
478 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
479 if ((Value) || (Value != EX_RUNDOWN_ACTIVE))
480 {
481 /* If the the rundown wasn't already active, then take the long path */
482 ExfWaitForRundownProtectionRelease(RunRef);
483 }
484 }
485
486 /*++
487 * @name ExRundownCompleted
488 * INTERNAL MACRO
489 *
490 * The ExRundownCompleted routine completes the rundown of the specified
491 * descriptor by setting the active bit.
492 *
493 * @param RunRef
494 * Pointer to a rundown reference descriptor.
495 *
496 * @return None.
497 *
498 * @remarks This is the internal macro for system use only.
499 *
500 *--*/
501 VOID
502 FORCEINLINE
503 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
504 {
505 /* Sanity check */
506 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
507
508 /* Mark the counter as active */
509 ExpSetRundown(&RunRef->Count, EX_RUNDOWN_ACTIVE);
510 }
511
512 /* PUSHLOCKS *****************************************************************/
513
514 /*++
515 * @name ExInitializePushLock
516 * INTERNAL MACRO
517 *
518 * The ExInitializePushLock macro initializes a PushLock.
519 *
520 * @params PushLock
521 * Pointer to the pushlock which is to be initialized.
522 *
523 * @return None.
524 *
525 * @remarks None.
526 *
527 *--*/
528 VOID
529 FORCEINLINE
530 ExInitializePushLock(IN PULONG_PTR PushLock)
531 {
532 /* Set the value to 0 */
533 *PushLock = 0;
534 }
535
536 /*++
537 * @name ExAcquirePushLockExclusive
538 * INTERNAL MACRO
539 *
540 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
541 *
542 * @params PushLock
543 * Pointer to the pushlock which is to be acquired.
544 *
545 * @return None.
546 *
547 * @remarks The function attempts the quickest route to acquire the lock, which is
548 * to simply set the lock bit.
549 * However, if the pushlock is already shared, the slower path is taken.
550 *
551 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
552 * This macro should usually be paired up with KeAcquireCriticalRegion.
553 *
554 *--*/
555 VOID
556 FORCEINLINE
557 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
558 {
559 /* Try acquiring the lock */
560 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
561 {
562 /* Someone changed it, use the slow path */
563 DbgPrint("%s - Contention!\n", __FUNCTION__);
564 ExfAcquirePushLockExclusive(PushLock);
565 }
566
567 /* Sanity check */
568 ASSERT(PushLock->Locked);
569 }
570
571 /*++
572 * @name ExAcquirePushLockShared
573 * INTERNAL MACRO
574 *
575 * The ExAcquirePushLockShared macro acquires a shared PushLock.
576 *
577 * @params PushLock
578 * Pointer to the pushlock which is to be acquired.
579 *
580 * @return None.
581 *
582 * @remarks The function attempts the quickest route to acquire the lock, which is
583 * to simply set the lock bit and set the share count to one.
584 * However, if the pushlock is already shared, the slower path is taken.
585 *
586 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
587 * This macro should usually be paired up with KeAcquireCriticalRegion.
588 *
589 *--*/
590 VOID
591 FORCEINLINE
592 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
593 {
594 EX_PUSH_LOCK NewValue;
595
596 /* Try acquiring the lock */
597 NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
598 if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
599 {
600 /* Someone changed it, use the slow path */
601 DbgPrint("%s - Contention!\n", __FUNCTION__);
602 ExfAcquirePushLockShared(PushLock);
603 }
604
605 /* Sanity checks */
606 ASSERT(PushLock->Locked);
607 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
608 }
609
610 /*++
611 * @name ExConvertPushLockSharedToExclusive
612 * INTERNAL MACRO
613 *
614 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
615 * pushlock to a shared pushlock.
616 *
617 * @params PushLock
618 * Pointer to the pushlock which is to be converted.
619 *
620 * @return FALSE if conversion failed, TRUE otherwise.
621 *
622 * @remarks The function attempts the quickest route to convert the lock, which is
623 * to simply set the lock bit and remove any other bits.
624 *
625 *--*/
626 BOOLEAN
627 FORCEINLINE
628 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock)
629 {
630 EX_PUSH_LOCK OldValue;
631
632 /* Set the expected old value */
633 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
634
635 /* Try converting the lock */
636 if (ExpChangePushlock(PushLock, EX_PUSH_LOCK_LOCK, OldValue.Value) !=
637 OldValue.Ptr)
638 {
639 /* Conversion failed */
640 return FALSE;
641 }
642
643 /* Sanity check */
644 ASSERT(PushLock->Locked);
645 return TRUE;
646 }
647
648 /*++
649 * @name ExWaitOnPushLock
650 * INTERNAL MACRO
651 *
652 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
653 *
654 * @params PushLock
655 * Pointer to a pushlock.
656 *
657 * @return None.
658 *
659 * @remarks The function attempts to get any exclusive waiters out of their slow
660 * path by forcing an instant acquire/release operation.
661 *
662 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
663 *
664 *--*/
665 VOID
666 FORCEINLINE
667 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
668 {
669 /* Acquire the lock */
670 ExfAcquirePushLockExclusive(PushLock);
671 ASSERT(PushLock->Locked);
672
673 /* Release it */
674 ExfReleasePushLockExclusive(PushLock);
675 }
676
677 /*++
678 * @name ExReleasePushLockShared
679 * INTERNAL MACRO
680 *
681 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
682 *
683 * @params PushLock
684 * Pointer to a previously acquired pushlock.
685 *
686 * @return None.
687 *
688 * @remarks The function attempts the quickest route to release the lock, which is
689 * to simply decrease the share count and remove the lock bit.
690 * However, if the pushlock is being waited on then the long path is taken.
691 *
692 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
693 * This macro should usually be paired up with KeLeaveCriticalRegion.
694 *
695 *--*/
696 VOID
697 FORCEINLINE
698 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
699 {
700 EX_PUSH_LOCK OldValue;
701
702 /* Sanity checks */
703 ASSERT(PushLock->Locked);
704 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
705
706 /* Try to clear the pushlock */
707 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
708 if (ExpChangePushlock(PushLock, 0, OldValue.Ptr) != OldValue.Ptr)
709 {
710 /* There are still other people waiting on it */
711 DbgPrint("%s - Contention!\n", __FUNCTION__);
712 ExfReleasePushLockShared(PushLock);
713 }
714 }
715
716 /*++
717 * @name ExReleasePushLockExclusive
718 * INTERNAL MACRO
719 *
720 * The ExReleasePushLockExclusive macro releases a previously
721 * exclusively acquired PushLock.
722 *
723 * @params PushLock
724 * Pointer to a previously acquired pushlock.
725 *
726 * @return None.
727 *
728 * @remarks The function attempts the quickest route to release the lock, which is
729 * to simply clear the locked bit.
730 * However, if the pushlock is being waited on, the slow path is taken
731 * in an attempt to wake up the lock.
732 *
733 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
734 * This macro should usually be paired up with KeLeaveCriticalRegion.
735 *
736 *--*/
737 VOID
738 FORCEINLINE
739 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
740 {
741 EX_PUSH_LOCK OldValue;
742
743 /* Sanity checks */
744 ASSERT(PushLock->Locked);
745 ASSERT(PushLock->Waiting || PushLock->Shared == 0);
746
747 /* Unlock the pushlock */
748 OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock, -1);
749
750 /* Sanity checks */
751 ASSERT(OldValue.Locked);
752 ASSERT(OldValue.Waiting || OldValue.Shared == 0);
753
754 /* Check if anyone is waiting on it and it's not already waking*/
755 if ((OldValue.Waiting) && !(OldValue.Waking))
756 {
757 /* Wake it up */
758 DbgPrint("%s - Contention!\n", __FUNCTION__);
759 ExfTryToWakePushLock(PushLock);
760 }
761 }
762
763 /*++
764 * @name ExReleasePushLock
765 * INTERNAL MACRO
766 *
767 * The ExReleasePushLock macro releases a previously acquired PushLock.
768 *
769 * @params PushLock
770 * Pointer to a previously acquired pushlock.
771 *
772 * @return None.
773 *
774 * @remarks The function attempts the quickest route to release the lock, which is
775 * to simply clear all the fields and decrease the share count if required.
776 * However, if the pushlock is being waited on then the long path is taken.
777 *
778 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
779 * This macro should usually be paired up with KeLeaveCriticalRegion.
780 *
781 *--*/
782 VOID
783 FORCEINLINE
784 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
785 {
786 EX_PUSH_LOCK OldValue = *PushLock;
787 EX_PUSH_LOCK NewValue;
788
789 /* Sanity checks */
790 ASSERT(OldValue.Locked);
791
792 /* Check if the pushlock is shared */
793 if (OldValue.Shared > 1)
794 {
795 /* Decrease the share count */
796 NewValue.Value = OldValue.Value &~ EX_PUSH_LOCK_SHARE_INC;
797 }
798 else
799 {
800 /* Clear the pushlock entirely */
801 NewValue.Value = 0;
802 }
803
804 /* Check if nobody is waiting on us and try clearing the lock here */
805 if ((OldValue.Waiting) ||
806 (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
807 OldValue.Ptr))
808 {
809 /* We have waiters, use the long path */
810 DbgPrint("%s - Contention!\n", __FUNCTION__);
811 ExfReleasePushLock(PushLock);
812 }
813 }
814
815 /* OTHER FUNCTIONS **********************************************************/
816
817 LONGLONG
818 FASTCALL
819 ExfpInterlockedExchange64(
820 LONGLONG volatile * Destination,
821 PLONGLONG Exchange
822 );
823
824 NTSTATUS
825 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation);
826
827 NTSTATUS
828 NTAPI
829 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId);
830
831 VOID
832 NTAPI
833 ExTimerRundown(VOID);
834
835 #define InterlockedDecrementUL(Addend) \
836 (ULONG)InterlockedDecrement((PLONG)(Addend))
837
838 #define InterlockedIncrementUL(Addend) \
839 (ULONG)InterlockedIncrement((PLONG)(Addend))
840
841 #define InterlockedExchangeUL(Target, Value) \
842 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
843
844 #define InterlockedExchangeAddUL(Addend, Value) \
845 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
846
847 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
848 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
849
850 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
851 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
852
853 #define ExfpInterlockedExchange64UL(Target, Value) \
854 (ULONGLONG)ExfpInterlockedExchange64((PLONGLONG)(Target), (PLONGLONG)(Value))
855
856 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */