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 #define MAX_FAST_REFS 7
26 #define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
27 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
28 EX_HANDLE_ENTRY_AUDITONCLOSE)))
29 #define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->Object) & \
30 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
31 EX_HANDLE_ENTRY_AUDITONCLOSE)))
33 /* Note: we only use a spinlock on SMP. On UP, we cli/sti intead */
35 #define ExAcquireResourceLock(l, i) { \
39 #define ExReleaseResourceLock(l, i) _enable();
41 #define ExAcquireResourceLock(l, i) KeAcquireSpinLock(l, i);
42 #define ExReleaseResourceLock(l, i) KeReleaseSpinLock(l, i);
45 #define ExAcquireRundownProtection _ExAcquireRundownProtection
46 #define ExReleaseRundownProtection _ExReleaseRundownProtection
47 #define ExInitializeRundownProtection _ExInitializeRundownProtection
48 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
49 #define ExRundownCompleted _ExRundownCompleted
50 #define ExGetPreviousMode KeGetPreviousMode
55 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40102
58 // Broken GCC with Alignment Bug. We'll do alignment ourselves at higher cost.
60 #define DEFINE_WAIT_BLOCK(x) \
64 EX_PUSH_LOCK_WAIT_BLOCK UnalignedBlock; \
66 PEX_PUSH_LOCK_WAIT_BLOCK x = (PEX_PUSH_LOCK_WAIT_BLOCK) \
67 ((ULONG_PTR)&WaitBlockBuffer.UnalignedBlock &~ 0xF);
72 // This is only for compatibility; the compiler will optimize the extra
73 // local variable (the actual pointer) away, so we don't take any perf hit
76 #define DEFINE_WAIT_BLOCK(x) \
77 EX_PUSH_LOCK_WAIT_BLOCK WaitBlockBuffer; \
78 PEX_PUSH_LOCK_WAIT_BLOCK x = &WaitBlockBuffer;
82 /* INITIALIZATION FUNCTIONS *************************************************/
100 ExpInitializePushLocks(VOID
);
104 ExRefreshTimeZoneInformation(
105 IN PLARGE_INTEGER SystemBootTime
110 ExpInitializeWorkerThreads(VOID
);
114 ExpInitLookasideLists(VOID
);
118 ExInitializeSystemLookasideList(
119 IN PGENERAL_LOOKASIDE List
,
123 IN USHORT MaximumDepth
,
124 IN PLIST_ENTRY ListHead
129 ExpInitializeCallbacks(VOID
);
137 ExpInitializeExecutive(
139 IN PLOADER_PARAMETER_BLOCK LoaderBlock
144 ExpInitializeEventImplementation(VOID
);
148 ExpInitializeEventImplementation(VOID
);
152 ExpInitializeEventPairImplementation(VOID
);
156 ExpInitializeSemaphoreImplementation(VOID
);
160 ExpInitializeMutantImplementation(VOID
);
164 ExpInitializeTimerImplementation(VOID
);
168 ExpInitializeProfileImplementation(VOID
);
172 ExpResourceInitialization(VOID
);
176 ExInitPoolLookasidePointers(VOID
);
178 /* Callback Functions ********************************************************/
182 ExInitializeCallBack(
183 IN PEX_CALLBACK Callback
186 /* Rundown Functions ********************************************************/
190 ExfInitializeRundownProtection(
191 OUT PEX_RUNDOWN_REF RunRef
196 ExfReInitializeRundownProtection(
197 OUT PEX_RUNDOWN_REF RunRef
202 ExfAcquireRundownProtection(
203 IN OUT PEX_RUNDOWN_REF RunRef
208 ExfAcquireRundownProtectionEx(
209 IN OUT PEX_RUNDOWN_REF RunRef
,
215 ExfReleaseRundownProtection(
216 IN OUT PEX_RUNDOWN_REF RunRef
221 ExfReleaseRundownProtectionEx(
222 IN OUT PEX_RUNDOWN_REF RunRef
,
229 OUT PEX_RUNDOWN_REF RunRef
234 ExfWaitForRundownProtectionRelease(
235 IN OUT PEX_RUNDOWN_REF RunRef
238 /* HANDLE TABLE FUNCTIONS ***************************************************/
240 #define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1))
241 #define EX_HANDLE_ENTRY_PROTECTFROMCLOSE (1 << 0)
242 #define EX_HANDLE_ENTRY_INHERITABLE (1 << 1)
243 #define EX_HANDLE_ENTRY_AUDITONCLOSE (1 << 2)
245 #define EX_HANDLE_TABLE_CLOSING 0x1
247 #define EX_HANDLE_ENTRY_FLAGSMASK (EX_HANDLE_ENTRY_LOCKED | \
248 EX_HANDLE_ENTRY_PROTECTFROMCLOSE | \
249 EX_HANDLE_ENTRY_INHERITABLE | \
250 EX_HANDLE_ENTRY_AUDITONCLOSE)
252 typedef VOID (NTAPI PEX_SWEEP_HANDLE_CALLBACK
)(
253 PHANDLE_TABLE_ENTRY HandleTableEntry
,
258 typedef BOOLEAN (NTAPI PEX_DUPLICATE_HANDLE_CALLBACK
)(
259 PHANDLE_TABLE HandleTable
,
260 PHANDLE_TABLE_ENTRY HandleTableEntry
,
264 typedef BOOLEAN (NTAPI PEX_CHANGE_HANDLE_CALLBACK
)(
265 PHANDLE_TABLE HandleTable
,
266 PHANDLE_TABLE_ENTRY HandleTableEntry
,
271 ExpInitializeHandleTables(VOID
);
274 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
);
277 ExDestroyHandleTable(
278 IN PHANDLE_TABLE HandleTable
283 IN PHANDLE_TABLE HandleTable
,
284 IN PEX_SWEEP_HANDLE_CALLBACK SweepHandleCallback OPTIONAL
,
285 IN PVOID Context OPTIONAL
290 IN PEPROCESS QuotaProcess OPTIONAL
,
291 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
292 IN PVOID Context OPTIONAL
,
293 IN PHANDLE_TABLE SourceHandleTable
297 ExLockHandleTableEntry(
298 IN PHANDLE_TABLE HandleTable
,
299 IN PHANDLE_TABLE_ENTRY Entry
303 ExUnlockHandleTableEntry(
304 IN PHANDLE_TABLE HandleTable
,
305 IN PHANDLE_TABLE_ENTRY Entry
310 IN PHANDLE_TABLE HandleTable
,
311 IN PHANDLE_TABLE_ENTRY Entry
316 IN PHANDLE_TABLE HandleTable
,
321 ExDestroyHandleByEntry(
322 IN PHANDLE_TABLE HandleTable
,
323 IN PHANDLE_TABLE_ENTRY Entry
,
328 ExMapHandleToPointer(
329 IN PHANDLE_TABLE HandleTable
,
335 IN PHANDLE_TABLE HandleTable
,
337 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
341 /* PSEH EXCEPTION HANDLING **************************************************/
345 ExSystemExceptionFilter(VOID
);
347 static __inline
_SEH_FILTER(_SEH_ExSystemExceptionFilter
)
349 return ExSystemExceptionFilter();
352 /* RUNDOWN *******************************************************************/
355 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
356 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
358 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z))
359 #define ExpChangePushlock(x, y, z) LongToPtr(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
360 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
364 * @name ExfAcquireRundownProtection
367 * The ExfAcquireRundownProtection routine acquires rundown protection for
368 * the specified descriptor.
371 * Pointer to a rundown reference descriptor.
373 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
375 * @remarks This is the internal macro for system use only.In case the rundown
376 * was active, then the slow-path will be called through the exported
382 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
384 ULONG_PTR Value
, NewValue
;
386 /* Get the current value and mask the active bit */
387 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
389 /* Add a reference */
390 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
392 /* Change the value */
393 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
394 if (NewValue
!= Value
)
396 /* Rundown was active, use long path */
397 return ExfAcquireRundownProtection(RunRef
);
405 * @name ExReleaseRundownProtection
408 * The ExReleaseRundownProtection routine releases rundown protection for
409 * the specified descriptor.
412 * Pointer to a rundown reference descriptor.
414 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
416 * @remarks This is the internal macro for system use only.In case the rundown
417 * was active, then the slow-path will be called through the exported
423 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
425 ULONG_PTR Value
, NewValue
;
427 /* Get the current value and mask the active bit */
428 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
430 /* Remove a reference */
431 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
433 /* Change the value */
434 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
436 /* Check if the rundown was active */
437 if (NewValue
!= Value
)
439 /* Rundown was active, use long path */
440 ExfReleaseRundownProtection(RunRef
);
445 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
450 * @name ExInitializeRundownProtection
453 * The ExInitializeRundownProtection routine initializes a rundown
454 * protection descriptor.
457 * Pointer to a rundown reference descriptor.
461 * @remarks This is the internal macro for system use only.
466 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
468 /* Set the count to zero */
473 * @name ExWaitForRundownProtectionRelease
476 * The ExWaitForRundownProtectionRelease routine waits until the specified
477 * rundown descriptor has been released.
480 * Pointer to a rundown reference descriptor.
484 * @remarks This is the internal macro for system use only. If a wait is actually
485 * necessary, then the slow path is taken through the exported function.
490 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
494 /* Set the active bit */
495 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
496 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
498 /* If the the rundown wasn't already active, then take the long path */
499 ExfWaitForRundownProtectionRelease(RunRef
);
504 * @name ExRundownCompleted
507 * The ExRundownCompleted routine completes the rundown of the specified
508 * descriptor by setting the active bit.
511 * Pointer to a rundown reference descriptor.
515 * @remarks This is the internal macro for system use only.
520 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
523 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
525 /* Mark the counter as active */
526 ExpSetRundown(&RunRef
->Count
, EX_RUNDOWN_ACTIVE
);
529 /* PUSHLOCKS *****************************************************************/
531 /* FIXME: VERIFY THESE! */
535 ExBlockPushLock(PEX_PUSH_LOCK PushLock
,
540 ExfUnblockPushLock(PEX_PUSH_LOCK PushLock
,
541 PVOID CurrentWaitBlock
);
545 ExWaitForUnblockPushLock(IN PEX_PUSH_LOCK PushLock
,
546 IN PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock
);
549 * @name ExInitializePushLock
552 * The ExInitializePushLock macro initializes a PushLock.
555 * Pointer to the pushlock which is to be initialized.
564 ExInitializePushLock(IN PULONG_PTR PushLock
)
566 /* Set the value to 0 */
571 * @name ExAcquirePushLockExclusive
574 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
577 * Pointer to the pushlock which is to be acquired.
581 * @remarks The function attempts the quickest route to acquire the lock, which is
582 * to simply set the lock bit.
583 * However, if the pushlock is already shared, the slower path is taken.
585 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
586 * This macro should usually be paired up with KeAcquireCriticalRegion.
591 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
593 /* Try acquiring the lock */
594 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
596 /* Someone changed it, use the slow path */
597 DbgPrint("%s - Contention!\n", __FUNCTION__
);
598 ExfAcquirePushLockExclusive(PushLock
);
602 ASSERT(PushLock
->Locked
);
606 * @name ExAcquirePushLockShared
609 * The ExAcquirePushLockShared macro acquires a shared PushLock.
612 * Pointer to the pushlock which is to be acquired.
616 * @remarks The function attempts the quickest route to acquire the lock, which is
617 * to simply set the lock bit and set the share count to one.
618 * However, if the pushlock is already shared, the slower path is taken.
620 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
621 * This macro should usually be paired up with KeAcquireCriticalRegion.
626 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
628 EX_PUSH_LOCK NewValue
;
630 /* Try acquiring the lock */
631 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
632 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
634 /* Someone changed it, use the slow path */
635 DbgPrint("%s - Contention!\n", __FUNCTION__
);
636 ExfAcquirePushLockShared(PushLock
);
640 ASSERT(PushLock
->Locked
);
641 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
645 * @name ExConvertPushLockSharedToExclusive
648 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
649 * pushlock to a shared pushlock.
652 * Pointer to the pushlock which is to be converted.
654 * @return FALSE if conversion failed, TRUE otherwise.
656 * @remarks The function attempts the quickest route to convert the lock, which is
657 * to simply set the lock bit and remove any other bits.
662 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
664 EX_PUSH_LOCK OldValue
;
666 /* Set the expected old value */
667 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
669 /* Try converting the lock */
670 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
673 /* Conversion failed */
678 ASSERT(PushLock
->Locked
);
683 * @name ExWaitOnPushLock
686 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
689 * Pointer to a pushlock.
693 * @remarks The function attempts to get any exclusive waiters out of their slow
694 * path by forcing an instant acquire/release operation.
696 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
701 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
703 /* Check if we're locked */
704 if (PushLock
->Locked
)
706 /* Acquire the lock */
707 ExfAcquirePushLockExclusive(PushLock
);
708 ASSERT(PushLock
->Locked
);
711 ExfReleasePushLockExclusive(PushLock
);
716 * @name ExReleasePushLockShared
719 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
722 * Pointer to a previously acquired pushlock.
726 * @remarks The function attempts the quickest route to release the lock, which is
727 * to simply decrease the share count and remove the lock bit.
728 * However, if the pushlock is being waited on then the long path is taken.
730 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
731 * This macro should usually be paired up with KeLeaveCriticalRegion.
736 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
738 EX_PUSH_LOCK OldValue
;
741 ASSERT(PushLock
->Locked
);
742 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
744 /* Try to clear the pushlock */
745 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
746 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
748 /* There are still other people waiting on it */
749 DbgPrint("%s - Contention!\n", __FUNCTION__
);
750 ExfReleasePushLockShared(PushLock
);
755 * @name ExReleasePushLockExclusive
758 * The ExReleasePushLockExclusive macro releases a previously
759 * exclusively acquired PushLock.
762 * Pointer to a previously acquired pushlock.
766 * @remarks The function attempts the quickest route to release the lock, which is
767 * to simply clear the locked bit.
768 * However, if the pushlock is being waited on, the slow path is taken
769 * in an attempt to wake up the lock.
771 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
772 * This macro should usually be paired up with KeLeaveCriticalRegion.
777 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
779 EX_PUSH_LOCK OldValue
;
782 ASSERT(PushLock
->Locked
);
783 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
== 0);
785 /* Unlock the pushlock */
786 OldValue
.Value
= InterlockedExchangeAddSizeT((PLONG
)PushLock
,
790 ASSERT(OldValue
.Locked
);
791 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
793 /* Check if anyone is waiting on it and it's not already waking*/
794 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
797 DbgPrint("%s - Contention!\n", __FUNCTION__
);
798 ExfTryToWakePushLock(PushLock
);
803 * @name ExReleasePushLock
806 * The ExReleasePushLock macro releases a previously acquired PushLock.
809 * Pointer to a previously acquired pushlock.
813 * @remarks The function attempts the quickest route to release the lock, which is
814 * to simply clear all the fields and decrease the share count if required.
815 * However, if the pushlock is being waited on then the long path is taken.
817 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
818 * This macro should usually be paired up with KeLeaveCriticalRegion.
823 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
825 EX_PUSH_LOCK OldValue
= *PushLock
;
826 EX_PUSH_LOCK NewValue
;
829 ASSERT(OldValue
.Locked
);
831 /* Check if the pushlock is shared */
832 if (OldValue
.Shared
> 1)
834 /* Decrease the share count */
835 NewValue
.Value
= OldValue
.Value
&~ EX_PUSH_LOCK_SHARE_INC
;
839 /* Clear the pushlock entirely */
843 /* Check if nobody is waiting on us and try clearing the lock here */
844 if ((OldValue
.Waiting
) ||
845 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
848 /* We have waiters, use the long path */
849 DbgPrint("%s - Contention!\n", __FUNCTION__
);
850 ExfReleasePushLock(PushLock
);
854 /* OTHER FUNCTIONS **********************************************************/
858 ExfpInterlockedExchange64(
859 LONGLONG
volatile * Destination
,
864 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
);
868 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
);
872 ExTimerRundown(VOID
);
874 #define InterlockedDecrementUL(Addend) \
875 (ULONG)InterlockedDecrement((PLONG)(Addend))
877 #define InterlockedIncrementUL(Addend) \
878 (ULONG)InterlockedIncrement((PLONG)(Addend))
880 #define InterlockedExchangeUL(Target, Value) \
881 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
883 #define InterlockedExchangeAddUL(Addend, Value) \
884 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
886 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
887 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
889 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
890 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
892 #define ExfpInterlockedExchange64UL(Target, Value) \
893 (ULONGLONG)ExfpInterlockedExchange64((PLONGLONG)(Target), (PLONGLONG)(Value))
895 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */