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 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
;
33 * NT/Cm Version Info variables
35 extern ULONG NtMajorVersion
;
36 extern ULONG NtMinorVersion
;
37 extern ULONG NtBuildNumber
;
38 extern ULONG CmNtSpBuildNumber
;
39 extern ULONG CmNtCSDVersion
;
40 extern ULONG CmNtCSDReleaseType
;
41 extern UNICODE_STRING CmVersionString
;
42 extern UNICODE_STRING CmCSDVersionString
;
43 extern CHAR NtBuildLab
[];
47 * WinDBG Debugger Worker State Machine data (see dbgctrl.c)
49 typedef enum _WINKD_WORKER_STATE
53 WinKdWorkerInitialized
56 extern WORK_QUEUE_ITEM ExpDebuggerWorkItem
;
57 extern WINKD_WORKER_STATE ExpDebuggerWork
;
58 extern PEPROCESS ExpDebuggerProcessAttach
;
59 extern PEPROCESS ExpDebuggerProcessKill
;
60 extern ULONG_PTR ExpDebuggerPageIn
;
61 VOID NTAPI
ExpDebuggerWorker(IN PVOID Context
);
62 // #endif /* _WINKD_ */
65 #define HANDLE_LOW_BITS (PAGE_SHIFT - 4)
66 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 3)
68 #define HANDLE_LOW_BITS (PAGE_SHIFT - 3)
69 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2)
71 #define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - 31)
73 typedef union _EXHANDLE
83 ULONG_PTR LowIndex
:HANDLE_LOW_BITS
;
84 ULONG_PTR MidIndex
:HANDLE_HIGH_BITS
;
85 ULONG_PTR HighIndex
:HANDLE_HIGH_BITS
;
86 ULONG_PTR KernelFlag
:KERNEL_FLAG_BITS
;
88 HANDLE GenericHandleOverlay
;
90 } EXHANDLE
, *PEXHANDLE
;
92 typedef struct _ETIMER
97 LIST_ENTRY ActiveTimerListEntry
;
100 BOOLEAN ApcAssociated
;
102 LIST_ENTRY WakeTimerListEntry
;
107 PCALLBACK_OBJECT
*CallbackObject
;
111 typedef struct _HARDERROR_USER_PARAMETERS
113 ULONG_PTR Parameters
[MAXIMUM_HARDERROR_PARAMETERS
];
114 UNICODE_STRING Strings
[MAXIMUM_HARDERROR_PARAMETERS
];
115 WCHAR Buffer
[ANYSIZE_ARRAY
];
116 } HARDERROR_USER_PARAMETERS
, *PHARDERROR_USER_PARAMETERS
;
118 #define MAX_FAST_REFS 7
120 #define ExAcquireRundownProtection _ExAcquireRundownProtection
121 #define ExReleaseRundownProtection _ExReleaseRundownProtection
122 #define ExInitializeRundownProtection _ExInitializeRundownProtection
123 #define ExWaitForRundownProtectionRelease _ExWaitForRundownProtectionRelease
124 #define ExRundownCompleted _ExRundownCompleted
125 #define ExGetPreviousMode KeGetPreviousMode
129 // Various bits tagged on the handle or handle table
131 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT 1
132 #define FREE_HANDLE_MASK -1
135 // Number of entries in each table level
137 #define LOW_LEVEL_ENTRIES (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
138 #define MID_LEVEL_ENTRIES (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
139 #define HIGH_LEVEL_ENTRIES (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
142 // Maximum index in each table level before we need another table
144 #define MAX_LOW_INDEX LOW_LEVEL_ENTRIES
145 #define MAX_MID_INDEX (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
146 #define MAX_HIGH_INDEX (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
148 #define ExpChangeRundown(x, y, z) (ULONG_PTR)InterlockedCompareExchangePointer(&x->Ptr, (PVOID)y, (PVOID)z)
149 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
150 #define ExpSetRundown(x, y) InterlockedExchangePointer(&x->Ptr, (PVOID)y)
155 IN PSYSTEM_POOLTAG_INFORMATION SystemInformation
,
156 IN ULONG SystemInformationLength
,
157 IN OUT PULONG ReturnLength OPTIONAL
160 /* INITIALIZATION FUNCTIONS *************************************************/
172 Phase1Initialization(
178 ExpInitializePushLocks(VOID
);
182 ExRefreshTimeZoneInformation(
183 IN PLARGE_INTEGER SystemBootTime
188 ExpInitializeWorkerThreads(VOID
);
192 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap
);
196 ExpInitLookasideLists(VOID
);
200 ExInitializeSystemLookasideList(
201 IN PGENERAL_LOOKASIDE List
,
205 IN USHORT MaximumDepth
,
206 IN PLIST_ENTRY ListHead
211 ExpInitializeCallbacks(VOID
);
219 ExpInitializeExecutive(
221 IN PLOADER_PARAMETER_BLOCK LoaderBlock
226 ExpInitializeEventImplementation(VOID
);
230 ExpInitializeKeyedEventImplementation(VOID
);
234 ExpInitializeEventPairImplementation(VOID
);
238 ExpInitializeSemaphoreImplementation(VOID
);
242 ExpInitializeMutantImplementation(VOID
);
246 ExpInitializeTimerImplementation(VOID
);
250 ExpInitializeProfileImplementation(VOID
);
254 ExpResourceInitialization(VOID
);
258 ExInitPoolLookasidePointers(VOID
);
260 /* Callback Functions ********************************************************/
264 ExInitializeCallBack(
265 IN OUT PEX_CALLBACK Callback
268 PEX_CALLBACK_ROUTINE_BLOCK
271 IN PEX_CALLBACK_FUNCTION Function
,
278 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
283 ExCompareExchangeCallBack (
284 IN OUT PEX_CALLBACK CallBack
,
285 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock
,
286 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
289 PEX_CALLBACK_ROUTINE_BLOCK
291 ExReferenceCallBackBlock(
292 IN OUT PEX_CALLBACK CallBack
297 ExDereferenceCallBackBlock(
298 IN OUT PEX_CALLBACK CallBack
,
299 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
302 PEX_CALLBACK_FUNCTION
304 ExGetCallBackBlockRoutine(
305 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
310 ExGetCallBackBlockContext(
311 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
317 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
320 /* Rundown Functions ********************************************************/
324 ExfInitializeRundownProtection(
325 OUT PEX_RUNDOWN_REF RunRef
330 ExfReInitializeRundownProtection(
331 OUT PEX_RUNDOWN_REF RunRef
336 ExfAcquireRundownProtection(
337 IN OUT PEX_RUNDOWN_REF RunRef
342 ExfAcquireRundownProtectionEx(
343 IN OUT PEX_RUNDOWN_REF RunRef
,
349 ExfReleaseRundownProtection(
350 IN OUT PEX_RUNDOWN_REF RunRef
355 ExfReleaseRundownProtectionEx(
356 IN OUT PEX_RUNDOWN_REF RunRef
,
363 OUT PEX_RUNDOWN_REF RunRef
368 ExfWaitForRundownProtectionRelease(
369 IN OUT PEX_RUNDOWN_REF RunRef
372 /* HANDLE TABLE FUNCTIONS ***************************************************/
375 (NTAPI
*PEX_SWEEP_HANDLE_CALLBACK
)(
376 PHANDLE_TABLE_ENTRY HandleTableEntry
,
382 (NTAPI
*PEX_DUPLICATE_HANDLE_CALLBACK
)(
383 IN PEPROCESS Process
,
384 IN PHANDLE_TABLE HandleTable
,
385 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
386 IN PHANDLE_TABLE_ENTRY NewEntry
390 (NTAPI
*PEX_CHANGE_HANDLE_CALLBACK
)(
391 PHANDLE_TABLE_ENTRY HandleTableEntry
,
397 ExpInitializeHandleTables(
404 IN PEPROCESS Process OPTIONAL
409 ExUnlockHandleTableEntry(
410 IN PHANDLE_TABLE HandleTable
,
411 IN PHANDLE_TABLE_ENTRY HandleTableEntry
417 IN PHANDLE_TABLE HandleTable
,
418 IN PHANDLE_TABLE_ENTRY HandleTableEntry
423 ExDestroyHandleTable(
424 IN PHANDLE_TABLE HandleTable
,
425 IN PVOID DestroyHandleProcedure OPTIONAL
431 IN PHANDLE_TABLE HandleTable
,
433 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
438 ExMapHandleToPointer(
439 IN PHANDLE_TABLE HandleTable
,
446 IN PEPROCESS Process
,
447 IN PHANDLE_TABLE HandleTable
,
448 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure
,
455 IN PHANDLE_TABLE HandleTable
,
457 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine
,
464 IN PHANDLE_TABLE HandleTable
,
465 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure
,
469 /* PSEH EXCEPTION HANDLING **************************************************/
473 ExSystemExceptionFilter(VOID
);
475 /* CALLBACKS *****************************************************************/
479 ExDoCallBack(IN OUT PEX_CALLBACK Callback
,
484 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock
;
485 PEX_CALLBACK_FUNCTION Function
;
487 /* Reference the block */
488 CallbackBlock
= ExReferenceCallBackBlock(Callback
);
491 /* Get the function */
492 Function
= ExGetCallBackBlockRoutine(CallbackBlock
);
494 /* Do the callback */
495 Function(Context
, Argument1
, Argument2
);
497 /* Now dereference it */
498 ExDereferenceCallBackBlock(Callback
, CallbackBlock
);
502 /* FAST REFS ******************************************************************/
506 ExGetObjectFastReference(IN EX_FAST_REF FastRef
)
508 /* Return the unbiased pointer */
509 return (PVOID
)(FastRef
.Value
& ~MAX_FAST_REFS
);
514 ExGetCountFastReference(IN EX_FAST_REF FastRef
)
516 /* Return the reference count */
517 return (ULONG
)FastRef
.RefCnt
;
522 ExInitializeFastReference(OUT PEX_FAST_REF FastRef
,
523 IN OPTIONAL PVOID Object
)
526 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
528 /* Check if an object is being set */
531 /* Clear the field */
532 FastRef
->Object
= NULL
;
536 /* Otherwise, we assume the object was referenced and is ready */
537 FastRef
->Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
543 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef
)
545 EX_FAST_REF OldValue
, NewValue
;
547 /* Start reference loop */
550 /* Get the current reference count */
554 /* Increase the reference count */
555 NewValue
.Value
= OldValue
.Value
- 1;
556 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
559 if (NewValue
.Object
!= OldValue
.Object
) continue;
566 /* Return the old value */
572 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef
,
575 EX_FAST_REF OldValue
, NewValue
;
578 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
580 /* Start update loop */
583 /* Get the current reference count */
586 /* Check if the current count is too high or if the pointer changed */
587 if (((OldValue
.RefCnt
+ MAX_FAST_REFS
) > MAX_FAST_REFS
) ||
588 ((OldValue
.Value
&~ MAX_FAST_REFS
) != (ULONG_PTR
)Object
))
594 /* Update the reference count */
595 NewValue
.Value
= OldValue
.Value
+ MAX_FAST_REFS
;
596 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
599 if (NewValue
.Object
!= OldValue
.Object
) continue;
611 ExReleaseFastReference(IN PEX_FAST_REF FastRef
,
614 EX_FAST_REF OldValue
, NewValue
;
617 ASSERT(Object
!= NULL
);
618 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
620 /* Start reference loop */
623 /* Get the current reference count */
626 /* Check if we're full if if the pointer changed */
627 if ((OldValue
.Value
^ (ULONG_PTR
)Object
) >= MAX_FAST_REFS
) return FALSE
;
629 /* Decrease the reference count */
630 NewValue
.Value
= OldValue
.Value
+ 1;
631 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
634 if (NewValue
.Object
!= OldValue
.Object
) continue;
646 ExSwapFastReference(IN PEX_FAST_REF FastRef
,
649 EX_FAST_REF NewValue
, OldValue
;
652 ASSERT((((ULONG_PTR
)Object
) & MAX_FAST_REFS
) == 0);
654 /* Check if an object is being set */
657 /* Clear the field */
658 NewValue
.Object
= NULL
;
662 /* Otherwise, we assume the object was referenced and is ready */
663 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
666 /* Update the object */
667 OldValue
.Object
= InterlockedExchangePointer(&FastRef
->Object
, NewValue
.Object
);
673 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef
,
677 EX_FAST_REF OldValue
, NewValue
;
679 /* Sanity check and start swap loop */
680 ASSERT(!(((ULONG_PTR
)Object
) & MAX_FAST_REFS
));
683 /* Get the current value */
686 /* Make sure there's enough references to swap */
687 if (!((OldValue
.Value
^ (ULONG_PTR
)OldObject
) <= MAX_FAST_REFS
)) break;
689 /* Check if we have an object to swap */
692 /* Set up the value with maximum fast references */
693 NewValue
.Value
= (ULONG_PTR
)Object
| MAX_FAST_REFS
;
697 /* Write the object address itself (which is empty) */
698 NewValue
.Value
= (ULONG_PTR
)Object
;
701 /* Do the actual compare exchange */
702 NewValue
.Object
= ExpChangePushlock(&FastRef
->Object
,
705 if (NewValue
.Object
!= OldValue
.Object
) continue;
711 /* Return the old value */
715 /* RUNDOWN *******************************************************************/
718 * @name ExfAcquireRundownProtection
721 * The ExfAcquireRundownProtection routine acquires rundown protection for
722 * the specified descriptor.
725 * Pointer to a rundown reference descriptor.
727 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
729 * @remarks This is the internal macro for system use only.In case the rundown
730 * was active, then the slow-path will be called through the exported
736 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
738 ULONG_PTR Value
, NewValue
;
740 /* Get the current value and mask the active bit */
741 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
743 /* Add a reference */
744 NewValue
= Value
+ EX_RUNDOWN_COUNT_INC
;
746 /* Change the value */
747 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
748 if (NewValue
!= Value
)
750 /* Rundown was active, use long path */
751 return ExfAcquireRundownProtection(RunRef
);
759 * @name ExReleaseRundownProtection
762 * The ExReleaseRundownProtection routine releases rundown protection for
763 * the specified descriptor.
766 * Pointer to a rundown reference descriptor.
768 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
770 * @remarks This is the internal macro for system use only.In case the rundown
771 * was active, then the slow-path will be called through the exported
777 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
779 ULONG_PTR Value
, NewValue
;
781 /* Get the current value and mask the active bit */
782 Value
= RunRef
->Count
&~ EX_RUNDOWN_ACTIVE
;
784 /* Remove a reference */
785 NewValue
= Value
- EX_RUNDOWN_COUNT_INC
;
787 /* Change the value */
788 NewValue
= ExpChangeRundown(RunRef
, NewValue
, Value
);
790 /* Check if the rundown was active */
791 if (NewValue
!= Value
)
793 /* Rundown was active, use long path */
794 ExfReleaseRundownProtection(RunRef
);
799 ASSERT((Value
>= EX_RUNDOWN_COUNT_INC
) || (KeNumberProcessors
> 1));
804 * @name ExInitializeRundownProtection
807 * The ExInitializeRundownProtection routine initializes a rundown
808 * protection descriptor.
811 * Pointer to a rundown reference descriptor.
815 * @remarks This is the internal macro for system use only.
820 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef
)
822 /* Set the count to zero */
827 * @name ExWaitForRundownProtectionRelease
830 * The ExWaitForRundownProtectionRelease routine waits until the specified
831 * rundown descriptor has been released.
834 * Pointer to a rundown reference descriptor.
838 * @remarks This is the internal macro for system use only. If a wait is actually
839 * necessary, then the slow path is taken through the exported function.
844 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef
)
848 /* Set the active bit */
849 Value
= ExpChangeRundown(RunRef
, EX_RUNDOWN_ACTIVE
, 0);
850 if ((Value
) && (Value
!= EX_RUNDOWN_ACTIVE
))
852 /* If the the rundown wasn't already active, then take the long path */
853 ExfWaitForRundownProtectionRelease(RunRef
);
858 * @name ExRundownCompleted
861 * The ExRundownCompleted routine completes the rundown of the specified
862 * descriptor by setting the active bit.
865 * Pointer to a rundown reference descriptor.
869 * @remarks This is the internal macro for system use only.
874 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef
)
877 ASSERT((RunRef
->Count
& EX_RUNDOWN_ACTIVE
) != 0);
879 /* Mark the counter as active */
880 ExpSetRundown(RunRef
, EX_RUNDOWN_ACTIVE
);
883 /* PUSHLOCKS *****************************************************************/
885 /* FIXME: VERIFY THESE! */
890 IN PEX_PUSH_LOCK PushLock
,
897 IN PEX_PUSH_LOCK PushLock
,
898 IN PVOID CurrentWaitBlock
903 ExWaitForUnblockPushLock(
904 IN PEX_PUSH_LOCK PushLock
,
909 * @name _ExInitializePushLock
912 * The _ExInitializePushLock macro initializes a PushLock.
915 * Pointer to the pushlock which is to be initialized.
924 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock
)
926 /* Set the value to 0 */
929 #define ExInitializePushLock _ExInitializePushLock
932 * @name ExAcquirePushLockExclusive
935 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
938 * Pointer to the pushlock which is to be acquired.
942 * @remarks The function attempts the quickest route to acquire the lock, which is
943 * to simply set the lock bit.
944 * However, if the pushlock is already shared, the slower path is taken.
946 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
947 * This macro should usually be paired up with KeAcquireCriticalRegion.
952 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
954 /* Try acquiring the lock */
955 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
957 /* Someone changed it, use the slow path */
958 ExfAcquirePushLockExclusive(PushLock
);
962 ASSERT(PushLock
->Locked
);
966 * @name ExTryToAcquirePushLockExclusive
969 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
972 * Pointer to the pushlock which is to be acquired.
976 * @remarks The function attempts the quickest route to acquire the lock, which is
977 * to simply set the lock bit.
978 * However, if the pushlock is already shared, the slower path is taken.
980 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
981 * This macro should usually be paired up with KeAcquireCriticalRegion.
986 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock
)
988 /* Try acquiring the lock */
989 if (InterlockedBitTestAndSet((PLONG
)PushLock
, EX_PUSH_LOCK_LOCK_V
))
996 ASSERT (PushLock
->Locked
);
1001 * @name ExAcquirePushLockShared
1004 * The ExAcquirePushLockShared macro acquires a shared PushLock.
1007 * Pointer to the pushlock which is to be acquired.
1011 * @remarks The function attempts the quickest route to acquire the lock, which is
1012 * to simply set the lock bit and set the share count to one.
1013 * However, if the pushlock is already shared, the slower path is taken.
1015 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1016 * This macro should usually be paired up with KeAcquireCriticalRegion.
1021 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock
)
1023 EX_PUSH_LOCK NewValue
;
1025 /* Try acquiring the lock */
1026 NewValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1027 if (ExpChangePushlock(PushLock
, NewValue
.Ptr
, 0))
1029 /* Someone changed it, use the slow path */
1030 ExfAcquirePushLockShared(PushLock
);
1034 ASSERT(PushLock
->Locked
);
1038 * @name ExConvertPushLockSharedToExclusive
1041 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
1042 * pushlock to a shared pushlock.
1045 * Pointer to the pushlock which is to be converted.
1047 * @return FALSE if conversion failed, TRUE otherwise.
1049 * @remarks The function attempts the quickest route to convert the lock, which is
1050 * to simply set the lock bit and remove any other bits.
1055 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock
)
1057 EX_PUSH_LOCK OldValue
;
1059 /* Set the expected old value */
1060 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1062 /* Try converting the lock */
1063 if (ExpChangePushlock(PushLock
, EX_PUSH_LOCK_LOCK
, OldValue
.Value
) !=
1066 /* Conversion failed */
1071 ASSERT(PushLock
->Locked
);
1076 * @name ExWaitOnPushLock
1079 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1082 * Pointer to a pushlock.
1086 * @remarks The function attempts to get any exclusive waiters out of their slow
1087 * path by forcing an instant acquire/release operation.
1089 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1094 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock
)
1096 /* Check if we're locked */
1097 if (PushLock
->Locked
)
1099 /* Acquire the lock */
1100 ExfAcquirePushLockExclusive(PushLock
);
1101 ASSERT(PushLock
->Locked
);
1104 ExfReleasePushLockExclusive(PushLock
);
1109 * @name ExReleasePushLockShared
1112 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
1115 * Pointer to a previously acquired pushlock.
1119 * @remarks The function attempts the quickest route to release the lock, which is
1120 * to simply decrease the share count and remove the lock bit.
1121 * However, if the pushlock is being waited on then the long path is taken.
1123 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1124 * This macro should usually be paired up with KeLeaveCriticalRegion.
1129 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock
)
1131 EX_PUSH_LOCK OldValue
;
1134 ASSERT(PushLock
->Locked
);
1136 /* Try to clear the pushlock */
1137 OldValue
.Value
= EX_PUSH_LOCK_LOCK
| EX_PUSH_LOCK_SHARE_INC
;
1138 if (ExpChangePushlock(PushLock
, 0, OldValue
.Ptr
) != OldValue
.Ptr
)
1140 /* There are still other people waiting on it */
1141 ExfReleasePushLockShared(PushLock
);
1146 * @name ExReleasePushLockExclusive
1149 * The ExReleasePushLockExclusive macro releases a previously
1150 * exclusively acquired PushLock.
1153 * Pointer to a previously acquired pushlock.
1157 * @remarks The function attempts the quickest route to release the lock, which is
1158 * to simply clear the locked bit.
1159 * However, if the pushlock is being waited on, the slow path is taken
1160 * in an attempt to wake up the lock.
1162 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1163 * This macro should usually be paired up with KeLeaveCriticalRegion.
1168 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock
)
1170 EX_PUSH_LOCK OldValue
;
1173 ASSERT(PushLock
->Locked
);
1175 /* Unlock the pushlock */
1176 OldValue
.Value
= InterlockedExchangeAddSizeT((PSIZE_T
)PushLock
,
1177 -(SSIZE_T
)EX_PUSH_LOCK_LOCK
);
1180 ASSERT(OldValue
.Locked
);
1181 ASSERT(OldValue
.Waiting
|| OldValue
.Shared
== 0);
1183 /* Check if anyone is waiting on it and it's not already waking*/
1184 if ((OldValue
.Waiting
) && !(OldValue
.Waking
))
1187 ExfTryToWakePushLock(PushLock
);
1192 * @name ExReleasePushLock
1195 * The ExReleasePushLock macro releases a previously acquired PushLock.
1198 * Pointer to a previously acquired pushlock.
1202 * @remarks The function attempts the quickest route to release the lock, which is
1203 * to simply clear all the fields and decrease the share count if required.
1204 * However, if the pushlock is being waited on then the long path is taken.
1206 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1207 * This macro should usually be paired up with KeLeaveCriticalRegion.
1212 ExReleasePushLock(PEX_PUSH_LOCK PushLock
)
1214 EX_PUSH_LOCK OldValue
= *PushLock
;
1215 EX_PUSH_LOCK NewValue
;
1218 ASSERT(OldValue
.Locked
);
1220 /* Check if the pushlock is shared */
1221 if (OldValue
.Shared
> 1)
1223 /* Decrease the share count */
1224 NewValue
.Value
= OldValue
.Value
- EX_PUSH_LOCK_SHARE_INC
;
1228 /* Clear the pushlock entirely */
1232 /* Check if nobody is waiting on us and try clearing the lock here */
1233 if ((OldValue
.Waiting
) ||
1234 (ExpChangePushlock(PushLock
, NewValue
.Ptr
, OldValue
.Ptr
) !=
1237 /* We have waiters, use the long path */
1238 ExfReleasePushLock(PushLock
);
1242 /* FAST MUTEX INLINES *********************************************************/
1246 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex
)
1248 PKTHREAD Thread
= KeGetCurrentThread();
1251 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1252 (Thread
->CombinedApcDisable
!= 0) ||
1253 (Thread
->Teb
== NULL
) ||
1254 (Thread
->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1255 ASSERT(FastMutex
->Owner
!= Thread
);
1257 /* Decrease the count */
1258 if (InterlockedDecrement(&FastMutex
->Count
))
1260 /* Someone is still holding it, use slow path */
1261 KiAcquireFastMutex(FastMutex
);
1265 FastMutex
->Owner
= Thread
;
1270 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1272 ASSERT((KeGetCurrentIrql() == APC_LEVEL
) ||
1273 (KeGetCurrentThread()->CombinedApcDisable
!= 0) ||
1274 (KeGetCurrentThread()->Teb
== NULL
) ||
1275 (KeGetCurrentThread()->Teb
>= (PTEB
)MM_SYSTEM_RANGE_START
));
1276 ASSERT(FastMutex
->Owner
== KeGetCurrentThread());
1278 /* Erase the owner */
1279 FastMutex
->Owner
= NULL
;
1281 /* Increase the count */
1282 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1284 /* Someone was waiting for it, signal the waiter */
1285 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1291 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex
)
1294 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1296 /* Raise IRQL to APC */
1297 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1299 /* Decrease the count */
1300 if (InterlockedDecrement(&FastMutex
->Count
))
1302 /* Someone is still holding it, use slow path */
1303 KiAcquireFastMutex(FastMutex
);
1306 /* Set the owner and IRQL */
1307 FastMutex
->Owner
= KeGetCurrentThread();
1308 FastMutex
->OldIrql
= OldIrql
;
1313 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1316 ASSERT(KeGetCurrentIrql() == APC_LEVEL
);
1318 /* Erase the owner */
1319 FastMutex
->Owner
= NULL
;
1320 OldIrql
= (KIRQL
)FastMutex
->OldIrql
;
1322 /* Increase the count */
1323 if (InterlockedIncrement(&FastMutex
->Count
) <= 0)
1325 /* Someone was waiting for it, signal the waiter */
1326 KeSetEventBoostPriority(&FastMutex
->Event
, NULL
);
1329 /* Lower IRQL back */
1330 KeLowerIrql(OldIrql
);
1335 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
)
1338 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
1340 /* Raise to APC_LEVEL */
1341 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1343 /* Check if we can quickly acquire it */
1344 if (InterlockedCompareExchange(&FastMutex
->Count
, 0, 1) == 1)
1346 /* We have, set us as owners */
1347 FastMutex
->Owner
= KeGetCurrentThread();
1348 FastMutex
->OldIrql
= OldIrql
;
1353 /* Acquire attempt failed */
1354 KeLowerIrql(OldIrql
);
1362 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex
)
1364 /* Enter the Critical Region */
1365 KeEnterCriticalRegion();
1367 /* Acquire the mutex unsafely */
1368 _ExAcquireFastMutexUnsafe(FastMutex
);
1373 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex
)
1375 /* Release the mutex unsafely */
1376 _ExReleaseFastMutexUnsafe(FastMutex
);
1378 /* Leave the critical region */
1379 KeLeaveCriticalRegion();
1382 /* OTHER FUNCTIONS **********************************************************/
1386 ExTryToAcquireResourceExclusiveLite(
1387 IN PERESOURCE Resource
1391 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation
);
1395 ExAcquireTimeRefreshLock(BOOLEAN Wait
);
1399 ExReleaseTimeRefreshLock(VOID
);
1403 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime
,
1404 IN ULONG MaxSepInSeconds
);
1408 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
);
1412 ExTimerRundown(VOID
);
1417 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1423 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1426 #define InterlockedDecrementUL(Addend) \
1427 (ULONG)InterlockedDecrement((PLONG)(Addend))
1429 #define InterlockedIncrementUL(Addend) \
1430 (ULONG)InterlockedIncrement((PLONG)(Addend))
1432 #define InterlockedExchangeUL(Target, Value) \
1433 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1435 #define InterlockedExchangeAddUL(Addend, Value) \
1436 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1438 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1439 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1441 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1442 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))