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 *************************************************/
182 Phase1Initialization(
188 ExpInitializePushLocks(VOID
);
192 ExRefreshTimeZoneInformation(
193 IN PLARGE_INTEGER SystemBootTime
198 ExpInitializeWorkerThreads(VOID
);
202 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap
);
206 ExpInitLookasideLists(VOID
);
210 ExInitializeSystemLookasideList(
211 IN PGENERAL_LOOKASIDE List
,
215 IN USHORT MaximumDepth
,
216 IN PLIST_ENTRY ListHead
221 ExpInitializeCallbacks(VOID
);
229 ExpInitializeExecutive(
231 IN PLOADER_PARAMETER_BLOCK LoaderBlock
236 ExShutdownSystem(VOID
);
240 ExpInitializeEventImplementation(VOID
);
244 ExpInitializeKeyedEventImplementation(VOID
);
248 ExpInitializeEventPairImplementation(VOID
);
252 ExpInitializeSemaphoreImplementation(VOID
);
256 ExpInitializeMutantImplementation(VOID
);
260 ExpInitializeTimerImplementation(VOID
);
264 ExpInitializeProfileImplementation(VOID
);
268 ExpResourceInitialization(VOID
);
272 ExInitPoolLookasidePointers(VOID
);
274 /* Callback Functions ********************************************************/
278 ExInitializeCallBack(
279 IN OUT PEX_CALLBACK Callback
282 PEX_CALLBACK_ROUTINE_BLOCK
285 IN PEX_CALLBACK_FUNCTION Function
,
292 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
297 ExCompareExchangeCallBack (
298 IN OUT PEX_CALLBACK CallBack
,
299 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock
,
300 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
303 PEX_CALLBACK_ROUTINE_BLOCK
305 ExReferenceCallBackBlock(
306 IN OUT PEX_CALLBACK CallBack
311 ExDereferenceCallBackBlock(
312 IN OUT PEX_CALLBACK CallBack
,
313 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
316 PEX_CALLBACK_FUNCTION
318 ExGetCallBackBlockRoutine(
319 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
324 ExGetCallBackBlockContext(
325 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
331 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
334 /* Rundown Functions ********************************************************/
338 ExfInitializeRundownProtection(
339 OUT PEX_RUNDOWN_REF RunRef
344 ExfReInitializeRundownProtection(
345 OUT PEX_RUNDOWN_REF RunRef
350 ExfAcquireRundownProtection(
351 IN OUT PEX_RUNDOWN_REF RunRef
356 ExfAcquireRundownProtectionEx(
357 IN OUT PEX_RUNDOWN_REF RunRef
,
363 ExfReleaseRundownProtection(
364 IN OUT PEX_RUNDOWN_REF RunRef
369 ExfReleaseRundownProtectionEx(
370 IN OUT PEX_RUNDOWN_REF RunRef
,
377 OUT PEX_RUNDOWN_REF RunRef
382 ExfWaitForRundownProtectionRelease(
383 IN OUT PEX_RUNDOWN_REF RunRef
386 /* HANDLE TABLE FUNCTIONS ***************************************************/
389 (NTAPI
*PEX_SWEEP_HANDLE_CALLBACK
)(
390 PHANDLE_TABLE_ENTRY HandleTableEntry
,
396 (NTAPI
*PEX_DUPLICATE_HANDLE_CALLBACK
)(
397 IN PEPROCESS Process
,
398 IN PHANDLE_TABLE HandleTable
,
399 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
400 IN PHANDLE_TABLE_ENTRY NewEntry
404 (NTAPI
*PEX_CHANGE_HANDLE_CALLBACK
)(
405 PHANDLE_TABLE_ENTRY HandleTableEntry
,
411 ExpInitializeHandleTables(
418 IN PEPROCESS Process OPTIONAL
423 ExUnlockHandleTableEntry(
424 IN PHANDLE_TABLE HandleTable
,
425 IN PHANDLE_TABLE_ENTRY HandleTableEntry
431 IN PHANDLE_TABLE HandleTable
,
432 IN PHANDLE_TABLE_ENTRY HandleTableEntry
437 ExDestroyHandleTable(
438 IN PHANDLE_TABLE HandleTable
,
439 IN PVOID DestroyHandleProcedure OPTIONAL
445 IN PHANDLE_TABLE HandleTable
,
447 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
452 ExMapHandleToPointer(
453 IN PHANDLE_TABLE HandleTable
,
460 IN PEPROCESS Process
,
461 IN PHANDLE_TABLE HandleTable
,
462 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
469 IN PHANDLE_TABLE HandleTable
,
471 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
478 IN PHANDLE_TABLE HandleTable
,
479 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
485 ExpLookupHandleTableEntry(
486 IN PHANDLE_TABLE HandleTable
,
492 ExpLockHandleTableEntry(
493 IN PHANDLE_TABLE HandleTable
,
494 IN PHANDLE_TABLE_ENTRY HandleTableEntry
497 /* PSEH EXCEPTION HANDLING **************************************************/
501 ExSystemExceptionFilter(VOID
);
503 /* CALLBACKS *****************************************************************/
507 ExDoCallBack(IN OUT PEX_CALLBACK Callback
,
512 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock
;
513 PEX_CALLBACK_FUNCTION Function
;
515 /* Reference the block */
516 CallbackBlock
= ExReferenceCallBackBlock(Callback
);
519 /* Get the function */
520 Function
= ExGetCallBackBlockRoutine(CallbackBlock
);
522 /* Do the callback */
523 Function(Context
, Argument1
, Argument2
);
525 /* Now dereference it */
526 ExDereferenceCallBackBlock(Callback
, CallbackBlock
);
530 /* FAST REFS ******************************************************************/
534 ExGetObjectFastReference(IN EX_FAST_REF FastRef
)
536 /* Return the unbiased pointer */
537 return (PVOID
)(FastRef
.Value
& ~MAX_FAST_REFS
);
542 ExGetCountFastReference(IN EX_FAST_REF FastRef
)
544 /* Return the reference count */
545 return (ULONG
)FastRef
.RefCnt
;
550 ExGetRunRefForCurrentProcessor(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware
)
552 return (PEX_RUNDOWN_REF
)((ULONG_PTR
)RunRefCacheAware
->RunRefs
+
553 RunRefCacheAware
->RunRefSize
*
554 (KeGetCurrentProcessorNumber() % RunRefCacheAware
->Number
));
559 ExInitializeFastReference(OUT PEX_FAST_REF FastRef
,
560 IN OPTIONAL PVOID Object
)
563 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
565 /* Check if an object is being set */
568 /* Clear the field */
569 FastRef
->Object
= NULL
;
573 /* Otherwise, we assume the object was referenced and is ready */
574 FastRef
->Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
580 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef
)
582 EX_FAST_REF OldValue
, NewValue
;
584 /* Start reference loop */
587 /* Get the current reference count */
591 /* Increase the reference count */
592 NewValue
.Value
= OldValue
.Value
- 1;
593 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
596 if (NewValue
.Object
!= OldValue
.Object
) continue;
603 /* Return the old value */
609 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef
,
612 EX_FAST_REF OldValue
, NewValue
;
615 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
617 /* Start update loop */
620 /* Get the current reference count */
623 /* Check if the current count is too high or if the pointer changed */
624 if (((OldValue
.RefCnt
+ MAX_FAST_REFS
) > MAX_FAST_REFS
) ||
625 ((OldValue
.Value
&~ MAX_FAST_REFS
) != (ULONG_PTR
)Object
))
631 /* Update the reference count */
632 NewValue
.Value
= OldValue
.Value
+ MAX_FAST_REFS
;
633 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
636 if (NewValue
.Object
!= OldValue
.Object
) continue;
648 ExReleaseFastReference(IN PEX_FAST_REF FastRef
,
651 EX_FAST_REF OldValue
, NewValue
;
654 ASSERT(Object
!= NULL
);
655 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
657 /* Start reference loop */
660 /* Get the current reference count */
663 /* Check if we're full if if the pointer changed */
664 if ((OldValue
.Value
^ (ULONG_PTR
)Object
) >= MAX_FAST_REFS
) return FALSE
;
666 /* Decrease the reference count */
667 NewValue
.Value
= OldValue
.Value
+ 1;
668 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
671 if (NewValue
.Object
!= OldValue
.Object
) continue;
683 ExSwapFastReference(IN PEX_FAST_REF FastRef
,
686 EX_FAST_REF NewValue
, OldValue
;
689 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
691 /* Check if an object is being set */
694 /* Clear the field */
695 NewValue
.Object
= NULL
;
699 /* Otherwise, we assume the object was referenced and is ready */
700 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
703 /* Update the object */
704 OldValue
.Object
= InterlockedExchangePointer(&FastRef
->Object
, NewValue
.Object
);
710 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef
,
714 EX_FAST_REF OldValue
, NewValue
;
716 /* Sanity check and start swap loop */
717 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
720 /* Get the current value */
723 /* Make sure there's enough references to swap */
724 if (!((OldValue
.Value
^ (ULONG_PTR
)OldObject
) <= MAX_FAST_REFS
)) break;
726 /* Check if we have an object to swap */
729 /* Set up the value with maximum fast references */
730 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
734 /* Write the object address itself (which is empty) */
735 NewValue
.Value
= (ULONG_PTR
)Object
;
738 /* Do the actual compare exchange */
739 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
742 if (NewValue
.Object
!= OldValue
.Object
) continue;
748 /* Return the old value */
752 /* RUNDOWN *******************************************************************/
755 * @name ExfAcquireRundownProtection
758 * The ExfAcquireRundownProtection routine acquires rundown protection for
759 * the specified descriptor.
762 * Pointer to a rundown reference descriptor.
764 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
766 * @remarks This is the internal macro for system use only.In case the rundown
767 * was active, then the slow-path will be called through the exported
773 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
775 ULONG_PTR Value
, NewValue
;
777 /* Get the current value and mask the active bit */
778 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
780 /* Add a reference */
781 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
783 /* Change the value */
784 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
785 if (NewValue
!= Value
)
787 /* Rundown was active, use long path */
788 return ExfAcquireRundownProtection(RunRef
);
796 * @name ExReleaseRundownProtection
799 * The ExReleaseRundownProtection routine releases rundown protection for
800 * the specified descriptor.
803 * Pointer to a rundown reference descriptor.
805 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
807 * @remarks This is the internal macro for system use only.In case the rundown
808 * was active, then the slow-path will be called through the exported
814 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
816 ULONG_PTR Value
, NewValue
;
818 /* Get the current value and mask the active bit */
819 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
821 /* Remove a reference */
822 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
824 /* Change the value */
825 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
827 /* Check if the rundown was active */
828 if (NewValue
!= Value
)
830 /* Rundown was active, use long path */
831 ExfReleaseRundownProtection(RunRef
);
836 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
841 * @name ExInitializeRundownProtection
844 * The ExInitializeRundownProtection routine initializes a rundown
845 * protection descriptor.
848 * Pointer to a rundown reference descriptor.
852 * @remarks This is the internal macro for system use only.
857 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
859 /* Set the count to zero */
864 * @name ExWaitForRundownProtectionRelease
867 * The ExWaitForRundownProtectionRelease routine waits until the specified
868 * rundown descriptor has been released.
871 * Pointer to a rundown reference descriptor.
875 * @remarks This is the internal macro for system use only. If a wait is actually
876 * necessary, then the slow path is taken through the exported function.
881 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
885 /* Set the active bit */
886 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
887 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
889 /* If the the rundown wasn't already active, then take the long path */
890 ExfWaitForRundownProtectionRelease(RunRef
);
895 * @name ExRundownCompleted
898 * The ExRundownCompleted routine completes the rundown of the specified
899 * descriptor by setting the active bit.
902 * Pointer to a rundown reference descriptor.
906 * @remarks This is the internal macro for system use only.
911 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
914 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
916 /* Mark the counter as active */
917 ExpSetRundown(RunRef
, EX_RUNDOWN_ACTIVE
);
920 /* PUSHLOCKS *****************************************************************/
922 /* FIXME: VERIFY THESE! */
927 IN PEX_PUSH_LOCK PushLock
,
934 IN PEX_PUSH_LOCK PushLock
,
935 IN PVOID CurrentWaitBlock
940 ExWaitForUnblockPushLock(
941 IN PEX_PUSH_LOCK PushLock
,
946 * @name _ExInitializePushLock
949 * The _ExInitializePushLock macro initializes a PushLock.
952 * Pointer to the pushlock which is to be initialized.
961 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock
)
963 /* Set the value to 0 */
966 #define ExInitializePushLock _ExInitializePushLock
969 * @name ExAcquirePushLockExclusive
972 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
975 * Pointer to the pushlock which is to be acquired.
979 * @remarks The function attempts the quickest route to acquire the lock, which is
980 * to simply set the lock bit.
981 * However, if the pushlock is already shared, the slower path is taken.
983 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
984 * This macro should usually be paired up with KeAcquireCriticalRegion.
989 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
991 /* Try acquiring the lock */
992 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
994 /* Someone changed it, use the slow path */
995 ExfAcquirePushLockExclusive(PushLock
);
999 ASSERT(PushLock
->Locked
);
1003 * @name ExTryToAcquirePushLockExclusive
1006 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
1009 * Pointer to the pushlock which is to be acquired.
1013 * @remarks The function attempts the quickest route to acquire the lock, which is
1014 * to simply set the lock bit.
1015 * However, if the pushlock is already shared, the slower path is taken.
1017 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1018 * This macro should usually be paired up with KeAcquireCriticalRegion.
1023 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1025 /* Try acquiring the lock */
1026 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
1033 ASSERT (PushLock
->Locked
);
1038 * @name ExAcquirePushLockShared
1041 * The ExAcquirePushLockShared macro acquires a shared PushLock.
1044 * Pointer to the pushlock which is to be acquired.
1048 * @remarks The function attempts the quickest route to acquire the lock, which is
1049 * to simply set the lock bit and set the share count to one.
1050 * However, if the pushlock is already shared, the slower path is taken.
1052 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1053 * This macro should usually be paired up with KeAcquireCriticalRegion.
1058 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
1060 EX_PUSH_LOCK NewValue
;
1062 /* Try acquiring the lock */
1063 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1064 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
1066 /* Someone changed it, use the slow path */
1067 ExfAcquirePushLockShared(PushLock
);
1071 ASSERT(PushLock
->Locked
);
1075 * @name ExConvertPushLockSharedToExclusive
1078 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
1079 * pushlock to a shared pushlock.
1082 * Pointer to the pushlock which is to be converted.
1084 * @return FALSE if conversion failed, TRUE otherwise.
1086 * @remarks The function attempts the quickest route to convert the lock, which is
1087 * to simply set the lock bit and remove any other bits.
1092 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
1094 EX_PUSH_LOCK OldValue
;
1096 /* Set the expected old value */
1097 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1099 /* Try converting the lock */
1100 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
1103 /* Conversion failed */
1108 ASSERT(PushLock
->Locked
);
1113 * @name ExWaitOnPushLock
1116 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1119 * Pointer to a pushlock.
1123 * @remarks The function attempts to get any exclusive waiters out of their slow
1124 * path by forcing an instant acquire/release operation.
1126 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1131 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
1133 /* Check if we're locked */
1134 if (PushLock
->Locked
)
1136 /* Acquire the lock */
1137 ExfAcquirePushLockExclusive(PushLock
);
1138 ASSERT(PushLock
->Locked
);
1141 ExfReleasePushLockExclusive(PushLock
);
1146 * @name ExReleasePushLockShared
1149 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
1152 * Pointer to a previously acquired pushlock.
1156 * @remarks The function attempts the quickest route to release the lock, which is
1157 * to simply decrease the share count and remove the lock bit.
1158 * However, if the pushlock is being waited on then the long path is taken.
1160 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1161 * This macro should usually be paired up with KeLeaveCriticalRegion.
1166 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
1168 EX_PUSH_LOCK OldValue
;
1171 ASSERT(PushLock
->Locked
);
1173 /* Try to clear the pushlock */
1174 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1175 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
1177 /* There are still other people waiting on it */
1178 ExfReleasePushLockShared(PushLock
);
1183 * @name ExReleasePushLockExclusive
1186 * The ExReleasePushLockExclusive macro releases a previously
1187 * exclusively acquired PushLock.
1190 * Pointer to a previously acquired pushlock.
1194 * @remarks The function attempts the quickest route to release the lock, which is
1195 * to simply clear the locked bit.
1196 * However, if the pushlock is being waited on, the slow path is taken
1197 * in an attempt to wake up the lock.
1199 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1200 * This macro should usually be paired up with KeLeaveCriticalRegion.
1205 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1207 EX_PUSH_LOCK OldValue
;
1210 ASSERT(PushLock
->Locked
);
1212 /* Unlock the pushlock */
1213 OldValue
.Value
= InterlockedExchangeAddSizeT((PSIZE_T
)PushLock
,
1214 -(SSIZE_T
)EX_PUSH_LOCK_LOCK
);
1217 ASSERT(OldValue
.Locked
);
1218 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
1220 /* Check if anyone is waiting on it and it's not already waking*/
1221 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
1224 ExfTryToWakePushLock(PushLock
);
1229 * @name ExReleasePushLock
1232 * The ExReleasePushLock macro releases a previously acquired PushLock.
1235 * Pointer to a previously acquired pushlock.
1239 * @remarks The function attempts the quickest route to release the lock, which is
1240 * to simply clear all the fields and decrease the share count if required.
1241 * However, if the pushlock is being waited on then the long path is taken.
1243 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1244 * This macro should usually be paired up with KeLeaveCriticalRegion.
1249 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
1251 EX_PUSH_LOCK OldValue
= *PushLock
;
1252 EX_PUSH_LOCK NewValue
;
1255 ASSERT(OldValue
.Locked
);
1257 /* Check if the pushlock is shared */
1258 if (OldValue
.Shared
> 1)
1260 /* Decrease the share count */
1261 NewValue
.Value
= OldValue
.Value
- EX_PUSH_LOCK_SHARE_INC
;
1265 /* Clear the pushlock entirely */
1269 /* Check if nobody is waiting on us and try clearing the lock here */
1270 if ((OldValue
.Waiting
) ||
1271 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
1274 /* We have waiters, use the long path */
1275 ExfReleasePushLock(PushLock
);
1279 /* FAST MUTEX INLINES *********************************************************/
1283 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex
)
1285 PKTHREAD Thread
= KeGetCurrentThread();
1288 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1289 (Thread
->CombinedApcDisable
!= 0) ||
1290 (Thread
->Teb
== NULL
) ||
1291 (Thread
->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1292 ASSERT(FastMutex
->Owner
!= Thread
);
1294 /* Decrease the count */
1295 if (InterlockedDecrement(&FastMutex
->Count
))
1297 /* Someone is still holding it, use slow path */
1298 KiAcquireFastMutex(FastMutex
);
1302 FastMutex
->Owner
= Thread
;
1307 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1309 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1310 (KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
1311 (KeGetCurrentThread()->Teb
== NULL
) ||
1312 (KeGetCurrentThread()->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1313 ASSERT(FastMutex
->Owner
== KeGetCurrentThread());
1315 /* Erase the owner */
1316 FastMutex
->Owner
= NULL
;
1318 /* Increase the count */
1319 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1321 /* Someone was waiting for it, signal the waiter */
1322 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1328 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
1331 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1333 /* Raise IRQL to APC */
1334 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1336 /* Decrease the count */
1337 if (InterlockedDecrement(&FastMutex
->Count
))
1339 /* Someone is still holding it, use slow path */
1340 KiAcquireFastMutex(FastMutex
);
1343 /* Set the owner and IRQL */
1344 FastMutex
->Owner
= KeGetCurrentThread();
1345 FastMutex
->OldIrql
= OldIrql
;
1350 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1353 ASSERT(KeGetCurrentIrql() == APC_LEVEL
);
1355 /* Erase the owner */
1356 FastMutex
->Owner
= NULL
;
1357 OldIrql
= (KIRQL
)FastMutex
->OldIrql
;
1359 /* Increase the count */
1360 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1362 /* Someone was waiting for it, signal the waiter */
1363 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1366 /* Lower IRQL back */
1367 KeLowerIrql(OldIrql
);
1372 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1375 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1377 /* Raise to APC_LEVEL */
1378 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1380 /* Check if we can quickly acquire it */
1381 if (InterlockedCompareExchange(&FastMutex
->Count
, 0, 1) == 1)
1383 /* We have, set us as owners */
1384 FastMutex
->Owner
= KeGetCurrentThread();
1385 FastMutex
->OldIrql
= OldIrql
;
1390 /* Acquire attempt failed */
1391 KeLowerIrql(OldIrql
);
1399 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1401 /* Enter the Critical Region */
1402 KeEnterCriticalRegion();
1404 /* Acquire the mutex unsafely */
1405 _ExAcquireFastMutexUnsafe(FastMutex
);
1410 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex
)
1412 /* Release the mutex unsafely */
1413 _ExReleaseFastMutexUnsafe(FastMutex
);
1415 /* Leave the critical region */
1416 KeLeaveCriticalRegion();
1419 /* OTHER FUNCTIONS **********************************************************/
1423 ExTryToAcquireResourceExclusiveLite(
1424 IN PERESOURCE Resource
1428 ExpSetTimeZoneInformation(
1429 IN PRTL_TIME_ZONE_INFORMATION TimeZoneInformation
1434 ExAcquireTimeRefreshLock(
1440 ExReleaseTimeRefreshLock(
1446 ExUpdateSystemTimeFromCmos(
1447 IN BOOLEAN UpdateInterruptTime
,
1448 IN ULONG MaxSepInSeconds
1453 ExAllocateLocallyUniqueId(
1454 OUT LUID
*LocallyUniqueId
1466 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1472 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1475 #define InterlockedDecrementUL(Addend) \
1476 (ULONG)InterlockedDecrement((PLONG)(Addend))
1478 #define InterlockedIncrementUL(Addend) \
1479 (ULONG)InterlockedIncrement((PLONG)(Addend))
1481 #define InterlockedExchangeUL(Target, Value) \
1482 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1484 #define InterlockedExchangeAddUL(Addend, Value) \
1485 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1487 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1488 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1490 #define InterlockedCompareExchangeSizeT(Destination, Exchange, Comperand) \
1491 (SIZE_T)InterlockedCompareExchangePointer((PVOID*)(Destination), (PVOID)(SIZE_T)(Exchange), (PVOID)(SIZE_T)(Comperand))
1493 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1494 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))