3 /* GLOBAL VARIABLES *********************************************************/
5 extern 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 ULONG NtBuildNumber
;
13 extern ULONG NtMajorVersion
;
14 extern ULONG NtMinorVersion
;
15 extern FAST_MUTEX ExpEnvironmentLock
;
16 extern ERESOURCE ExpFirmwareTableResource
;
17 extern LIST_ENTRY ExpFirmwareTableProviderListHead
;
18 extern BOOLEAN ExpIsWinPEMode
;
19 extern LIST_ENTRY ExpSystemResourcesList
;
20 extern ULONG ExpAnsiCodePageDataOffset
, ExpOemCodePageDataOffset
;
21 extern ULONG ExpUnicodeCaseTableDataOffset
;
22 extern PVOID ExpNlsSectionPointer
;
23 extern CHAR NtBuildLab
[];
24 extern ULONG CmNtCSDVersion
;
25 extern ULONG NtGlobalFlag
;
26 extern ULONG ExpInitializationPhase
;
27 extern ULONG ExpAltTimeZoneBias
;
28 extern LIST_ENTRY ExSystemLookasideListHead
;
29 extern PCALLBACK_OBJECT PowerStateCallback
;
31 typedef struct _EXHANDLE
40 HANDLE GenericHandleOverlay
;
43 } EXHANDLE
, *PEXHANDLE
;
45 typedef struct _ETIMER
50 LIST_ENTRY ActiveTimerListEntry
;
53 BOOLEAN ApcAssociated
;
55 LIST_ENTRY WakeTimerListEntry
;
60 PCALLBACK_OBJECT
*CallbackObject
;
64 typedef struct _HARDERROR_USER_PARAMETERS
66 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
67 UNICODE_STRING Strings
[MAXIMUM_HARDERROR_PARAMETERS
];
68 WCHAR Buffer
[ANYSIZE_ARRAY
];
69 } HARDERROR_USER_PARAMETERS
, *PHARDERROR_USER_PARAMETERS
;
71 #define MAX_FAST_REFS 7
73 #define ExAcquireRundownProtection _ExAcquireRundownProtection
74 #define ExReleaseRundownProtection _ExReleaseRundownProtection
75 #define ExInitializeRundownProtection _ExInitializeRundownProtection
76 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
77 #define ExRundownCompleted _ExRundownCompleted
78 #define ExGetPreviousMode KeGetPreviousMode
82 // Various bits tagged on the handle or handle table
84 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT 1
85 #define FREE_HANDLE_MASK -1
88 // Number of entries in each table level
90 #define LOW_LEVEL_ENTRIES (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
91 #define MID_LEVEL_ENTRIES (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
92 #define HIGH_LEVEL_ENTRIES (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
95 // Maximum index in each table level before we need another table
97 #define MAX_LOW_INDEX LOW_LEVEL_ENTRIES
98 #define MAX_MID_INDEX (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
99 #define MAX_HIGH_INDEX (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
101 #define ExpChangeRundown(x, y, z) (ULONG_PTR)InterlockedCompareExchangePointer(&x->Ptr, (PVOID)y, (PVOID)z)
102 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
103 #define ExpSetRundown(x, y) InterlockedExchangePointer(&x->Ptr, (PVOID)y)
108 IN PSYSTEM_POOLTAG_INFORMATION SystemInformation
,
109 IN ULONG SystemInformationLength
,
110 IN OUT PULONG ReturnLength OPTIONAL
113 /* INITIALIZATION FUNCTIONS *************************************************/
125 Phase1Initialization(
131 ExpInitializePushLocks(VOID
);
135 ExRefreshTimeZoneInformation(
136 IN PLARGE_INTEGER SystemBootTime
141 ExpInitializeWorkerThreads(VOID
);
145 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap
);
149 ExpInitLookasideLists(VOID
);
153 ExInitializeSystemLookasideList(
154 IN PGENERAL_LOOKASIDE List
,
158 IN USHORT MaximumDepth
,
159 IN PLIST_ENTRY ListHead
164 ExpInitializeCallbacks(VOID
);
172 ExpInitializeExecutive(
174 IN PLOADER_PARAMETER_BLOCK LoaderBlock
179 ExpInitializeEventImplementation(VOID
);
183 ExpInitializeKeyedEventImplementation(VOID
);
187 ExpInitializeEventPairImplementation(VOID
);
191 ExpInitializeSemaphoreImplementation(VOID
);
195 ExpInitializeMutantImplementation(VOID
);
199 ExpInitializeTimerImplementation(VOID
);
203 ExpInitializeProfileImplementation(VOID
);
207 ExpResourceInitialization(VOID
);
211 ExInitPoolLookasidePointers(VOID
);
213 /* Callback Functions ********************************************************/
217 ExInitializeCallBack(
218 IN OUT PEX_CALLBACK Callback
221 PEX_CALLBACK_ROUTINE_BLOCK
224 IN PEX_CALLBACK_FUNCTION Function
,
231 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
236 ExCompareExchangeCallBack (
237 IN OUT PEX_CALLBACK CallBack
,
238 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock
,
239 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
242 PEX_CALLBACK_ROUTINE_BLOCK
244 ExReferenceCallBackBlock(
245 IN OUT PEX_CALLBACK CallBack
250 ExDereferenceCallBackBlock(
251 IN OUT PEX_CALLBACK CallBack
,
252 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
255 PEX_CALLBACK_FUNCTION
257 ExGetCallBackBlockRoutine(
258 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
263 ExGetCallBackBlockContext(
264 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
270 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
273 /* Rundown Functions ********************************************************/
277 ExfInitializeRundownProtection(
278 OUT PEX_RUNDOWN_REF RunRef
283 ExfReInitializeRundownProtection(
284 OUT PEX_RUNDOWN_REF RunRef
289 ExfAcquireRundownProtection(
290 IN OUT PEX_RUNDOWN_REF RunRef
295 ExfAcquireRundownProtectionEx(
296 IN OUT PEX_RUNDOWN_REF RunRef
,
302 ExfReleaseRundownProtection(
303 IN OUT PEX_RUNDOWN_REF RunRef
308 ExfReleaseRundownProtectionEx(
309 IN OUT PEX_RUNDOWN_REF RunRef
,
316 OUT PEX_RUNDOWN_REF RunRef
321 ExfWaitForRundownProtectionRelease(
322 IN OUT PEX_RUNDOWN_REF RunRef
325 /* HANDLE TABLE FUNCTIONS ***************************************************/
328 (NTAPI
*PEX_SWEEP_HANDLE_CALLBACK
)(
329 PHANDLE_TABLE_ENTRY HandleTableEntry
,
335 (NTAPI
*PEX_DUPLICATE_HANDLE_CALLBACK
)(
336 IN PEPROCESS Process
,
337 IN PHANDLE_TABLE HandleTable
,
338 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
339 IN PHANDLE_TABLE_ENTRY NewEntry
343 (NTAPI
*PEX_CHANGE_HANDLE_CALLBACK
)(
344 PHANDLE_TABLE_ENTRY HandleTableEntry
,
350 ExpInitializeHandleTables(
357 IN PEPROCESS Process OPTIONAL
362 ExUnlockHandleTableEntry(
363 IN PHANDLE_TABLE HandleTable
,
364 IN PHANDLE_TABLE_ENTRY HandleTableEntry
370 IN PHANDLE_TABLE HandleTable
,
371 IN PHANDLE_TABLE_ENTRY HandleTableEntry
376 ExDestroyHandleTable(
377 IN PHANDLE_TABLE HandleTable
,
378 IN PVOID DestroyHandleProcedure OPTIONAL
384 IN PHANDLE_TABLE HandleTable
,
386 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
391 ExMapHandleToPointer(
392 IN PHANDLE_TABLE HandleTable
,
399 IN PEPROCESS Process
,
400 IN PHANDLE_TABLE HandleTable
,
401 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
408 IN PHANDLE_TABLE HandleTable
,
410 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
417 IN PHANDLE_TABLE HandleTable
,
418 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
422 /* PSEH EXCEPTION HANDLING **************************************************/
426 ExSystemExceptionFilter(VOID
);
428 /* CALLBACKS *****************************************************************/
432 ExDoCallBack(IN OUT PEX_CALLBACK Callback
,
437 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock
;
438 PEX_CALLBACK_FUNCTION Function
;
440 /* Reference the block */
441 CallbackBlock
= ExReferenceCallBackBlock(Callback
);
444 /* Get the function */
445 Function
= ExGetCallBackBlockRoutine(CallbackBlock
);
447 /* Do the callback */
448 Function(Context
, Argument1
, Argument2
);
450 /* Now dereference it */
451 ExDereferenceCallBackBlock(Callback
, CallbackBlock
);
455 /* FAST REFS ******************************************************************/
459 ExGetObjectFastReference(IN EX_FAST_REF FastRef
)
461 /* Return the unbiased pointer */
462 return (PVOID
)(FastRef
.Value
& ~MAX_FAST_REFS
);
467 ExGetCountFastReference(IN EX_FAST_REF FastRef
)
469 /* Return the reference count */
470 return (ULONG
)FastRef
.RefCnt
;
475 ExInitializeFastReference(OUT PEX_FAST_REF FastRef
,
476 IN OPTIONAL PVOID Object
)
479 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
481 /* Check if an object is being set */
484 /* Clear the field */
485 FastRef
->Object
= NULL
;
489 /* Otherwise, we assume the object was referenced and is ready */
490 FastRef
->Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
496 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef
)
498 EX_FAST_REF OldValue
, NewValue
;
500 /* Start reference loop */
503 /* Get the current reference count */
507 /* Increase the reference count */
508 NewValue
.Value
= OldValue
.Value
- 1;
509 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
512 if (NewValue
.Object
!= OldValue
.Object
) continue;
519 /* Return the old value */
525 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef
,
528 EX_FAST_REF OldValue
, NewValue
;
531 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
533 /* Start update loop */
536 /* Get the current reference count */
539 /* Check if the current count is too high or if the pointer changed */
540 if (((OldValue
.RefCnt
+ MAX_FAST_REFS
) > MAX_FAST_REFS
) ||
541 ((OldValue
.Value
&~ MAX_FAST_REFS
) != (ULONG_PTR
)Object
))
547 /* Update the reference count */
548 NewValue
.Value
= OldValue
.Value
+ MAX_FAST_REFS
;
549 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
552 if (NewValue
.Object
!= OldValue
.Object
) continue;
564 ExReleaseFastReference(IN PEX_FAST_REF FastRef
,
567 EX_FAST_REF OldValue
, NewValue
;
570 ASSERT(Object
!= NULL
);
571 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
573 /* Start reference loop */
576 /* Get the current reference count */
579 /* Check if we're full if if the pointer changed */
580 if ((OldValue
.Value
^ (ULONG_PTR
)Object
) >= MAX_FAST_REFS
) return FALSE
;
582 /* Decrease the reference count */
583 NewValue
.Value
= OldValue
.Value
+ 1;
584 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
587 if (NewValue
.Object
!= OldValue
.Object
) continue;
599 ExSwapFastReference(IN PEX_FAST_REF FastRef
,
602 EX_FAST_REF NewValue
, OldValue
;
605 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
607 /* Check if an object is being set */
610 /* Clear the field */
611 NewValue
.Object
= NULL
;
615 /* Otherwise, we assume the object was referenced and is ready */
616 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
619 /* Update the object */
620 OldValue
.Object
= InterlockedExchangePointer(&FastRef
->Object
, NewValue
.Object
);
626 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef
,
630 EX_FAST_REF OldValue
, NewValue
;
632 /* Sanity check and start swap loop */
633 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
636 /* Get the current value */
639 /* Make sure there's enough references to swap */
640 if (!((OldValue
.Value
^ (ULONG_PTR
)OldObject
) <= MAX_FAST_REFS
)) break;
642 /* Check if we have an object to swap */
645 /* Set up the value with maximum fast references */
646 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
650 /* Write the object address itself (which is empty) */
651 NewValue
.Value
= (ULONG_PTR
)Object
;
654 /* Do the actual compare exchange */
655 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
658 if (NewValue
.Object
!= OldValue
.Object
) continue;
664 /* Return the old value */
668 /* RUNDOWN *******************************************************************/
671 * @name ExfAcquireRundownProtection
674 * The ExfAcquireRundownProtection routine acquires rundown protection for
675 * the specified descriptor.
678 * Pointer to a rundown reference descriptor.
680 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
682 * @remarks This is the internal macro for system use only.In case the rundown
683 * was active, then the slow-path will be called through the exported
689 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
691 ULONG_PTR Value
, NewValue
;
693 /* Get the current value and mask the active bit */
694 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
696 /* Add a reference */
697 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
699 /* Change the value */
700 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
701 if (NewValue
!= Value
)
703 /* Rundown was active, use long path */
704 return ExfAcquireRundownProtection(RunRef
);
712 * @name ExReleaseRundownProtection
715 * The ExReleaseRundownProtection routine releases rundown protection for
716 * the specified descriptor.
719 * Pointer to a rundown reference descriptor.
721 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
723 * @remarks This is the internal macro for system use only.In case the rundown
724 * was active, then the slow-path will be called through the exported
730 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
732 ULONG_PTR Value
, NewValue
;
734 /* Get the current value and mask the active bit */
735 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
737 /* Remove a reference */
738 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
740 /* Change the value */
741 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
743 /* Check if the rundown was active */
744 if (NewValue
!= Value
)
746 /* Rundown was active, use long path */
747 ExfReleaseRundownProtection(RunRef
);
752 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
757 * @name ExInitializeRundownProtection
760 * The ExInitializeRundownProtection routine initializes a rundown
761 * protection descriptor.
764 * Pointer to a rundown reference descriptor.
768 * @remarks This is the internal macro for system use only.
773 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
775 /* Set the count to zero */
780 * @name ExWaitForRundownProtectionRelease
783 * The ExWaitForRundownProtectionRelease routine waits until the specified
784 * rundown descriptor has been released.
787 * Pointer to a rundown reference descriptor.
791 * @remarks This is the internal macro for system use only. If a wait is actually
792 * necessary, then the slow path is taken through the exported function.
797 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
801 /* Set the active bit */
802 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
803 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
805 /* If the the rundown wasn't already active, then take the long path */
806 ExfWaitForRundownProtectionRelease(RunRef
);
811 * @name ExRundownCompleted
814 * The ExRundownCompleted routine completes the rundown of the specified
815 * descriptor by setting the active bit.
818 * Pointer to a rundown reference descriptor.
822 * @remarks This is the internal macro for system use only.
827 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
830 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
832 /* Mark the counter as active */
833 ExpSetRundown(RunRef
, EX_RUNDOWN_ACTIVE
);
836 /* PUSHLOCKS *****************************************************************/
838 /* FIXME: VERIFY THESE! */
843 IN PEX_PUSH_LOCK PushLock
,
850 IN PEX_PUSH_LOCK PushLock
,
851 IN PVOID CurrentWaitBlock
856 ExWaitForUnblockPushLock(
857 IN PEX_PUSH_LOCK PushLock
,
862 * @name _ExInitializePushLock
865 * The _ExInitializePushLock macro initializes a PushLock.
868 * Pointer to the pushlock which is to be initialized.
877 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock
)
879 /* Set the value to 0 */
882 #define ExInitializePushLock _ExInitializePushLock
885 * @name ExAcquirePushLockExclusive
888 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
891 * Pointer to the pushlock which is to be acquired.
895 * @remarks The function attempts the quickest route to acquire the lock, which is
896 * to simply set the lock bit.
897 * However, if the pushlock is already shared, the slower path is taken.
899 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
900 * This macro should usually be paired up with KeAcquireCriticalRegion.
905 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
907 /* Try acquiring the lock */
908 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
910 /* Someone changed it, use the slow path */
911 ExfAcquirePushLockExclusive(PushLock
);
915 ASSERT(PushLock
->Locked
);
919 * @name ExTryToAcquirePushLockExclusive
922 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
925 * Pointer to the pushlock which is to be acquired.
929 * @remarks The function attempts the quickest route to acquire the lock, which is
930 * to simply set the lock bit.
931 * However, if the pushlock is already shared, the slower path is taken.
933 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
934 * This macro should usually be paired up with KeAcquireCriticalRegion.
939 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
941 /* Try acquiring the lock */
942 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
949 ASSERT (PushLock
->Locked
);
954 * @name ExAcquirePushLockShared
957 * The ExAcquirePushLockShared macro acquires a shared PushLock.
960 * Pointer to the pushlock which is to be acquired.
964 * @remarks The function attempts the quickest route to acquire the lock, which is
965 * to simply set the lock bit and set the share count to one.
966 * However, if the pushlock is already shared, the slower path is taken.
968 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
969 * This macro should usually be paired up with KeAcquireCriticalRegion.
974 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
976 EX_PUSH_LOCK NewValue
;
978 /* Try acquiring the lock */
979 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
980 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
982 /* Someone changed it, use the slow path */
983 ExfAcquirePushLockShared(PushLock
);
987 ASSERT(PushLock
->Locked
);
988 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
992 * @name ExConvertPushLockSharedToExclusive
995 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
996 * pushlock to a shared pushlock.
999 * Pointer to the pushlock which is to be converted.
1001 * @return FALSE if conversion failed, TRUE otherwise.
1003 * @remarks The function attempts the quickest route to convert the lock, which is
1004 * to simply set the lock bit and remove any other bits.
1009 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
1011 EX_PUSH_LOCK OldValue
;
1013 /* Set the expected old value */
1014 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1016 /* Try converting the lock */
1017 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
1020 /* Conversion failed */
1025 ASSERT(PushLock
->Locked
);
1030 * @name ExWaitOnPushLock
1033 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1036 * Pointer to a pushlock.
1040 * @remarks The function attempts to get any exclusive waiters out of their slow
1041 * path by forcing an instant acquire/release operation.
1043 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1048 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
1050 /* Check if we're locked */
1051 if (PushLock
->Locked
)
1053 /* Acquire the lock */
1054 ExfAcquirePushLockExclusive(PushLock
);
1055 ASSERT(PushLock
->Locked
);
1058 ExfReleasePushLockExclusive(PushLock
);
1063 * @name ExReleasePushLockShared
1066 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
1069 * Pointer to a previously acquired pushlock.
1073 * @remarks The function attempts the quickest route to release the lock, which is
1074 * to simply decrease the share count and remove the lock bit.
1075 * However, if the pushlock is being waited on then the long path is taken.
1077 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1078 * This macro should usually be paired up with KeLeaveCriticalRegion.
1083 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
1085 EX_PUSH_LOCK OldValue
;
1088 ASSERT(PushLock
->Locked
);
1089 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
> 0);
1091 /* Try to clear the pushlock */
1092 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1093 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
1095 /* There are still other people waiting on it */
1096 ExfReleasePushLockShared(PushLock
);
1101 * @name ExReleasePushLockExclusive
1104 * The ExReleasePushLockExclusive macro releases a previously
1105 * exclusively acquired PushLock.
1108 * Pointer to a previously acquired pushlock.
1112 * @remarks The function attempts the quickest route to release the lock, which is
1113 * to simply clear the locked bit.
1114 * However, if the pushlock is being waited on, the slow path is taken
1115 * in an attempt to wake up the lock.
1117 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1118 * This macro should usually be paired up with KeLeaveCriticalRegion.
1123 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1125 EX_PUSH_LOCK OldValue
;
1128 ASSERT(PushLock
->Locked
);
1129 ASSERT(PushLock
->Waiting
|| PushLock
->Shared
== 0);
1131 /* Unlock the pushlock */
1132 OldValue
.Value
= InterlockedExchangeAddSizeT((PSIZE_T
)PushLock
,
1133 -(SSIZE_T
)EX_PUSH_LOCK_LOCK
);
1136 ASSERT(OldValue
.Locked
);
1137 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
1139 /* Check if anyone is waiting on it and it's not already waking*/
1140 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
1143 ExfTryToWakePushLock(PushLock
);
1148 * @name ExReleasePushLock
1151 * The ExReleasePushLock macro releases a previously acquired PushLock.
1154 * Pointer to a previously acquired pushlock.
1158 * @remarks The function attempts the quickest route to release the lock, which is
1159 * to simply clear all the fields and decrease the share count if required.
1160 * However, if the pushlock is being waited on then the long path is taken.
1162 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1163 * This macro should usually be paired up with KeLeaveCriticalRegion.
1168 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
1170 EX_PUSH_LOCK OldValue
= *PushLock
;
1171 EX_PUSH_LOCK NewValue
;
1174 ASSERT(OldValue
.Locked
);
1176 /* Check if the pushlock is shared */
1177 if (OldValue
.Shared
> 1)
1179 /* Decrease the share count */
1180 NewValue
.Value
= OldValue
.Value
- EX_PUSH_LOCK_SHARE_INC
;
1184 /* Clear the pushlock entirely */
1188 /* Check if nobody is waiting on us and try clearing the lock here */
1189 if ((OldValue
.Waiting
) ||
1190 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
1193 /* We have waiters, use the long path */
1194 ExfReleasePushLock(PushLock
);
1198 /* FAST MUTEX INLINES *********************************************************/
1202 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex
)
1204 PKTHREAD Thread
= KeGetCurrentThread();
1207 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1208 (Thread
->CombinedApcDisable
!= 0) ||
1209 (Thread
->Teb
== NULL
) ||
1210 (Thread
->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1211 ASSERT(FastMutex
->Owner
!= Thread
);
1213 /* Decrease the count */
1214 if (InterlockedDecrement(&FastMutex
->Count
))
1216 /* Someone is still holding it, use slow path */
1217 KiAcquireFastMutex(FastMutex
);
1221 FastMutex
->Owner
= Thread
;
1226 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1228 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1229 (KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
1230 (KeGetCurrentThread()->Teb
== NULL
) ||
1231 (KeGetCurrentThread()->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1232 ASSERT(FastMutex
->Owner
== KeGetCurrentThread());
1234 /* Erase the owner */
1235 FastMutex
->Owner
= NULL
;
1237 /* Increase the count */
1238 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1240 /* Someone was waiting for it, signal the waiter */
1241 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1247 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
1250 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1252 /* Raise IRQL to APC */
1253 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1255 /* Decrease the count */
1256 if (InterlockedDecrement(&FastMutex
->Count
))
1258 /* Someone is still holding it, use slow path */
1259 KiAcquireFastMutex(FastMutex
);
1262 /* Set the owner and IRQL */
1263 FastMutex
->Owner
= KeGetCurrentThread();
1264 FastMutex
->OldIrql
= OldIrql
;
1269 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1272 ASSERT(KeGetCurrentIrql() == APC_LEVEL
);
1274 /* Erase the owner */
1275 FastMutex
->Owner
= NULL
;
1276 OldIrql
= (KIRQL
)FastMutex
->OldIrql
;
1278 /* Increase the count */
1279 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1281 /* Someone was waiting for it, signal the waiter */
1282 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1285 /* Lower IRQL back */
1286 KeLowerIrql(OldIrql
);
1291 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1294 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1296 /* Raise to APC_LEVEL */
1297 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1299 /* Check if we can quickly acquire it */
1300 if (InterlockedCompareExchange(&FastMutex
->Count
, 0, 1) == 1)
1302 /* We have, set us as owners */
1303 FastMutex
->Owner
= KeGetCurrentThread();
1304 FastMutex
->OldIrql
= OldIrql
;
1309 /* Acquire attempt failed */
1310 KeLowerIrql(OldIrql
);
1318 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1320 /* Enter the Critical Region */
1321 KeEnterCriticalRegion();
1323 /* Acquire the mutex unsafely */
1324 _ExAcquireFastMutexUnsafe(FastMutex
);
1329 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex
)
1331 /* Release the mutex unsafely */
1332 _ExReleaseFastMutexUnsafe(FastMutex
);
1334 /* Leave the critical region */
1335 KeLeaveCriticalRegion();
1338 /* OTHER FUNCTIONS **********************************************************/
1342 ExTryToAcquireResourceExclusiveLite(
1343 IN PERESOURCE Resource
1347 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
);
1351 ExAcquireTimeRefreshLock(BOOLEAN Wait
);
1355 ExReleaseTimeRefreshLock(VOID
);
1359 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime
,
1360 IN ULONG MaxSepInSeconds
);
1364 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
);
1368 ExTimerRundown(VOID
);
1373 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1379 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1382 #define InterlockedDecrementUL(Addend) \
1383 (ULONG)InterlockedDecrement((PLONG)(Addend))
1385 #define InterlockedIncrementUL(Addend) \
1386 (ULONG)InterlockedIncrement((PLONG)(Addend))
1388 #define InterlockedExchangeUL(Target, Value) \
1389 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1391 #define InterlockedExchangeAddUL(Addend, Value) \
1392 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1394 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1395 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1397 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1398 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))