3 /* GLOBAL VARIABLES *********************************************************/
5 extern RTL_TIME_ZONE_INFORMATION ExpTimeZoneInfo
;
6 extern LARGE_INTEGER ExpTimeZoneBias
;
7 extern ULONG ExpTimeZoneId
;
8 extern ULONG ExpTickCountMultiplier
;
9 extern ULONG ExpLastTimeZoneBias
;
10 extern POBJECT_TYPE ExEventPairObjectType
;
11 extern POBJECT_TYPE _ExEventObjectType
, _ExSemaphoreObjectType
;
12 extern FAST_MUTEX ExpEnvironmentLock
;
13 extern ERESOURCE ExpFirmwareTableResource
;
14 extern LIST_ENTRY ExpFirmwareTableProviderListHead
;
15 extern BOOLEAN ExpIsWinPEMode
;
16 extern LIST_ENTRY ExpSystemResourcesList
;
17 extern ULONG ExpAnsiCodePageDataOffset
, ExpOemCodePageDataOffset
;
18 extern ULONG ExpUnicodeCaseTableDataOffset
;
19 extern PVOID ExpNlsSectionPointer
;
20 extern ULONG NtGlobalFlag
;
21 extern UNICODE_STRING NtSystemRoot
;
22 extern ULONG ExpInitializationPhase
;
23 extern ULONG ExpAltTimeZoneBias
;
24 extern LIST_ENTRY ExSystemLookasideListHead
;
25 extern PCALLBACK_OBJECT PowerStateCallback
;
26 extern LIST_ENTRY ExPoolLookasideListHead
;
27 extern LIST_ENTRY ExpNonPagedLookasideListHead
;
28 extern LIST_ENTRY ExpPagedLookasideListHead
;
29 extern KSPIN_LOCK ExpNonPagedLookasideListLock
;
30 extern KSPIN_LOCK ExpPagedLookasideListLock
;
31 extern ULONG ExCriticalWorkerThreads
;
32 extern ULONG ExDelayedWorkerThreads
;
34 extern PVOID ExpDefaultErrorPort
;
35 extern PEPROCESS ExpDefaultErrorPortProcess
;
38 * NT/Cm Version Info variables
40 extern ULONG NtMajorVersion
;
41 extern ULONG NtMinorVersion
;
42 extern ULONG NtBuildNumber
;
43 extern ULONG CmNtSpBuildNumber
;
44 extern ULONG CmNtCSDVersion
;
45 extern ULONG CmNtCSDReleaseType
;
46 extern UNICODE_STRING CmVersionString
;
47 extern UNICODE_STRING CmCSDVersionString
;
48 extern CHAR NtBuildLab
[];
52 * WinDBG Debugger Worker State Machine data (see dbgctrl.c)
54 typedef enum _WINKD_WORKER_STATE
58 WinKdWorkerInitialized
61 extern WORK_QUEUE_ITEM ExpDebuggerWorkItem
;
62 extern WINKD_WORKER_STATE ExpDebuggerWork
;
63 extern PEPROCESS ExpDebuggerProcessAttach
;
64 extern PEPROCESS ExpDebuggerProcessKill
;
65 extern ULONG_PTR ExpDebuggerPageIn
;
67 VOID NTAPI
ExpDebuggerWorker(IN PVOID Context
);
68 // #endif /* _WINKD_ */
71 #define HANDLE_LOW_BITS (PAGE_SHIFT - 4)
72 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 3)
74 #define HANDLE_LOW_BITS (PAGE_SHIFT - 3)
75 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2)
77 #define HANDLE_TAG_BITS (2)
78 #define HANDLE_INDEX_BITS (HANDLE_LOW_BITS + 2*HANDLE_HIGH_BITS)
79 #define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - HANDLE_INDEX_BITS - HANDLE_TAG_BITS)
81 typedef union _EXHANDLE
85 ULONG_PTR TagBits
: HANDLE_TAG_BITS
;
86 ULONG_PTR Index
: HANDLE_INDEX_BITS
;
87 ULONG_PTR KernelFlag
: KERNEL_FLAG_BITS
;
91 ULONG_PTR TagBits2
: HANDLE_TAG_BITS
;
92 ULONG_PTR LowIndex
: HANDLE_LOW_BITS
;
93 ULONG_PTR MidIndex
: HANDLE_HIGH_BITS
;
94 ULONG_PTR HighIndex
: HANDLE_HIGH_BITS
;
95 ULONG_PTR KernelFlag2
: KERNEL_FLAG_BITS
;
97 HANDLE GenericHandleOverlay
;
100 } EXHANDLE
, *PEXHANDLE
;
102 typedef struct _ETIMER
107 LIST_ENTRY ActiveTimerListEntry
;
110 BOOLEAN ApcAssociated
;
112 LIST_ENTRY WakeTimerListEntry
;
117 PCALLBACK_OBJECT
*CallbackObject
;
121 typedef struct _HARDERROR_USER_PARAMETERS
123 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
124 UNICODE_STRING Strings
[MAXIMUM_HARDERROR_PARAMETERS
];
125 WCHAR Buffer
[ANYSIZE_ARRAY
];
126 } HARDERROR_USER_PARAMETERS
, *PHARDERROR_USER_PARAMETERS
;
128 #define MAX_FAST_REFS 7
130 #define ExAcquireRundownProtection _ExAcquireRundownProtection
131 #define ExReleaseRundownProtection _ExReleaseRundownProtection
132 #define ExInitializeRundownProtection _ExInitializeRundownProtection
133 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
134 #define ExRundownCompleted _ExRundownCompleted
135 #define ExGetPreviousMode KeGetPreviousMode
139 // Various bits tagged on the handle or handle table
141 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT 1
142 #define FREE_HANDLE_MASK -1
145 // Number of entries in each table level
147 #define LOW_LEVEL_ENTRIES (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
148 #define MID_LEVEL_ENTRIES (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
149 #define HIGH_LEVEL_ENTRIES (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
152 // Maximum index in each table level before we need another table
154 #define MAX_LOW_INDEX LOW_LEVEL_ENTRIES
155 #define MAX_MID_INDEX (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
156 #define MAX_HIGH_INDEX (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
158 #define ExpChangeRundown(x, y, z) (ULONG_PTR)InterlockedCompareExchangePointer(&x->Ptr, (PVOID)y, (PVOID)z)
159 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
160 #define ExpSetRundown(x, y) InterlockedExchangePointer(&x->Ptr, (PVOID)y)
165 IN PSYSTEM_POOLTAG_INFORMATION SystemInformation
,
166 IN ULONG SystemInformationLength
,
167 IN OUT PULONG ReturnLength OPTIONAL
170 /* INITIALIZATION FUNCTIONS *************************************************/
183 Phase1Initialization(
190 ExpInitializePushLocks(VOID
);
194 ExRefreshTimeZoneInformation(
195 IN PLARGE_INTEGER SystemBootTime
201 ExpInitializeWorkerThreads(VOID
);
205 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap
);
210 ExpInitLookasideLists(VOID
);
215 ExInitializeSystemLookasideList(
216 IN PGENERAL_LOOKASIDE List
,
220 IN USHORT MaximumDepth
,
221 IN PLIST_ENTRY ListHead
227 ExpInitializeCallbacks(VOID
);
237 ExpInitializeExecutive(
239 IN PLOADER_PARAMETER_BLOCK LoaderBlock
244 ExShutdownSystem(VOID
);
249 ExpInitializeEventImplementation(VOID
);
254 ExpInitializeKeyedEventImplementation(VOID
);
259 ExpInitializeEventPairImplementation(VOID
);
264 ExpInitializeSemaphoreImplementation(VOID
);
269 ExpInitializeMutantImplementation(VOID
);
274 ExpInitializeTimerImplementation(VOID
);
279 ExpInitializeProfileImplementation(VOID
);
284 ExpResourceInitialization(VOID
);
289 ExInitPoolLookasidePointers(VOID
);
291 /* Callback Functions ********************************************************/
295 ExInitializeCallBack(
296 IN OUT PEX_CALLBACK Callback
299 PEX_CALLBACK_ROUTINE_BLOCK
302 IN PEX_CALLBACK_FUNCTION Function
,
309 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
314 ExCompareExchangeCallBack (
315 IN OUT PEX_CALLBACK CallBack
,
316 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock
,
317 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
320 PEX_CALLBACK_ROUTINE_BLOCK
322 ExReferenceCallBackBlock(
323 IN OUT PEX_CALLBACK CallBack
328 ExDereferenceCallBackBlock(
329 IN OUT PEX_CALLBACK CallBack
,
330 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
333 PEX_CALLBACK_FUNCTION
335 ExGetCallBackBlockRoutine(
336 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
341 ExGetCallBackBlockContext(
342 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
348 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
351 /* Rundown Functions ********************************************************/
355 ExfInitializeRundownProtection(
356 OUT PEX_RUNDOWN_REF RunRef
361 ExfReInitializeRundownProtection(
362 OUT PEX_RUNDOWN_REF RunRef
367 ExfAcquireRundownProtection(
368 IN OUT PEX_RUNDOWN_REF RunRef
373 ExfAcquireRundownProtectionEx(
374 IN OUT PEX_RUNDOWN_REF RunRef
,
380 ExfReleaseRundownProtection(
381 IN OUT PEX_RUNDOWN_REF RunRef
386 ExfReleaseRundownProtectionEx(
387 IN OUT PEX_RUNDOWN_REF RunRef
,
394 OUT PEX_RUNDOWN_REF RunRef
399 ExfWaitForRundownProtectionRelease(
400 IN OUT PEX_RUNDOWN_REF RunRef
403 /* HANDLE TABLE FUNCTIONS ***************************************************/
406 (NTAPI
*PEX_SWEEP_HANDLE_CALLBACK
)(
407 PHANDLE_TABLE_ENTRY HandleTableEntry
,
413 (NTAPI
*PEX_DUPLICATE_HANDLE_CALLBACK
)(
414 IN PEPROCESS Process
,
415 IN PHANDLE_TABLE HandleTable
,
416 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
417 IN PHANDLE_TABLE_ENTRY NewEntry
421 (NTAPI
*PEX_CHANGE_HANDLE_CALLBACK
)(
422 PHANDLE_TABLE_ENTRY HandleTableEntry
,
429 ExpInitializeHandleTables(
436 IN PEPROCESS Process OPTIONAL
441 ExUnlockHandleTableEntry(
442 IN PHANDLE_TABLE HandleTable
,
443 IN PHANDLE_TABLE_ENTRY HandleTableEntry
449 IN PHANDLE_TABLE HandleTable
,
450 IN PHANDLE_TABLE_ENTRY HandleTableEntry
455 ExDestroyHandleTable(
456 IN PHANDLE_TABLE HandleTable
,
457 IN PVOID DestroyHandleProcedure OPTIONAL
463 IN PHANDLE_TABLE HandleTable
,
465 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
470 ExMapHandleToPointer(
471 IN PHANDLE_TABLE HandleTable
,
478 IN PEPROCESS Process
,
479 IN PHANDLE_TABLE HandleTable
,
480 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
487 IN PHANDLE_TABLE HandleTable
,
489 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
496 IN PHANDLE_TABLE HandleTable
,
497 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
503 ExpLookupHandleTableEntry(
504 IN PHANDLE_TABLE HandleTable
,
510 ExpLockHandleTableEntry(
511 IN PHANDLE_TABLE HandleTable
,
512 IN PHANDLE_TABLE_ENTRY HandleTableEntry
515 /* PSEH EXCEPTION HANDLING **************************************************/
519 ExSystemExceptionFilter(VOID
);
521 /* CALLBACKS *****************************************************************/
525 ExDoCallBack(IN OUT PEX_CALLBACK Callback
,
530 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock
;
531 PEX_CALLBACK_FUNCTION Function
;
533 /* Reference the block */
534 CallbackBlock
= ExReferenceCallBackBlock(Callback
);
537 /* Get the function */
538 Function
= ExGetCallBackBlockRoutine(CallbackBlock
);
540 /* Do the callback */
541 Function(Context
, Argument1
, Argument2
);
543 /* Now dereference it */
544 ExDereferenceCallBackBlock(Callback
, CallbackBlock
);
548 /* FAST REFS ******************************************************************/
552 ExGetObjectFastReference(IN EX_FAST_REF FastRef
)
554 /* Return the unbiased pointer */
555 return (PVOID
)(FastRef
.Value
& ~MAX_FAST_REFS
);
560 ExGetCountFastReference(IN EX_FAST_REF FastRef
)
562 /* Return the reference count */
563 return (ULONG
)FastRef
.RefCnt
;
568 ExInitializeFastReference(OUT PEX_FAST_REF FastRef
,
569 IN OPTIONAL PVOID Object
)
572 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
574 /* Check if an object is being set */
577 /* Clear the field */
578 FastRef
->Object
= NULL
;
582 /* Otherwise, we assume the object was referenced and is ready */
583 FastRef
->Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
589 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef
)
591 EX_FAST_REF OldValue
, NewValue
;
593 /* Start reference loop */
596 /* Get the current reference count */
600 /* Increase the reference count */
601 NewValue
.Value
= OldValue
.Value
- 1;
602 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
605 if (NewValue
.Object
!= OldValue
.Object
) continue;
612 /* Return the old value */
618 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef
,
621 EX_FAST_REF OldValue
, NewValue
;
624 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
626 /* Start update loop */
629 /* Get the current reference count */
632 /* Check if the current count is too high or if the pointer changed */
633 if (((OldValue
.RefCnt
+ MAX_FAST_REFS
) > MAX_FAST_REFS
) ||
634 ((OldValue
.Value
&~ MAX_FAST_REFS
) != (ULONG_PTR
)Object
))
640 /* Update the reference count */
641 NewValue
.Value
= OldValue
.Value
+ MAX_FAST_REFS
;
642 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
645 if (NewValue
.Object
!= OldValue
.Object
) continue;
657 ExReleaseFastReference(IN PEX_FAST_REF FastRef
,
660 EX_FAST_REF OldValue
, NewValue
;
663 ASSERT(Object
!= NULL
);
664 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
666 /* Start reference loop */
669 /* Get the current reference count */
672 /* Check if we're full if if the pointer changed */
673 if ((OldValue
.Value
^ (ULONG_PTR
)Object
) >= MAX_FAST_REFS
) return FALSE
;
675 /* Decrease the reference count */
676 NewValue
.Value
= OldValue
.Value
+ 1;
677 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
680 if (NewValue
.Object
!= OldValue
.Object
) continue;
692 ExSwapFastReference(IN PEX_FAST_REF FastRef
,
695 EX_FAST_REF NewValue
, OldValue
;
698 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
700 /* Check if an object is being set */
703 /* Clear the field */
704 NewValue
.Object
= NULL
;
708 /* Otherwise, we assume the object was referenced and is ready */
709 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
712 /* Update the object */
713 OldValue
.Object
= InterlockedExchangePointer(&FastRef
->Object
, NewValue
.Object
);
719 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef
,
723 EX_FAST_REF OldValue
, NewValue
;
725 /* Sanity check and start swap loop */
726 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
729 /* Get the current value */
732 /* Make sure there's enough references to swap */
733 if (!((OldValue
.Value
^ (ULONG_PTR
)OldObject
) <= MAX_FAST_REFS
)) break;
735 /* Check if we have an object to swap */
738 /* Set up the value with maximum fast references */
739 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
743 /* Write the object address itself (which is empty) */
744 NewValue
.Value
= (ULONG_PTR
)Object
;
747 /* Do the actual compare exchange */
748 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
751 if (NewValue
.Object
!= OldValue
.Object
) continue;
757 /* Return the old value */
761 /* RUNDOWN *******************************************************************/
765 ExGetRunRefForGivenProcessor(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
,
768 return (PEX_RUNDOWN_REF
)((ULONG_PTR
)RunRefCacheAware
->RunRefs
+
769 RunRefCacheAware
->RunRefSize
*
770 (ProcNumber
% RunRefCacheAware
->Number
));
774 * @name ExfAcquireRundownProtection
777 * The ExfAcquireRundownProtection routine acquires rundown protection for
778 * the specified descriptor.
781 * Pointer to a rundown reference descriptor.
783 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
785 * @remarks This is the internal macro for system use only.In case the rundown
786 * was active, then the slow-path will be called through the exported
792 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
794 ULONG_PTR Value
, NewValue
;
796 /* Get the current value and mask the active bit */
797 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
799 /* Add a reference */
800 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
802 /* Change the value */
803 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
804 if (NewValue
!= Value
)
806 /* Rundown was active, use long path */
807 return ExfAcquireRundownProtection(RunRef
);
815 * @name ExReleaseRundownProtection
818 * The ExReleaseRundownProtection routine releases rundown protection for
819 * the specified descriptor.
822 * Pointer to a rundown reference descriptor.
824 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
826 * @remarks This is the internal macro for system use only.In case the rundown
827 * was active, then the slow-path will be called through the exported
833 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
835 ULONG_PTR Value
, NewValue
;
837 /* Get the current value and mask the active bit */
838 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
840 /* Remove a reference */
841 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
843 /* Change the value */
844 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
846 /* Check if the rundown was active */
847 if (NewValue
!= Value
)
849 /* Rundown was active, use long path */
850 ExfReleaseRundownProtection(RunRef
);
855 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
860 * @name ExInitializeRundownProtection
863 * The ExInitializeRundownProtection routine initializes a rundown
864 * protection descriptor.
867 * Pointer to a rundown reference descriptor.
871 * @remarks This is the internal macro for system use only.
876 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
878 /* Set the count to zero */
883 * @name ExWaitForRundownProtectionRelease
886 * The ExWaitForRundownProtectionRelease routine waits until the specified
887 * rundown descriptor has been released.
890 * Pointer to a rundown reference descriptor.
894 * @remarks This is the internal macro for system use only. If a wait is actually
895 * necessary, then the slow path is taken through the exported function.
900 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
904 /* Set the active bit */
905 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
906 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
908 /* If the the rundown wasn't already active, then take the long path */
909 ExfWaitForRundownProtectionRelease(RunRef
);
914 * @name ExRundownCompleted
917 * The ExRundownCompleted routine completes the rundown of the specified
918 * descriptor by setting the active bit.
921 * Pointer to a rundown reference descriptor.
925 * @remarks This is the internal macro for system use only.
930 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
933 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
935 /* Mark the counter as active */
936 ExpSetRundown(RunRef
, EX_RUNDOWN_ACTIVE
);
939 /* PUSHLOCKS *****************************************************************/
941 /* FIXME: VERIFY THESE! */
946 IN PEX_PUSH_LOCK PushLock
,
953 IN PEX_PUSH_LOCK PushLock
,
954 IN PVOID CurrentWaitBlock
959 ExWaitForUnblockPushLock(
960 IN PEX_PUSH_LOCK PushLock
,
965 * @name _ExInitializePushLock
968 * The _ExInitializePushLock macro initializes a PushLock.
971 * Pointer to the pushlock which is to be initialized.
980 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock
)
982 /* Set the value to 0 */
985 #define ExInitializePushLock _ExInitializePushLock
988 * @name ExAcquirePushLockExclusive
991 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
994 * Pointer to the pushlock which is to be acquired.
998 * @remarks The function attempts the quickest route to acquire the lock, which is
999 * to simply set the lock bit.
1000 * However, if the pushlock is already shared, the slower path is taken.
1002 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1003 * This macro should usually be paired up with KeAcquireCriticalRegion.
1008 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1010 /* Try acquiring the lock */
1011 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
1013 /* Someone changed it, use the slow path */
1014 ExfAcquirePushLockExclusive(PushLock
);
1018 ASSERT(PushLock
->Locked
);
1022 * @name ExTryToAcquirePushLockExclusive
1025 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
1028 * Pointer to the pushlock which is to be acquired.
1032 * @remarks The function attempts the quickest route to acquire the lock, which is
1033 * to simply set the lock bit.
1034 * However, if the pushlock is already shared, the slower path is taken.
1036 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1037 * This macro should usually be paired up with KeAcquireCriticalRegion.
1042 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1044 /* Try acquiring the lock */
1045 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
1052 ASSERT (PushLock
->Locked
);
1057 * @name ExAcquirePushLockShared
1060 * The ExAcquirePushLockShared macro acquires a shared PushLock.
1063 * Pointer to the pushlock which is to be acquired.
1067 * @remarks The function attempts the quickest route to acquire the lock, which is
1068 * to simply set the lock bit and set the share count to one.
1069 * However, if the pushlock is already shared, the slower path is taken.
1071 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1072 * This macro should usually be paired up with KeAcquireCriticalRegion.
1077 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
1079 EX_PUSH_LOCK NewValue
;
1081 /* Try acquiring the lock */
1082 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1083 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
1085 /* Someone changed it, use the slow path */
1086 ExfAcquirePushLockShared(PushLock
);
1090 ASSERT(PushLock
->Locked
);
1094 * @name ExConvertPushLockSharedToExclusive
1097 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
1098 * pushlock to a shared pushlock.
1101 * Pointer to the pushlock which is to be converted.
1103 * @return FALSE if conversion failed, TRUE otherwise.
1105 * @remarks The function attempts the quickest route to convert the lock, which is
1106 * to simply set the lock bit and remove any other bits.
1111 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
1113 EX_PUSH_LOCK OldValue
;
1115 /* Set the expected old value */
1116 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1118 /* Try converting the lock */
1119 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
1122 /* Conversion failed */
1127 ASSERT(PushLock
->Locked
);
1132 * @name ExWaitOnPushLock
1135 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1138 * Pointer to a pushlock.
1142 * @remarks The function attempts to get any exclusive waiters out of their slow
1143 * path by forcing an instant acquire/release operation.
1145 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1150 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
1152 /* Check if we're locked */
1153 if (PushLock
->Locked
)
1155 /* Acquire the lock */
1156 ExfAcquirePushLockExclusive(PushLock
);
1157 ASSERT(PushLock
->Locked
);
1160 ExfReleasePushLockExclusive(PushLock
);
1165 * @name ExReleasePushLockShared
1168 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
1171 * Pointer to a previously acquired pushlock.
1175 * @remarks The function attempts the quickest route to release the lock, which is
1176 * to simply decrease the share count and remove the lock bit.
1177 * However, if the pushlock is being waited on then the long path is taken.
1179 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1180 * This macro should usually be paired up with KeLeaveCriticalRegion.
1185 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
1187 EX_PUSH_LOCK OldValue
;
1190 ASSERT(PushLock
->Locked
);
1192 /* Try to clear the pushlock */
1193 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1194 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
1196 /* There are still other people waiting on it */
1197 ExfReleasePushLockShared(PushLock
);
1202 * @name ExReleasePushLockExclusive
1205 * The ExReleasePushLockExclusive macro releases a previously
1206 * exclusively acquired PushLock.
1209 * Pointer to a previously acquired pushlock.
1213 * @remarks The function attempts the quickest route to release the lock, which is
1214 * to simply clear the locked bit.
1215 * However, if the pushlock is being waited on, the slow path is taken
1216 * in an attempt to wake up the lock.
1218 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1219 * This macro should usually be paired up with KeLeaveCriticalRegion.
1224 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1226 EX_PUSH_LOCK OldValue
;
1229 ASSERT(PushLock
->Locked
);
1231 /* Unlock the pushlock */
1232 OldValue
.Value
= InterlockedExchangeAddSizeT((PSIZE_T
)PushLock
,
1233 -(SSIZE_T
)EX_PUSH_LOCK_LOCK
);
1236 ASSERT(OldValue
.Locked
);
1237 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
1239 /* Check if anyone is waiting on it and it's not already waking*/
1240 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
1243 ExfTryToWakePushLock(PushLock
);
1248 * @name ExReleasePushLock
1251 * The ExReleasePushLock macro releases a previously acquired PushLock.
1254 * Pointer to a previously acquired pushlock.
1258 * @remarks The function attempts the quickest route to release the lock, which is
1259 * to simply clear all the fields and decrease the share count if required.
1260 * However, if the pushlock is being waited on then the long path is taken.
1262 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1263 * This macro should usually be paired up with KeLeaveCriticalRegion.
1268 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
1270 EX_PUSH_LOCK OldValue
= *PushLock
;
1271 EX_PUSH_LOCK NewValue
;
1274 ASSERT(OldValue
.Locked
);
1276 /* Check if the pushlock is shared */
1277 if (OldValue
.Shared
> 1)
1279 /* Decrease the share count */
1280 NewValue
.Value
= OldValue
.Value
- EX_PUSH_LOCK_SHARE_INC
;
1284 /* Clear the pushlock entirely */
1288 /* Check if nobody is waiting on us and try clearing the lock here */
1289 if ((OldValue
.Waiting
) ||
1290 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
1293 /* We have waiters, use the long path */
1294 ExfReleasePushLock(PushLock
);
1298 /* FAST MUTEX INLINES *********************************************************/
1302 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex
)
1304 PKTHREAD Thread
= KeGetCurrentThread();
1307 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1308 (Thread
->CombinedApcDisable
!= 0) ||
1309 (Thread
->Teb
== NULL
) ||
1310 (Thread
->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1311 ASSERT(FastMutex
->Owner
!= Thread
);
1313 /* Decrease the count */
1314 if (InterlockedDecrement(&FastMutex
->Count
))
1316 /* Someone is still holding it, use slow path */
1317 KiAcquireFastMutex(FastMutex
);
1321 FastMutex
->Owner
= Thread
;
1326 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1328 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1329 (KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
1330 (KeGetCurrentThread()->Teb
== NULL
) ||
1331 (KeGetCurrentThread()->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1332 ASSERT(FastMutex
->Owner
== KeGetCurrentThread());
1334 /* Erase the owner */
1335 FastMutex
->Owner
= NULL
;
1337 /* Increase the count */
1338 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1340 /* Someone was waiting for it, signal the waiter */
1341 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1347 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
1350 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1352 /* Raise IRQL to APC */
1353 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1355 /* Decrease the count */
1356 if (InterlockedDecrement(&FastMutex
->Count
))
1358 /* Someone is still holding it, use slow path */
1359 KiAcquireFastMutex(FastMutex
);
1362 /* Set the owner and IRQL */
1363 FastMutex
->Owner
= KeGetCurrentThread();
1364 FastMutex
->OldIrql
= OldIrql
;
1369 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1372 ASSERT(KeGetCurrentIrql() == APC_LEVEL
);
1374 /* Erase the owner */
1375 FastMutex
->Owner
= NULL
;
1376 OldIrql
= (KIRQL
)FastMutex
->OldIrql
;
1378 /* Increase the count */
1379 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1381 /* Someone was waiting for it, signal the waiter */
1382 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1385 /* Lower IRQL back */
1386 KeLowerIrql(OldIrql
);
1391 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1394 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1396 /* Raise to APC_LEVEL */
1397 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1399 /* Check if we can quickly acquire it */
1400 if (InterlockedCompareExchange(&FastMutex
->Count
, 0, 1) == 1)
1402 /* We have, set us as owners */
1403 FastMutex
->Owner
= KeGetCurrentThread();
1404 FastMutex
->OldIrql
= OldIrql
;
1409 /* Acquire attempt failed */
1410 KeLowerIrql(OldIrql
);
1418 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1420 /* Enter the Critical Region */
1421 KeEnterCriticalRegion();
1423 /* Acquire the mutex unsafely */
1424 _ExAcquireFastMutexUnsafe(FastMutex
);
1429 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex
)
1431 /* Release the mutex unsafely */
1432 _ExReleaseFastMutexUnsafe(FastMutex
);
1434 /* Leave the critical region */
1435 KeLeaveCriticalRegion();
1438 /* OTHER FUNCTIONS **********************************************************/
1442 ExTryToAcquireResourceExclusiveLite(
1443 IN PERESOURCE Resource
1447 ExpSetTimeZoneInformation(
1448 IN PRTL_TIME_ZONE_INFORMATION TimeZoneInformation
1453 ExAcquireTimeRefreshLock(
1459 ExReleaseTimeRefreshLock(
1465 ExUpdateSystemTimeFromCmos(
1466 IN BOOLEAN UpdateInterruptTime
,
1467 IN ULONG MaxSepInSeconds
1472 ExAllocateLocallyUniqueId(
1473 OUT LUID
*LocallyUniqueId
1486 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1493 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1496 #define InterlockedDecrementUL(Addend) \
1497 (ULONG)InterlockedDecrement((PLONG)(Addend))
1499 #define InterlockedIncrementUL(Addend) \
1500 (ULONG)InterlockedIncrement((PLONG)(Addend))
1502 #define InterlockedExchangeUL(Target, Value) \
1503 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1505 #define InterlockedExchangeAddUL(Addend, Value) \
1506 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1508 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1509 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1511 #define InterlockedCompareExchangeSizeT(Destination, Exchange, Comperand) \
1512 (SIZE_T)InterlockedCompareExchangePointer((PVOID*)(Destination), (PVOID)(SIZE_T)(Exchange), (PVOID)(SIZE_T)(Comperand))
1514 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1515 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))