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 POBJECT_TYPE ExEventPairObjectType
;
10 extern ULONG NtBuildNumber
;
11 extern ULONG NtMajorVersion
;
12 extern ULONG NtMinorVersion
;
14 #define MAX_FAST_REFS 7
16 #define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
17 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
18 EX_HANDLE_ENTRY_AUDITONCLOSE)))
19 #define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->Object) & \
20 ~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
21 EX_HANDLE_ENTRY_AUDITONCLOSE)))
23 /* Note: we only use a spinlock on SMP. On UP, we cli/sti intead */
25 #define ExAcquireResourceLock(l, i) { \
27 Ke386DisableInterrupts(); \
29 #define ExReleaseResourceLock(l, i) Ke386EnableInterrupts();
31 #define ExAcquireResourceLock(l, i) KeAcquireSpinLock(l, i);
32 #define ExReleaseResourceLock(l, i) KeReleaseSpinLock(l, i);
35 #define ExAcquireRundownProtection _ExAcquireRundownProtection
36 #define ExReleaseRundownProtection _ExReleaseRundownProtection
37 #define ExInitializeRundownProtection _ExInitializeRundownProtection
38 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
39 #define ExRundownCompleted _ExRundownCompleted
41 /* INITIALIZATION FUNCTIONS *************************************************/
59 ExpInitTimeZoneInfo(VOID
);
63 ExpInitializeWorkerThreads(VOID
);
67 ExpInitLookasideLists(VOID
);
71 ExpInitializeCallbacks(VOID
);
79 ExpInitializeExecutive(
81 IN PLOADER_PARAMETER_BLOCK LoaderBlock
86 ExpInitializeEventImplementation(VOID
);
90 ExpInitializeEventImplementation(VOID
);
94 ExpInitializeEventPairImplementation(VOID
);
98 ExpInitializeSemaphoreImplementation(VOID
);
102 ExpInitializeMutantImplementation(VOID
);
106 ExpInitializeTimerImplementation(VOID
);
110 ExpInitializeProfileImplementation(VOID
);
114 ExpResourceInitialization(VOID
);
118 ExInitPoolLookasidePointers(VOID
);
120 /* Rundown Functions ********************************************************/
124 ExfInitializeRundownProtection(
125 OUT PEX_RUNDOWN_REF RunRef
130 ExfReInitializeRundownProtection(
131 OUT PEX_RUNDOWN_REF RunRef
136 ExfAcquireRundownProtection(
137 IN OUT PEX_RUNDOWN_REF RunRef
142 ExfAcquireRundownProtectionEx(
143 IN OUT PEX_RUNDOWN_REF RunRef
,
149 ExfReleaseRundownProtection(
150 IN OUT PEX_RUNDOWN_REF RunRef
155 ExfReleaseRundownProtectionEx(
156 IN OUT PEX_RUNDOWN_REF RunRef
,
163 OUT PEX_RUNDOWN_REF RunRef
168 ExfWaitForRundownProtectionRelease(
169 IN OUT PEX_RUNDOWN_REF RunRef
172 /* HANDLE TABLE FUNCTIONS ***************************************************/
174 #define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1))
175 #define EX_HANDLE_ENTRY_PROTECTFROMCLOSE (1 << 0)
176 #define EX_HANDLE_ENTRY_INHERITABLE (1 << 1)
177 #define EX_HANDLE_ENTRY_AUDITONCLOSE (1 << 2)
179 #define EX_HANDLE_TABLE_CLOSING 0x1
181 #define EX_HANDLE_ENTRY_FLAGSMASK (EX_HANDLE_ENTRY_LOCKED | \
182 EX_HANDLE_ENTRY_PROTECTFROMCLOSE | \
183 EX_HANDLE_ENTRY_INHERITABLE | \
184 EX_HANDLE_ENTRY_AUDITONCLOSE)
186 typedef VOID (NTAPI PEX_SWEEP_HANDLE_CALLBACK
)(
187 PHANDLE_TABLE_ENTRY HandleTableEntry
,
192 typedef BOOLEAN (NTAPI PEX_DUPLICATE_HANDLE_CALLBACK
)(
193 PHANDLE_TABLE HandleTable
,
194 PHANDLE_TABLE_ENTRY HandleTableEntry
,
198 typedef BOOLEAN (NTAPI PEX_CHANGE_HANDLE_CALLBACK
)(
199 PHANDLE_TABLE HandleTable
,
200 PHANDLE_TABLE_ENTRY HandleTableEntry
,
205 ExpInitializeHandleTables(VOID
);
208 ExCreateHandleTable(IN PEPROCESS QuotaProcess OPTIONAL
);
211 ExDestroyHandleTable(
212 IN PHANDLE_TABLE HandleTable
217 IN PHANDLE_TABLE HandleTable
,
218 IN PEX_SWEEP_HANDLE_CALLBACK SweepHandleCallback OPTIONAL
,
219 IN PVOID Context OPTIONAL
224 IN PEPROCESS QuotaProcess OPTIONAL
,
225 IN PEX_DUPLICATE_HANDLE_CALLBACK DuplicateHandleCallback OPTIONAL
,
226 IN PVOID Context OPTIONAL
,
227 IN PHANDLE_TABLE SourceHandleTable
231 ExLockHandleTableEntry(
232 IN PHANDLE_TABLE HandleTable
,
233 IN PHANDLE_TABLE_ENTRY Entry
237 ExUnlockHandleTableEntry(
238 IN PHANDLE_TABLE HandleTable
,
239 IN PHANDLE_TABLE_ENTRY Entry
244 IN PHANDLE_TABLE HandleTable
,
245 IN PHANDLE_TABLE_ENTRY Entry
250 IN PHANDLE_TABLE HandleTable
,
255 ExDestroyHandleByEntry(
256 IN PHANDLE_TABLE HandleTable
,
257 IN PHANDLE_TABLE_ENTRY Entry
,
262 ExMapHandleToPointer(
263 IN PHANDLE_TABLE HandleTable
,
269 IN PHANDLE_TABLE HandleTable
,
271 IN PEX_CHANGE_HANDLE_CALLBACK ChangeHandleCallback
,
275 /* PSEH EXCEPTION HANDLING **************************************************/
279 ExSystemExceptionFilter(VOID
);
281 static __inline
_SEH_FILTER(_SEH_ExSystemExceptionFilter
)
283 return ExSystemExceptionFilter();
286 /* RUNDOWN *******************************************************************/
289 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
290 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
292 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z))
293 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
297 * @name ExfAcquireRundownProtection
300 * The ExfAcquireRundownProtection routine acquires rundown protection for
301 * the specified descriptor.
304 * Pointer to a rundown reference descriptor.
306 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
308 * @remarks This is the internal macro for system use only.In case the rundown
309 * was active, then the slow-path will be called through the exported
315 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
317 ULONG_PTR Value
, NewValue
, OldValue
;
319 /* Get the current value and mask the active bit */
320 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
322 /* Add a reference */
323 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
325 /* Change the value */
326 OldValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
327 if (OldValue
!= Value
)
329 /* Rundown was active, use long path */
330 return ExfAcquireRundownProtection(RunRef
);
338 * @name ExReleaseRundownProtection
341 * The ExReleaseRundownProtection routine releases rundown protection for
342 * the specified descriptor.
345 * Pointer to a rundown reference descriptor.
347 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
349 * @remarks This is the internal macro for system use only.In case the rundown
350 * was active, then the slow-path will be called through the exported
356 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
358 ULONG_PTR Value
, NewValue
, OldValue
;
360 /* Get the current value and mask the active bit */
361 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
363 /* Remove a reference */
364 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
366 /* Change the value */
367 OldValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
369 /* Check if the rundown was active */
370 if (OldValue
!= Value
)
372 /* Rundown was active, use long path */
373 ExfReleaseRundownProtection(RunRef
);
378 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
383 * @name ExInitializeRundownProtection
386 * The ExInitializeRundownProtection routine initializes a rundown
387 * protection descriptor.
390 * Pointer to a rundown reference descriptor.
394 * @remarks This is the internal macro for system use only.
399 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
401 /* Set the count to zero */
406 * @name ExWaitForRundownProtectionRelease
409 * The ExWaitForRundownProtectionRelease routine waits until the specified
410 * rundown descriptor has been released.
413 * Pointer to a rundown reference descriptor.
417 * @remarks This is the internal macro for system use only. If a wait is actually
418 * necessary, then the slow path is taken through the exported function.
423 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
427 /* Set the active bit */
428 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
429 if ((Value
) || (Value
!= EX_RUNDOWN_ACTIVE
))
431 /* If the the rundown wasn't already active, then take the long path */
432 ExfWaitForRundownProtectionRelease(RunRef
);
437 * @name ExRundownCompleted
440 * The ExRundownCompleted routine completes the rundown of the specified
441 * descriptor by setting the active bit.
444 * Pointer to a rundown reference descriptor.
448 * @remarks This is the internal macro for system use only.
453 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
456 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
458 /* Mark the counter as active */
459 ExpSetRundown(&RunRef
->Count
, EX_RUNDOWN_ACTIVE
);
462 /* PUSHLOCKS *****************************************************************/
465 * @name ExAcquirePushLockExclusive
468 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
471 * Pointer to the pushlock which is to be acquired.
475 * @remarks The function attempts the quickest route to acquire the lock, which is
476 * to simply set the lock bit.
477 * However, if the pushlock is already shared, the slower path is taken.
479 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
480 * This macro should usually be paired up with KeAcquireCriticalRegion.
485 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
487 /* Try acquiring the lock */
488 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
490 /* Someone changed it, use the slow path */
491 DbgPrint("%s - Contention!\n", __FUNCTION__
);
492 ExfAcquirePushLockExclusive(PushLock
);
496 ASSERT(PushLock
->Locked
);
500 * @name ExAcquirePushLockShared
503 * The ExAcquirePushLockShared macro acquires a shared PushLock.
506 * Pointer to the pushlock which is to be acquired.
510 * @remarks The function attempts the quickest route to acquire the lock, which is
511 * to simply set the lock bit and set the share count to one.
512 * However, if the pushlock is already shared, the slower path is taken.
514 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
515 * This macro should usually be paired up with KeAcquireCriticalRegion.
520 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
522 EX_PUSH_LOCK NewValue
;
524 /* Try acquiring the lock */
525 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
526 if (InterlockedCompareExchangePointer(PushLock
, NewValue
.Ptr
, 0))
528 /* Someone changed it, use the slow path */
529 DbgPrint("%s - Contention!\n", __FUNCTION__
);
530 ExfAcquirePushLockShared(PushLock
);
534 ASSERT(PushLock
->Locked
);
535 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
539 * @name ExWaitOnPushLock
542 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
545 * Pointer to a pushlock.
549 * @remarks The function attempts to get any exclusive waiters out of their slow
550 * path by forcing an instant acquire/release operation.
552 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
557 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
559 /* Acquire the lock */
560 ExfAcquirePushLockExclusive(PushLock
);
561 ASSERT(PushLock
->Locked
);
564 ExfReleasePushLockExclusive(PushLock
);
568 * @name ExReleasePushLockShared
571 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
574 * Pointer to a previously acquired pushlock.
578 * @remarks The function attempts the quickest route to release the lock, which is
579 * to simply decrease the share count and remove the lock bit.
580 * However, if the pushlock is being waited on then the long path is taken.
582 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
583 * This macro should usually be paired up with KeLeaveCriticalRegion.
588 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
590 EX_PUSH_LOCK OldValue
;
593 ASSERT(PushLock
->Locked
);
594 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
596 /* Try to clear the pushlock */
597 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
598 if (InterlockedCompareExchangePointer(PushLock
, 0, OldValue
.Ptr
) !=
601 /* There are still other people waiting on it */
602 DbgPrint("%s - Contention!\n", __FUNCTION__
);
603 ExfReleasePushLockShared(PushLock
);
608 * @name ExReleasePushLockExclusive
611 * The ExReleasePushLockExclusive macro releases a previously
612 * exclusively acquired PushLock.
615 * Pointer to a previously acquired pushlock.
619 * @remarks The function attempts the quickest route to release the lock, which is
620 * to simply clear the locked bit.
621 * However, if the pushlock is being waited on, the slow path is taken
622 * in an attempt to wake up the lock.
624 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
625 * This macro should usually be paired up with KeLeaveCriticalRegion.
630 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
632 EX_PUSH_LOCK OldValue
;
635 ASSERT(PushLock
->Locked
);
636 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
== 0);
638 /* Unlock the pushlock */
639 OldValue
.Value
= InterlockedExchangeAddSizeT((PLONG
)PushLock
, -1);
642 ASSERT(OldValue
.Locked
);
643 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
645 /* Check if anyone is waiting on it and it's not already waking*/
646 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
649 DbgPrint("%s - Contention!\n", __FUNCTION__
);
650 ExfTryToWakePushLock(PushLock
);
655 * @name ExReleasePushLock
658 * The ExReleasePushLock macro releases a previously acquired PushLock.
661 * Pointer to a previously acquired pushlock.
665 * @remarks The function attempts the quickest route to release the lock, which is
666 * to simply clear all the fields and decrease the share count if required.
667 * However, if the pushlock is being waited on then the long path is taken.
669 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
670 * This macro should usually be paired up with KeLeaveCriticalRegion.
675 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
677 EX_PUSH_LOCK OldValue
= *PushLock
;
678 EX_PUSH_LOCK NewValue
;
681 ASSERT(OldValue
.Locked
);
683 /* Check if the pushlock is shared */
684 if (OldValue
.Shared
> 1)
686 /* Decrease the share count */
687 NewValue
.Value
= OldValue
.Value
&~ EX_PUSH_LOCK_SHARE_INC
;
691 /* Clear the pushlock entirely */
695 /* Check if nobody is waiting on us and try clearing the lock here */
696 if ((OldValue
.Waiting
) ||
697 (InterlockedCompareExchangePointer(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) ==
700 /* We have waiters, use the long path */
701 DbgPrint("%s - Contention!\n", __FUNCTION__
);
702 ExfReleasePushLock(PushLock
);
706 /* OTHER FUNCTIONS **********************************************************/
710 ExfpInterlockedExchange64(
711 LONGLONG
volatile * Destination
,
716 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
);
720 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
);
724 ExTimerRundown(VOID
);
726 #define InterlockedDecrementUL(Addend) \
727 (ULONG)InterlockedDecrement((PLONG)(Addend))
729 #define InterlockedIncrementUL(Addend) \
730 (ULONG)InterlockedIncrement((PLONG)(Addend))
732 #define InterlockedExchangeUL(Target, Value) \
733 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
735 #define InterlockedExchangeAddUL(Addend, Value) \
736 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
738 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
739 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
741 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
742 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
744 #define ExfpInterlockedExchange64UL(Target, Value) \
745 (ULONGLONG)ExfpInterlockedExchange64((PLONGLONG)(Target), (PLONGLONG)(Value))
747 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */