1 #ifndef __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
2 #define __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
4 /* GLOBAL VARIABLES *********************************************************/
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 extern LIST_ENTRY ExpSystemResourcesList
;
21 extern ULONG ExpAnsiCodePageDataOffset
, ExpOemCodePageDataOffset
;
22 extern ULONG ExpUnicodeCaseTableDataOffset
;
23 extern PVOID ExpNlsSectionPointer
;
24 extern CHAR NtBuildLab
[];
25 extern ULONG CmNtCSDVersion
;
26 extern ULONG NtGlobalFlag
;
27 extern ULONG ExpInitializationPhase
;
28 extern ULONG ExpAltTimeZoneBias
;
29 extern LIST_ENTRY ExSystemLookasideListHead
;
31 typedef struct _EXHANDLE
40 HANDLE GenericHandleOverlay
;
43 } EXHANDLE
, *PEXHANDLE
;
45 typedef struct _ETIMER
50 LIST_ENTRY ActiveTimerListEntry
;
53 BOOLEAN ApcAssociated
;
55 LIST_ENTRY WakeTimerListEntry
;
60 PCALLBACK_OBJECT
*CallbackObject
;
64 #define MAX_FAST_REFS 7
66 #define ExAcquireRundownProtection _ExAcquireRundownProtection
67 #define ExReleaseRundownProtection _ExReleaseRundownProtection
68 #define ExInitializeRundownProtection _ExInitializeRundownProtection
69 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
70 #define ExRundownCompleted _ExRundownCompleted
71 #define ExGetPreviousMode KeGetPreviousMode
75 // Various bits tagged on the handle or handle table
77 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT 1
78 #define FREE_HANDLE_MASK -1
81 // Number of entries in each table level
83 #define LOW_LEVEL_ENTRIES (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
84 #define MID_LEVEL_ENTRIES (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
85 #define HIGH_LEVEL_ENTRIES (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
88 // Maximum index in each table level before we need another table
90 #define MAX_LOW_INDEX LOW_LEVEL_ENTRIES
91 #define MAX_MID_INDEX (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
92 #define MAX_HIGH_INDEX (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
97 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40300) || \
98 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ == 40303)
100 #define DEFINE_WAIT_BLOCK(x) \
104 EX_PUSH_LOCK_WAIT_BLOCK UnalignedBlock; \
106 PEX_PUSH_LOCK_WAIT_BLOCK x = (PEX_PUSH_LOCK_WAIT_BLOCK) \
107 ((ULONG_PTR)&WaitBlockBuffer.UnalignedBlock &~ 0xF);
112 // This is only for compatibility; the compiler will optimize the extra
113 // local variable (the actual pointer) away, so we don't take any perf hit
116 #define DEFINE_WAIT_BLOCK(x) \
117 EX_PUSH_LOCK_WAIT_BLOCK WaitBlockBuffer; \
118 PEX_PUSH_LOCK_WAIT_BLOCK x = &WaitBlockBuffer;
123 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
124 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
125 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
127 #define ExpChangeRundown(x, y, z) PtrToUlong(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
128 #define ExpChangePushlock(x, y, z) LongToPtr(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
129 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
132 /* INITIALIZATION FUNCTIONS *************************************************/
144 Phase1Initialization(
150 ExpInitializePushLocks(VOID
);
154 ExRefreshTimeZoneInformation(
155 IN PLARGE_INTEGER SystemBootTime
160 ExpInitializeWorkerThreads(VOID
);
164 ExpInitLookasideLists(VOID
);
168 ExInitializeSystemLookasideList(
169 IN PGENERAL_LOOKASIDE List
,
173 IN USHORT MaximumDepth
,
174 IN PLIST_ENTRY ListHead
179 ExpInitializeCallbacks(VOID
);
187 ExpInitializeExecutive(
189 IN PLOADER_PARAMETER_BLOCK LoaderBlock
194 ExpInitializeEventImplementation(VOID
);
198 ExpInitializeEventImplementation(VOID
);
202 ExpInitializeEventPairImplementation(VOID
);
206 ExpInitializeSemaphoreImplementation(VOID
);
210 ExpInitializeMutantImplementation(VOID
);
214 ExpInitializeTimerImplementation(VOID
);
218 ExpInitializeProfileImplementation(VOID
);
222 ExpResourceInitialization(VOID
);
226 ExInitPoolLookasidePointers(VOID
);
228 /* Callback Functions ********************************************************/
232 ExInitializeCallBack(
233 IN OUT PEX_CALLBACK Callback
236 PEX_CALLBACK_ROUTINE_BLOCK
239 IN PEX_CALLBACK_FUNCTION Function
,
246 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
251 ExCompareExchangeCallBack (
252 IN OUT PEX_CALLBACK CallBack
,
253 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock
,
254 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
257 PEX_CALLBACK_ROUTINE_BLOCK
259 ExReferenceCallBackBlock(
260 IN OUT PEX_CALLBACK CallBack
265 ExDereferenceCallBackBlock(
266 IN OUT PEX_CALLBACK CallBack
,
267 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
270 PEX_CALLBACK_FUNCTION
272 ExGetCallBackBlockRoutine(
273 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
278 ExGetCallBackBlockContext(
279 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
285 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
288 /* Rundown Functions ********************************************************/
292 ExfInitializeRundownProtection(
293 OUT PEX_RUNDOWN_REF RunRef
298 ExfReInitializeRundownProtection(
299 OUT PEX_RUNDOWN_REF RunRef
304 ExfAcquireRundownProtection(
305 IN OUT PEX_RUNDOWN_REF RunRef
310 ExfAcquireRundownProtectionEx(
311 IN OUT PEX_RUNDOWN_REF RunRef
,
317 ExfReleaseRundownProtection(
318 IN OUT PEX_RUNDOWN_REF RunRef
323 ExfReleaseRundownProtectionEx(
324 IN OUT PEX_RUNDOWN_REF RunRef
,
331 OUT PEX_RUNDOWN_REF RunRef
336 ExfWaitForRundownProtectionRelease(
337 IN OUT PEX_RUNDOWN_REF RunRef
340 /* HANDLE TABLE FUNCTIONS ***************************************************/
343 (NTAPI
*PEX_SWEEP_HANDLE_CALLBACK
)(
344 PHANDLE_TABLE_ENTRY HandleTableEntry
,
350 (NTAPI
*PEX_DUPLICATE_HANDLE_CALLBACK
)(
351 IN PEPROCESS Process
,
352 IN PHANDLE_TABLE HandleTable
,
353 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
354 IN PHANDLE_TABLE_ENTRY NewEntry
358 (NTAPI
*PEX_CHANGE_HANDLE_CALLBACK
)(
359 PHANDLE_TABLE_ENTRY HandleTableEntry
,
365 ExpInitializeHandleTables(
372 IN PEPROCESS Process OPTIONAL
377 ExUnlockHandleTableEntry(
378 IN PHANDLE_TABLE HandleTable
,
379 IN PHANDLE_TABLE_ENTRY HandleTableEntry
385 IN PHANDLE_TABLE HandleTable
,
386 IN PHANDLE_TABLE_ENTRY HandleTableEntry
391 ExDestroyHandleTable(
392 IN PHANDLE_TABLE HandleTable
,
393 IN PVOID DestroyHandleProcedure OPTIONAL
399 IN PHANDLE_TABLE HandleTable
,
401 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
406 ExMapHandleToPointer(
407 IN PHANDLE_TABLE HandleTable
,
414 IN PEPROCESS Process
,
415 IN PHANDLE_TABLE HandleTable
,
416 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
423 IN PHANDLE_TABLE HandleTable
,
425 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
432 IN PHANDLE_TABLE HandleTable
,
433 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
437 /* PSEH EXCEPTION HANDLING **************************************************/
441 ExSystemExceptionFilter(VOID
);
443 /* CALLBACKS *****************************************************************/
447 ExDoCallBack(IN OUT PEX_CALLBACK Callback
,
452 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock
;
453 PEX_CALLBACK_FUNCTION Function
;
455 /* Reference the block */
456 CallbackBlock
= ExReferenceCallBackBlock(Callback
);
459 /* Get the function */
460 Function
= ExGetCallBackBlockRoutine(CallbackBlock
);
462 /* Do the callback */
463 Function(Context
, Argument1
, Argument2
);
465 /* Now dereference it */
466 ExDereferenceCallBackBlock(Callback
, CallbackBlock
);
470 /* FAST REFS ******************************************************************/
474 ExGetObjectFastReference(IN EX_FAST_REF FastRef
)
476 /* Return the unbiased pointer */
477 return (PVOID
)(FastRef
.Value
& ~MAX_FAST_REFS
);
482 ExGetCountFastReference(IN EX_FAST_REF FastRef
)
484 /* Return the reference count */
485 return FastRef
.RefCnt
;
490 ExInitializeFastReference(OUT PEX_FAST_REF FastRef
,
491 IN OPTIONAL PVOID Object
)
494 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
496 /* Check if an object is being set */
499 /* Clear the field */
500 FastRef
->Object
= NULL
;
504 /* Otherwise, we assume the object was referenced and is ready */
505 FastRef
->Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
511 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef
)
513 EX_FAST_REF OldValue
, NewValue
;
515 /* Start reference loop */
518 /* Get the current reference count */
522 /* Increase the reference count */
523 NewValue
.Value
= OldValue
.Value
- 1;
524 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
527 if (NewValue
.Object
!= OldValue
.Object
) continue;
534 /* Return the old value */
540 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef
,
543 EX_FAST_REF OldValue
, NewValue
;
546 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
548 /* Start update loop */
551 /* Get the current reference count */
554 /* Check if the current count is too high or if the pointer changed */
555 if (((OldValue
.RefCnt
+ MAX_FAST_REFS
) > MAX_FAST_REFS
) ||
556 ((OldValue
.Value
&~ MAX_FAST_REFS
) != (ULONG_PTR
)Object
))
562 /* Update the reference count */
563 NewValue
.Value
= OldValue
.Value
+ MAX_FAST_REFS
;
564 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
567 if (NewValue
.Object
!= OldValue
.Object
) continue;
579 ExReleaseFastReference(IN PEX_FAST_REF FastRef
,
582 EX_FAST_REF OldValue
, NewValue
;
585 ASSERT(Object
!= NULL
);
586 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
588 /* Start reference loop */
591 /* Get the current reference count */
594 /* Check if we're full if if the pointer changed */
595 if ((OldValue
.Value
^ (ULONG_PTR
)Object
) >= MAX_FAST_REFS
) return FALSE
;
597 /* Decrease the reference count */
598 NewValue
.Value
= OldValue
.Value
+ 1;
599 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
602 if (NewValue
.Object
!= OldValue
.Object
) continue;
614 ExSwapFastReference(IN PEX_FAST_REF FastRef
,
617 EX_FAST_REF NewValue
, OldValue
;
620 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
622 /* Check if an object is being set */
625 /* Clear the field */
626 NewValue
.Object
= NULL
;
630 /* Otherwise, we assume the object was referenced and is ready */
631 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
634 /* Update the object */
635 OldValue
.Object
= InterlockedExchangePointer(&FastRef
->Object
, NewValue
.Object
);
641 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef
,
645 EX_FAST_REF OldValue
, NewValue
;
647 /* Sanity check and start swap loop */
648 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
651 /* Get the current value */
654 /* Make sure there's enough references to swap */
655 if (!((OldValue
.Value
^ (ULONG_PTR
)OldObject
) <= MAX_FAST_REFS
)) break;
657 /* Check if we have an object to swap */
660 /* Set up the value with maximum fast references */
661 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
665 /* Write the object address itself (which is empty) */
666 NewValue
.Value
= (ULONG_PTR
)Object
;
669 /* Do the actual compare exchange */
670 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
673 if (NewValue
.Object
!= OldValue
.Object
) continue;
679 /* Return the old value */
683 /* RUNDOWN *******************************************************************/
686 * @name ExfAcquireRundownProtection
689 * The ExfAcquireRundownProtection routine acquires rundown protection for
690 * the specified descriptor.
693 * Pointer to a rundown reference descriptor.
695 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
697 * @remarks This is the internal macro for system use only.In case the rundown
698 * was active, then the slow-path will be called through the exported
704 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
706 ULONG_PTR Value
, NewValue
;
708 /* Get the current value and mask the active bit */
709 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
711 /* Add a reference */
712 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
714 /* Change the value */
715 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
716 if (NewValue
!= Value
)
718 /* Rundown was active, use long path */
719 return ExfAcquireRundownProtection(RunRef
);
727 * @name ExReleaseRundownProtection
730 * The ExReleaseRundownProtection routine releases rundown protection for
731 * the specified descriptor.
734 * Pointer to a rundown reference descriptor.
736 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
738 * @remarks This is the internal macro for system use only.In case the rundown
739 * was active, then the slow-path will be called through the exported
745 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
747 ULONG_PTR Value
, NewValue
;
749 /* Get the current value and mask the active bit */
750 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
752 /* Remove a reference */
753 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
755 /* Change the value */
756 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
758 /* Check if the rundown was active */
759 if (NewValue
!= Value
)
761 /* Rundown was active, use long path */
762 ExfReleaseRundownProtection(RunRef
);
767 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
772 * @name ExInitializeRundownProtection
775 * The ExInitializeRundownProtection routine initializes a rundown
776 * protection descriptor.
779 * Pointer to a rundown reference descriptor.
783 * @remarks This is the internal macro for system use only.
788 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
790 /* Set the count to zero */
795 * @name ExWaitForRundownProtectionRelease
798 * The ExWaitForRundownProtectionRelease routine waits until the specified
799 * rundown descriptor has been released.
802 * Pointer to a rundown reference descriptor.
806 * @remarks This is the internal macro for system use only. If a wait is actually
807 * necessary, then the slow path is taken through the exported function.
812 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
816 /* Set the active bit */
817 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
818 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
820 /* If the the rundown wasn't already active, then take the long path */
821 ExfWaitForRundownProtectionRelease(RunRef
);
826 * @name ExRundownCompleted
829 * The ExRundownCompleted routine completes the rundown of the specified
830 * descriptor by setting the active bit.
833 * Pointer to a rundown reference descriptor.
837 * @remarks This is the internal macro for system use only.
842 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
845 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
847 /* Mark the counter as active */
848 ExpSetRundown(&RunRef
->Count
, EX_RUNDOWN_ACTIVE
);
851 /* PUSHLOCKS *****************************************************************/
853 /* FIXME: VERIFY THESE! */
858 IN PEX_PUSH_LOCK PushLock
,
865 IN PEX_PUSH_LOCK PushLock
,
866 IN PVOID CurrentWaitBlock
871 ExWaitForUnblockPushLock(
872 IN PEX_PUSH_LOCK PushLock
,
877 * @name ExInitializePushLock
880 * The ExInitializePushLock macro initializes a PushLock.
883 * Pointer to the pushlock which is to be initialized.
892 ExInitializePushLock(IN PULONG_PTR PushLock
)
894 /* Set the value to 0 */
899 * @name ExAcquirePushLockExclusive
902 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
905 * Pointer to the pushlock which is to be acquired.
909 * @remarks The function attempts the quickest route to acquire the lock, which is
910 * to simply set the lock bit.
911 * However, if the pushlock is already shared, the slower path is taken.
913 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
914 * This macro should usually be paired up with KeAcquireCriticalRegion.
919 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
921 /* Try acquiring the lock */
922 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
924 /* Someone changed it, use the slow path */
925 ExfAcquirePushLockExclusive(PushLock
);
929 ASSERT(PushLock
->Locked
);
933 * @name ExTryToAcquirePushLockExclusive
936 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
939 * Pointer to the pushlock which is to be acquired.
943 * @remarks The function attempts the quickest route to acquire the lock, which is
944 * to simply set the lock bit.
945 * However, if the pushlock is already shared, the slower path is taken.
947 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
948 * This macro should usually be paired up with KeAcquireCriticalRegion.
953 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
955 /* Try acquiring the lock */
956 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
963 ASSERT (PushLock
->Locked
);
968 * @name ExAcquirePushLockShared
971 * The ExAcquirePushLockShared macro acquires a shared PushLock.
974 * Pointer to the pushlock which is to be acquired.
978 * @remarks The function attempts the quickest route to acquire the lock, which is
979 * to simply set the lock bit and set the share count to one.
980 * However, if the pushlock is already shared, the slower path is taken.
982 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
983 * This macro should usually be paired up with KeAcquireCriticalRegion.
988 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
990 EX_PUSH_LOCK NewValue
;
992 /* Try acquiring the lock */
993 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
994 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
996 /* Someone changed it, use the slow path */
997 ExfAcquirePushLockShared(PushLock
);
1001 ASSERT(PushLock
->Locked
);
1002 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
1006 * @name ExConvertPushLockSharedToExclusive
1009 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
1010 * pushlock to a shared pushlock.
1013 * Pointer to the pushlock which is to be converted.
1015 * @return FALSE if conversion failed, TRUE otherwise.
1017 * @remarks The function attempts the quickest route to convert the lock, which is
1018 * to simply set the lock bit and remove any other bits.
1023 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
1025 EX_PUSH_LOCK OldValue
;
1027 /* Set the expected old value */
1028 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1030 /* Try converting the lock */
1031 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
1034 /* Conversion failed */
1039 ASSERT(PushLock
->Locked
);
1044 * @name ExWaitOnPushLock
1047 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1050 * Pointer to a pushlock.
1054 * @remarks The function attempts to get any exclusive waiters out of their slow
1055 * path by forcing an instant acquire/release operation.
1057 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1062 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
1064 /* Check if we're locked */
1065 if (PushLock
->Locked
)
1067 /* Acquire the lock */
1068 ExfAcquirePushLockExclusive(PushLock
);
1069 ASSERT(PushLock
->Locked
);
1072 ExfReleasePushLockExclusive(PushLock
);
1077 * @name ExReleasePushLockShared
1080 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
1083 * Pointer to a previously acquired pushlock.
1087 * @remarks The function attempts the quickest route to release the lock, which is
1088 * to simply decrease the share count and remove the lock bit.
1089 * However, if the pushlock is being waited on then the long path is taken.
1091 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1092 * This macro should usually be paired up with KeLeaveCriticalRegion.
1097 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
1099 EX_PUSH_LOCK OldValue
;
1102 ASSERT(PushLock
->Locked
);
1103 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
1105 /* Try to clear the pushlock */
1106 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1107 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
1109 /* There are still other people waiting on it */
1110 ExfReleasePushLockShared(PushLock
);
1115 * @name ExReleasePushLockExclusive
1118 * The ExReleasePushLockExclusive macro releases a previously
1119 * exclusively acquired PushLock.
1122 * Pointer to a previously acquired pushlock.
1126 * @remarks The function attempts the quickest route to release the lock, which is
1127 * to simply clear the locked bit.
1128 * However, if the pushlock is being waited on, the slow path is taken
1129 * in an attempt to wake up the lock.
1131 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1132 * This macro should usually be paired up with KeLeaveCriticalRegion.
1137 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1139 EX_PUSH_LOCK OldValue
;
1142 ASSERT(PushLock
->Locked
);
1143 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
== 0);
1145 /* Unlock the pushlock */
1146 OldValue
.Value
= InterlockedExchangeAddSizeT((PSIZE_T
)PushLock
,
1147 -(SIZE_T
)EX_PUSH_LOCK_LOCK
);
1150 ASSERT(OldValue
.Locked
);
1151 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
1153 /* Check if anyone is waiting on it and it's not already waking*/
1154 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
1157 ExfTryToWakePushLock(PushLock
);
1162 * @name ExReleasePushLock
1165 * The ExReleasePushLock macro releases a previously acquired PushLock.
1168 * Pointer to a previously acquired pushlock.
1172 * @remarks The function attempts the quickest route to release the lock, which is
1173 * to simply clear all the fields and decrease the share count if required.
1174 * However, if the pushlock is being waited on then the long path is taken.
1176 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1177 * This macro should usually be paired up with KeLeaveCriticalRegion.
1182 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
1184 EX_PUSH_LOCK OldValue
= *PushLock
;
1185 EX_PUSH_LOCK NewValue
;
1188 ASSERT(OldValue
.Locked
);
1190 /* Check if the pushlock is shared */
1191 if (OldValue
.Shared
> 1)
1193 /* Decrease the share count */
1194 NewValue
.Value
= OldValue
.Value
- EX_PUSH_LOCK_SHARE_INC
;
1198 /* Clear the pushlock entirely */
1202 /* Check if nobody is waiting on us and try clearing the lock here */
1203 if ((OldValue
.Waiting
) ||
1204 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
1207 /* We have waiters, use the long path */
1208 ExfReleasePushLock(PushLock
);
1212 /* FAST MUTEX INLINES *********************************************************/
1216 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex
)
1218 PKTHREAD Thread
= KeGetCurrentThread();
1221 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1222 (Thread
->CombinedApcDisable
!= 0) ||
1223 (Thread
->Teb
== NULL
) ||
1224 (Thread
->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1225 ASSERT(FastMutex
->Owner
!= Thread
);
1227 /* Decrease the count */
1228 if (InterlockedDecrement(&FastMutex
->Count
))
1230 /* Someone is still holding it, use slow path */
1231 KiAcquireFastMutex(FastMutex
);
1235 FastMutex
->Owner
= Thread
;
1240 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1242 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1243 (KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
1244 (KeGetCurrentThread()->Teb
== NULL
) ||
1245 (KeGetCurrentThread()->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1246 ASSERT(FastMutex
->Owner
== KeGetCurrentThread());
1248 /* Erase the owner */
1249 FastMutex
->Owner
= NULL
;
1251 /* Increase the count */
1252 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1254 /* Someone was waiting for it, signal the waiter */
1255 KeSetEventBoostPriority(&FastMutex
->Gate
, NULL
);
1261 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
1264 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1266 /* Raise IRQL to APC */
1267 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1269 /* Decrease the count */
1270 if (InterlockedDecrement(&FastMutex
->Count
))
1272 /* Someone is still holding it, use slow path */
1273 KiAcquireFastMutex(FastMutex
);
1276 /* Set the owner and IRQL */
1277 FastMutex
->Owner
= KeGetCurrentThread();
1278 FastMutex
->OldIrql
= OldIrql
;
1283 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1286 ASSERT(KeGetCurrentIrql() == APC_LEVEL
);
1288 /* Erase the owner */
1289 FastMutex
->Owner
= NULL
;
1290 OldIrql
= (KIRQL
)FastMutex
->OldIrql
;
1292 /* Increase the count */
1293 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1295 /* Someone was waiting for it, signal the waiter */
1296 KeSetEventBoostPriority(&FastMutex
->Gate
, NULL
);
1299 /* Lower IRQL back */
1300 KeLowerIrql(OldIrql
);
1305 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1308 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1310 /* Raise to APC_LEVEL */
1311 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1313 /* Check if we can quickly acquire it */
1314 if (InterlockedCompareExchange(&FastMutex
->Count
, 0, 1) == 1)
1316 /* We have, set us as owners */
1317 FastMutex
->Owner
= KeGetCurrentThread();
1318 FastMutex
->OldIrql
= OldIrql
;
1323 /* Acquire attempt failed */
1324 KeLowerIrql(OldIrql
);
1332 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1334 /* Enter the Critical Region */
1335 KeEnterCriticalRegion();
1337 /* Acquire the mutex unsafely */
1338 _ExAcquireFastMutexUnsafe(FastMutex
);
1343 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex
)
1345 /* Release the mutex unsafely */
1346 _ExReleaseFastMutexUnsafe(FastMutex
);
1348 /* Leave the critical region */
1349 KeLeaveCriticalRegion();
1352 /* OTHER FUNCTIONS **********************************************************/
1356 ExTryToAcquireResourceExclusiveLite(
1357 IN PERESOURCE Resource
1361 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
);
1365 ExAcquireTimeRefreshLock(BOOLEAN Wait
);
1369 ExReleaseTimeRefreshLock(VOID
);
1373 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime
,
1374 IN ULONG MaxSepInSeconds
);
1378 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
);
1382 ExTimerRundown(VOID
);
1387 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1393 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1396 #define InterlockedDecrementUL(Addend) \
1397 (ULONG)InterlockedDecrement((PLONG)(Addend))
1399 #define InterlockedIncrementUL(Addend) \
1400 (ULONG)InterlockedIncrement((PLONG)(Addend))
1402 #define InterlockedExchangeUL(Target, Value) \
1403 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1405 #define InterlockedExchangeAddUL(Addend, Value) \
1406 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1408 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1409 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1411 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1412 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
1414 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */