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 ULONG ExpAnsiCodePageDataOffset
, ExpOemCodePageDataOffset
;
21 ULONG ExpUnicodeCaseTableDataOffset
;
22 PVOID ExpNlsSectionPointer
;
24 typedef struct _ETIMER
29 LIST_ENTRY ActiveTimerListEntry
;
32 BOOLEAN ApcAssociated
;
34 LIST_ENTRY WakeTimerListEntry
;
37 #define MAX_FAST_REFS 7
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)))
46 /* Note: we only use a spinlock on SMP. On UP, we cli/sti intead */
48 #define ExAcquireResourceLock(l, i) { \
52 #define ExReleaseResourceLock(l, i) _enable();
54 #define ExAcquireResourceLock(l, i) KeAcquireSpinLock(l, i);
55 #define ExReleaseResourceLock(l, i) KeReleaseSpinLock(l, i);
58 #define ExAcquireRundownProtection _ExAcquireRundownProtection
59 #define ExReleaseRundownProtection _ExReleaseRundownProtection
60 #define ExInitializeRundownProtection _ExInitializeRundownProtection
61 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
62 #define ExRundownCompleted _ExRundownCompleted
63 #define ExGetPreviousMode KeGetPreviousMode
68 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40102
71 // Broken GCC with Alignment Bug. We'll do alignment ourselves at higher cost.
73 #define DEFINE_WAIT_BLOCK(x) \
77 EX_PUSH_LOCK_WAIT_BLOCK UnalignedBlock; \
79 PEX_PUSH_LOCK_WAIT_BLOCK x = (PEX_PUSH_LOCK_WAIT_BLOCK) \
80 ((ULONG_PTR)&WaitBlockBuffer.UnalignedBlock &~ 0xF);
85 // This is only for compatibility; the compiler will optimize the extra
86 // local variable (the actual pointer) away, so we don't take any perf hit
89 #define DEFINE_WAIT_BLOCK(x) \
90 EX_PUSH_LOCK_WAIT_BLOCK WaitBlockBuffer; \
91 PEX_PUSH_LOCK_WAIT_BLOCK x = &WaitBlockBuffer;
95 /* INITIALIZATION FUNCTIONS *************************************************/
113 ExpInitializePushLocks(VOID
);
117 ExRefreshTimeZoneInformation(
118 IN PLARGE_INTEGER SystemBootTime
123 ExpInitializeWorkerThreads(VOID
);
127 ExpInitLookasideLists(VOID
);
131 ExInitializeSystemLookasideList(
132 IN PGENERAL_LOOKASIDE List
,
136 IN USHORT MaximumDepth
,
137 IN PLIST_ENTRY ListHead
142 ExpInitializeCallbacks(VOID
);
150 ExpInitializeExecutive(
152 IN PLOADER_PARAMETER_BLOCK LoaderBlock
157 ExpInitializeEventImplementation(VOID
);
161 ExpInitializeEventImplementation(VOID
);
165 ExpInitializeEventPairImplementation(VOID
);
169 ExpInitializeSemaphoreImplementation(VOID
);
173 ExpInitializeMutantImplementation(VOID
);
177 ExpInitializeTimerImplementation(VOID
);
181 ExpInitializeProfileImplementation(VOID
);
185 ExpResourceInitialization(VOID
);
189 ExInitPoolLookasidePointers(VOID
);
191 /* Callback Functions ********************************************************/
195 ExInitializeCallBack(
196 IN PEX_CALLBACK Callback
199 /* Rundown Functions ********************************************************/
203 ExfInitializeRundownProtection(
204 OUT PEX_RUNDOWN_REF RunRef
209 ExfReInitializeRundownProtection(
210 OUT PEX_RUNDOWN_REF RunRef
215 ExfAcquireRundownProtection(
216 IN OUT PEX_RUNDOWN_REF RunRef
221 ExfAcquireRundownProtectionEx(
222 IN OUT PEX_RUNDOWN_REF RunRef
,
228 ExfReleaseRundownProtection(
229 IN OUT PEX_RUNDOWN_REF RunRef
234 ExfReleaseRundownProtectionEx(
235 IN OUT PEX_RUNDOWN_REF RunRef
,
242 OUT PEX_RUNDOWN_REF RunRef
247 ExfWaitForRundownProtectionRelease(
248 IN OUT PEX_RUNDOWN_REF RunRef
251 /* HANDLE TABLE FUNCTIONS ***************************************************/
253 #define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1))
254 #define EX_HANDLE_ENTRY_PROTECTFROMCLOSE (1 << 0)
255 #define EX_HANDLE_ENTRY_INHERITABLE (1 << 1)
256 #define EX_HANDLE_ENTRY_AUDITONCLOSE (1 << 2)
258 #define EX_HANDLE_TABLE_CLOSING 0x1
260 #define EX_HANDLE_ENTRY_FLAGSMASK (EX_HANDLE_ENTRY_LOCKED | \
261 EX_HANDLE_ENTRY_PROTECTFROMCLOSE | \
262 EX_HANDLE_ENTRY_INHERITABLE | \
263 EX_HANDLE_ENTRY_AUDITONCLOSE)
265 typedef VOID (NTAPI PEX_SWEEP_HANDLE_CALLBACK
)(
266 PHANDLE_TABLE_ENTRY HandleTableEntry
,
271 typedef BOOLEAN (NTAPI PEX_DUPLICATE_HANDLE_CALLBACK
)(
272 PHANDLE_TABLE HandleTable
,
273 PHANDLE_TABLE_ENTRY HandleTableEntry
,
277 typedef BOOLEAN (NTAPI PEX_CHANGE_HANDLE_CALLBACK
)(
278 PHANDLE_TABLE HandleTable
,
279 PHANDLE_TABLE_ENTRY HandleTableEntry
,
284 ExpInitializeHandleTables(VOID
);
287 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
);
290 ExDestroyHandleTable(
291 IN PHANDLE_TABLE HandleTable
296 IN PHANDLE_TABLE HandleTable
,
297 IN PEX_SWEEP_HANDLE_CALLBACK SweepHandleCallback OPTIONAL
,
298 IN PVOID Context OPTIONAL
303 IN PEPROCESS QuotaProcess OPTIONAL
,
304 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
305 IN PVOID Context OPTIONAL
,
306 IN PHANDLE_TABLE SourceHandleTable
310 ExLockHandleTableEntry(
311 IN PHANDLE_TABLE HandleTable
,
312 IN PHANDLE_TABLE_ENTRY Entry
316 ExUnlockHandleTableEntry(
317 IN PHANDLE_TABLE HandleTable
,
318 IN PHANDLE_TABLE_ENTRY Entry
323 IN PHANDLE_TABLE HandleTable
,
324 IN PHANDLE_TABLE_ENTRY Entry
329 IN PHANDLE_TABLE HandleTable
,
334 ExDestroyHandleByEntry(
335 IN PHANDLE_TABLE HandleTable
,
336 IN PHANDLE_TABLE_ENTRY Entry
,
341 ExMapHandleToPointer(
342 IN PHANDLE_TABLE HandleTable
,
348 IN PHANDLE_TABLE HandleTable
,
350 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
354 /* PSEH EXCEPTION HANDLING **************************************************/
358 ExSystemExceptionFilter(VOID
);
360 static __inline
_SEH_FILTER(_SEH_ExSystemExceptionFilter
)
362 return ExSystemExceptionFilter();
365 /* RUNDOWN *******************************************************************/
368 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
369 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
371 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z))
372 #define ExpChangePushlock(x, y, z) LongToPtr(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
373 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
377 * @name ExfAcquireRundownProtection
380 * The ExfAcquireRundownProtection routine acquires rundown protection for
381 * the specified descriptor.
384 * Pointer to a rundown reference descriptor.
386 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
388 * @remarks This is the internal macro for system use only.In case the rundown
389 * was active, then the slow-path will be called through the exported
395 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
397 ULONG_PTR Value
, NewValue
;
399 /* Get the current value and mask the active bit */
400 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
402 /* Add a reference */
403 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
405 /* Change the value */
406 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
407 if (NewValue
!= Value
)
409 /* Rundown was active, use long path */
410 return ExfAcquireRundownProtection(RunRef
);
418 * @name ExReleaseRundownProtection
421 * The ExReleaseRundownProtection routine releases rundown protection for
422 * the specified descriptor.
425 * Pointer to a rundown reference descriptor.
427 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
429 * @remarks This is the internal macro for system use only.In case the rundown
430 * was active, then the slow-path will be called through the exported
436 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
438 ULONG_PTR Value
, NewValue
;
440 /* Get the current value and mask the active bit */
441 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
443 /* Remove a reference */
444 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
446 /* Change the value */
447 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
449 /* Check if the rundown was active */
450 if (NewValue
!= Value
)
452 /* Rundown was active, use long path */
453 ExfReleaseRundownProtection(RunRef
);
458 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
463 * @name ExInitializeRundownProtection
466 * The ExInitializeRundownProtection routine initializes a rundown
467 * protection descriptor.
470 * Pointer to a rundown reference descriptor.
474 * @remarks This is the internal macro for system use only.
479 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
481 /* Set the count to zero */
486 * @name ExWaitForRundownProtectionRelease
489 * The ExWaitForRundownProtectionRelease routine waits until the specified
490 * rundown descriptor has been released.
493 * Pointer to a rundown reference descriptor.
497 * @remarks This is the internal macro for system use only. If a wait is actually
498 * necessary, then the slow path is taken through the exported function.
503 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
507 /* Set the active bit */
508 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
509 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
511 /* If the the rundown wasn't already active, then take the long path */
512 ExfWaitForRundownProtectionRelease(RunRef
);
517 * @name ExRundownCompleted
520 * The ExRundownCompleted routine completes the rundown of the specified
521 * descriptor by setting the active bit.
524 * Pointer to a rundown reference descriptor.
528 * @remarks This is the internal macro for system use only.
533 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
536 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
538 /* Mark the counter as active */
539 ExpSetRundown(&RunRef
->Count
, EX_RUNDOWN_ACTIVE
);
542 /* PUSHLOCKS *****************************************************************/
544 /* FIXME: VERIFY THESE! */
548 ExBlockPushLock(PEX_PUSH_LOCK PushLock
,
553 ExfUnblockPushLock(PEX_PUSH_LOCK PushLock
,
554 PVOID CurrentWaitBlock
);
558 ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock
,
559 IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock
);
562 * @name ExInitializePushLock
565 * The ExInitializePushLock macro initializes a PushLock.
568 * Pointer to the pushlock which is to be initialized.
577 ExInitializePushLock(IN PULONG_PTR PushLock
)
579 /* Set the value to 0 */
584 * @name ExAcquirePushLockExclusive
587 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
590 * Pointer to the pushlock which is to be acquired.
594 * @remarks The function attempts the quickest route to acquire the lock, which is
595 * to simply set the lock bit.
596 * However, if the pushlock is already shared, the slower path is taken.
598 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
599 * This macro should usually be paired up with KeAcquireCriticalRegion.
604 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
606 /* Try acquiring the lock */
607 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
609 /* Someone changed it, use the slow path */
610 DbgPrint("%s - Contention!\n", __FUNCTION__
);
611 ExfAcquirePushLockExclusive(PushLock
);
615 ASSERT(PushLock
->Locked
);
619 * @name ExAcquirePushLockShared
622 * The ExAcquirePushLockShared macro acquires a shared PushLock.
625 * Pointer to the pushlock which is to be acquired.
629 * @remarks The function attempts the quickest route to acquire the lock, which is
630 * to simply set the lock bit and set the share count to one.
631 * However, if the pushlock is already shared, the slower path is taken.
633 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
634 * This macro should usually be paired up with KeAcquireCriticalRegion.
639 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
641 EX_PUSH_LOCK NewValue
;
643 /* Try acquiring the lock */
644 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
645 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
647 /* Someone changed it, use the slow path */
648 DbgPrint("%s - Contention!\n", __FUNCTION__
);
649 ExfAcquirePushLockShared(PushLock
);
653 ASSERT(PushLock
->Locked
);
654 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
658 * @name ExConvertPushLockSharedToExclusive
661 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
662 * pushlock to a shared pushlock.
665 * Pointer to the pushlock which is to be converted.
667 * @return FALSE if conversion failed, TRUE otherwise.
669 * @remarks The function attempts the quickest route to convert the lock, which is
670 * to simply set the lock bit and remove any other bits.
675 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
677 EX_PUSH_LOCK OldValue
;
679 /* Set the expected old value */
680 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
682 /* Try converting the lock */
683 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
686 /* Conversion failed */
691 ASSERT(PushLock
->Locked
);
696 * @name ExWaitOnPushLock
699 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
702 * Pointer to a pushlock.
706 * @remarks The function attempts to get any exclusive waiters out of their slow
707 * path by forcing an instant acquire/release operation.
709 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
714 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
716 /* Check if we're locked */
717 if (PushLock
->Locked
)
719 /* Acquire the lock */
720 ExfAcquirePushLockExclusive(PushLock
);
721 ASSERT(PushLock
->Locked
);
724 ExfReleasePushLockExclusive(PushLock
);
729 * @name ExReleasePushLockShared
732 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
735 * Pointer to a previously acquired pushlock.
739 * @remarks The function attempts the quickest route to release the lock, which is
740 * to simply decrease the share count and remove the lock bit.
741 * However, if the pushlock is being waited on then the long path is taken.
743 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
744 * This macro should usually be paired up with KeLeaveCriticalRegion.
749 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
751 EX_PUSH_LOCK OldValue
;
754 ASSERT(PushLock
->Locked
);
755 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
757 /* Try to clear the pushlock */
758 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
759 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
761 /* There are still other people waiting on it */
762 DbgPrint("%s - Contention!\n", __FUNCTION__
);
763 ExfReleasePushLockShared(PushLock
);
768 * @name ExReleasePushLockExclusive
771 * The ExReleasePushLockExclusive macro releases a previously
772 * exclusively acquired PushLock.
775 * Pointer to a previously acquired pushlock.
779 * @remarks The function attempts the quickest route to release the lock, which is
780 * to simply clear the locked bit.
781 * However, if the pushlock is being waited on, the slow path is taken
782 * in an attempt to wake up the lock.
784 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
785 * This macro should usually be paired up with KeLeaveCriticalRegion.
790 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
792 EX_PUSH_LOCK OldValue
;
795 ASSERT(PushLock
->Locked
);
796 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
== 0);
798 /* Unlock the pushlock */
799 OldValue
.Value
= InterlockedExchangeAddSizeT((PLONG
)PushLock
,
803 ASSERT(OldValue
.Locked
);
804 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
806 /* Check if anyone is waiting on it and it's not already waking*/
807 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
810 DbgPrint("%s - Contention!\n", __FUNCTION__
);
811 ExfTryToWakePushLock(PushLock
);
816 * @name ExReleasePushLock
819 * The ExReleasePushLock macro releases a previously acquired PushLock.
822 * Pointer to a previously acquired pushlock.
826 * @remarks The function attempts the quickest route to release the lock, which is
827 * to simply clear all the fields and decrease the share count if required.
828 * However, if the pushlock is being waited on then the long path is taken.
830 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
831 * This macro should usually be paired up with KeLeaveCriticalRegion.
836 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
838 EX_PUSH_LOCK OldValue
= *PushLock
;
839 EX_PUSH_LOCK NewValue
;
842 ASSERT(OldValue
.Locked
);
844 /* Check if the pushlock is shared */
845 if (OldValue
.Shared
> 1)
847 /* Decrease the share count */
848 NewValue
.Value
= OldValue
.Value
&~ EX_PUSH_LOCK_SHARE_INC
;
852 /* Clear the pushlock entirely */
856 /* Check if nobody is waiting on us and try clearing the lock here */
857 if ((OldValue
.Waiting
) ||
858 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
861 /* We have waiters, use the long path */
862 DbgPrint("%s - Contention!\n", __FUNCTION__
);
863 ExfReleasePushLock(PushLock
);
867 /* OTHER FUNCTIONS **********************************************************/
871 ExfpInterlockedExchange64(
872 LONGLONG
volatile * Destination
,
877 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
);
881 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
);
885 ExTimerRundown(VOID
);
887 #define InterlockedDecrementUL(Addend) \
888 (ULONG)InterlockedDecrement((PLONG)(Addend))
890 #define InterlockedIncrementUL(Addend) \
891 (ULONG)InterlockedIncrement((PLONG)(Addend))
893 #define InterlockedExchangeUL(Target, Value) \
894 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
896 #define InterlockedExchangeAddUL(Addend, Value) \
897 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
899 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
900 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
902 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
903 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
905 #define ExfpInterlockedExchange64UL(Target, Value) \
906 (ULONGLONG)ExfpInterlockedExchange64((PLONGLONG)(Target), (PLONGLONG)(Value))
908 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */