xref: /reactos/ntoskrnl/include/internal/ex.h (revision 2b933529)
1 #pragma once
2 
3 /* GLOBAL VARIABLES *********************************************************/
4 
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;
33 
34 extern PVOID ExpDefaultErrorPort;
35 extern PEPROCESS ExpDefaultErrorPortProcess;
36 
37 /*
38  * NT/Cm Version Info variables
39  */
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[];
49 
50 /*
51  * WinDBG Debugger Worker State Machine data (see dbgctrl.c)
52  */
53 typedef enum _WINKD_WORKER_STATE
54 {
55     WinKdWorkerReady = 0,
56     WinKdWorkerStart,
57     WinKdWorkerInitialized
58 } WINKD_WORKER_STATE;
59 
60 extern WORK_QUEUE_ITEM ExpDebuggerWorkItem;
61 extern WINKD_WORKER_STATE ExpDebuggerWork;
62 extern PEPROCESS ExpDebuggerProcessAttach;
63 extern PEPROCESS ExpDebuggerProcessKill;
64 extern ULONG_PTR ExpDebuggerPageIn;
65 
66 VOID NTAPI ExpDebuggerWorker(IN PVOID Context);
67 
68 #ifdef _WIN64
69 #define HANDLE_LOW_BITS (PAGE_SHIFT - 4)
70 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 3)
71 #else
72 #define HANDLE_LOW_BITS (PAGE_SHIFT - 3)
73 #define HANDLE_HIGH_BITS (PAGE_SHIFT - 2)
74 #endif
75 #define HANDLE_TAG_BITS (2)
76 #define HANDLE_INDEX_BITS (HANDLE_LOW_BITS + 2*HANDLE_HIGH_BITS)
77 #define KERNEL_FLAG_BITS (sizeof(PVOID)*8 - HANDLE_INDEX_BITS - HANDLE_TAG_BITS)
78 
79 typedef union _EXHANDLE
80 {
81      struct
82      {
83          ULONG_PTR TagBits:     HANDLE_TAG_BITS;
84          ULONG_PTR Index:       HANDLE_INDEX_BITS;
85          ULONG_PTR KernelFlag : KERNEL_FLAG_BITS;
86      };
87      struct
88      {
89          ULONG_PTR TagBits2:    HANDLE_TAG_BITS;
90          ULONG_PTR LowIndex:    HANDLE_LOW_BITS;
91          ULONG_PTR MidIndex:    HANDLE_HIGH_BITS;
92          ULONG_PTR HighIndex:   HANDLE_HIGH_BITS;
93          ULONG_PTR KernelFlag2: KERNEL_FLAG_BITS;
94      };
95      HANDLE GenericHandleOverlay;
96      ULONG_PTR Value;
97      ULONG AsULONG;
98 } EXHANDLE, *PEXHANDLE;
99 
100 typedef struct _ETIMER
101 {
102     KTIMER KeTimer;
103     KAPC TimerApc;
104     KDPC TimerDpc;
105     LIST_ENTRY ActiveTimerListEntry;
106     KSPIN_LOCK Lock;
107     LONG Period;
108     BOOLEAN ApcAssociated;
109     BOOLEAN WakeTimer;
110     LIST_ENTRY WakeTimerListEntry;
111 } ETIMER, *PETIMER;
112 
113 typedef struct
114 {
115     PCALLBACK_OBJECT *CallbackObject;
116     PWSTR Name;
117 } SYSTEM_CALLBACKS;
118 
119 typedef struct _HARDERROR_USER_PARAMETERS
120 {
121     ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS];
122     UNICODE_STRING Strings[MAXIMUM_HARDERROR_PARAMETERS];
123     WCHAR Buffer[ANYSIZE_ARRAY];
124 } HARDERROR_USER_PARAMETERS, *PHARDERROR_USER_PARAMETERS;
125 
126 #define MAX_FAST_REFS           7
127 
128 #define ExAcquireRundownProtection                      _ExAcquireRundownProtection
129 #define ExReleaseRundownProtection                      _ExReleaseRundownProtection
130 #define ExInitializeRundownProtection                   _ExInitializeRundownProtection
131 #define ExWaitForRundownProtectionRelease               _ExWaitForRundownProtectionRelease
132 #define ExRundownCompleted                              _ExRundownCompleted
133 #define ExGetPreviousMode                               KeGetPreviousMode
134 
135 
136 //
137 // Various bits tagged on the handle or handle table
138 //
139 #define EXHANDLE_TABLE_ENTRY_LOCK_BIT    1
140 #define FREE_HANDLE_MASK                -1
141 
142 //
143 // Number of entries in each table level
144 //
145 #define LOW_LEVEL_ENTRIES   (PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY))
146 #define MID_LEVEL_ENTRIES   (PAGE_SIZE / sizeof(PHANDLE_TABLE_ENTRY))
147 #define HIGH_LEVEL_ENTRIES  (16777216 / (LOW_LEVEL_ENTRIES * MID_LEVEL_ENTRIES))
148 
149 //
150 // Maximum index in each table level before we need another table
151 //
152 #define MAX_LOW_INDEX       LOW_LEVEL_ENTRIES
153 #define MAX_MID_INDEX       (MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
154 #define MAX_HIGH_INDEX      (MID_LEVEL_ENTRIES * MID_LEVEL_ENTRIES * LOW_LEVEL_ENTRIES)
155 
156 #define ExpChangeRundown(x, y, z) (ULONG_PTR)InterlockedCompareExchangePointer(&x->Ptr, (PVOID)y, (PVOID)z)
157 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
158 #define ExpSetRundown(x, y) InterlockedExchangePointer(&x->Ptr, (PVOID)y)
159 
160 NTSTATUS
161 NTAPI
162 ExGetPoolTagInfo(
163     IN PSYSTEM_POOLTAG_INFORMATION SystemInformation,
164     IN ULONG SystemInformationLength,
165     IN OUT PULONG ReturnLength OPTIONAL
166 );
167 
168 typedef struct _UUID_CACHED_VALUES_STRUCT
169 {
170     ULONGLONG Time;
171     LONG AllocatedCount;
172     union
173     {
174         struct
175         {
176             UCHAR ClockSeqHiAndReserved;
177             UCHAR ClockSeqLow;
178             UCHAR NodeId[6 /*SEED_BUFFER_SIZE*/];
179         };
180         UCHAR GuidInit[8]; /* Match GUID.Data4 */
181     };
182 } UUID_CACHED_VALUES_STRUCT, *PUUID_CACHED_VALUES_STRUCT;
183 
184 C_ASSERT(RTL_FIELD_SIZE(UUID_CACHED_VALUES_STRUCT, GuidInit) == RTL_FIELD_SIZE(UUID, Data4));
185 
186 /* INITIALIZATION FUNCTIONS *************************************************/
187 
188 BOOLEAN
189 NTAPI
190 ExpWin32kInit(VOID);
191 
192 VOID
193 NTAPI
194 ExInit2(VOID);
195 
196 VOID
197 NTAPI
198 Phase1Initialization(
199     IN PVOID Context
200 );
201 
202 VOID
203 NTAPI
204 ExpInitializePushLocks(VOID);
205 
206 BOOLEAN
207 NTAPI
208 ExRefreshTimeZoneInformation(
209     IN PLARGE_INTEGER SystemBootTime
210 );
211 
212 VOID
213 NTAPI
214 ExpInitializeWorkerThreads(VOID);
215 
216 VOID
217 NTAPI
218 ExSwapinWorkerThreads(IN BOOLEAN AllowSwap);
219 
220 VOID
221 NTAPI
222 ExpInitLookasideLists(VOID);
223 
224 VOID
225 NTAPI
226 ExInitializeSystemLookasideList(
227     IN PGENERAL_LOOKASIDE List,
228     IN POOL_TYPE Type,
229     IN ULONG Size,
230     IN ULONG Tag,
231     IN USHORT MaximumDepth,
232     IN PLIST_ENTRY ListHead
233 );
234 
235 BOOLEAN
236 NTAPI
237 ExpInitializeCallbacks(VOID);
238 
239 BOOLEAN
240 NTAPI
241 ExpUuidInitialization(VOID);
242 
243 BOOLEAN
244 NTAPI
245 ExLuidInitialization(VOID);
246 
247 VOID
248 NTAPI
249 ExpInitializeExecutive(
250     IN ULONG Cpu,
251     IN PLOADER_PARAMETER_BLOCK LoaderBlock
252 );
253 
254 VOID
255 NTAPI
256 ExShutdownSystem(VOID);
257 
258 BOOLEAN
259 NTAPI
260 ExpInitializeEventImplementation(VOID);
261 
262 BOOLEAN
263 NTAPI
264 ExpInitializeKeyedEventImplementation(VOID);
265 
266 BOOLEAN
267 NTAPI
268 ExpInitializeEventPairImplementation(VOID);
269 
270 BOOLEAN
271 NTAPI
272 ExpInitializeSemaphoreImplementation(VOID);
273 
274 BOOLEAN
275 NTAPI
276 ExpInitializeMutantImplementation(VOID);
277 
278 BOOLEAN
279 NTAPI
280 ExpInitializeTimerImplementation(VOID);
281 
282 BOOLEAN
283 NTAPI
284 ExpInitializeProfileImplementation(VOID);
285 
286 VOID
287 NTAPI
288 ExpResourceInitialization(VOID);
289 
290 VOID
291 NTAPI
292 ExInitPoolLookasidePointers(VOID);
293 
294 /* Callback Functions ********************************************************/
295 
296 VOID
297 NTAPI
298 ExInitializeCallBack(
299     IN OUT PEX_CALLBACK Callback
300 );
301 
302 PEX_CALLBACK_ROUTINE_BLOCK
303 NTAPI
304 ExAllocateCallBack(
305     IN PEX_CALLBACK_FUNCTION Function,
306     IN PVOID Context
307 );
308 
309 VOID
310 NTAPI
311 ExFreeCallBack(
312     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
313 );
314 
315 BOOLEAN
316 NTAPI
317 ExCompareExchangeCallBack (
318     IN OUT PEX_CALLBACK CallBack,
319     IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
320     IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
321 );
322 
323 PEX_CALLBACK_ROUTINE_BLOCK
324 NTAPI
325 ExReferenceCallBackBlock(
326     IN OUT PEX_CALLBACK CallBack
327 );
328 
329 VOID
330 NTAPI
331 ExDereferenceCallBackBlock(
332     IN OUT PEX_CALLBACK CallBack,
333     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
334 );
335 
336 PEX_CALLBACK_FUNCTION
337 NTAPI
338 ExGetCallBackBlockRoutine(
339     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
340 );
341 
342 PVOID
343 NTAPI
344 ExGetCallBackBlockContext(
345     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
346 );
347 
348 VOID
349 NTAPI
350 ExWaitForCallBacks(
351     IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
352 );
353 
354 /* Rundown Functions ********************************************************/
355 
356 VOID
357 FASTCALL
358 ExfInitializeRundownProtection(
359      OUT PEX_RUNDOWN_REF RunRef
360 );
361 
362 VOID
363 FASTCALL
364 ExfReInitializeRundownProtection(
365      OUT PEX_RUNDOWN_REF RunRef
366 );
367 
368 BOOLEAN
369 FASTCALL
370 ExfAcquireRundownProtection(
371      IN OUT PEX_RUNDOWN_REF RunRef
372 );
373 
374 BOOLEAN
375 FASTCALL
376 ExfAcquireRundownProtectionEx(
377      IN OUT PEX_RUNDOWN_REF RunRef,
378      IN ULONG Count
379 );
380 
381 VOID
382 FASTCALL
383 ExfReleaseRundownProtection(
384      IN OUT PEX_RUNDOWN_REF RunRef
385 );
386 
387 VOID
388 FASTCALL
389 ExfReleaseRundownProtectionEx(
390      IN OUT PEX_RUNDOWN_REF RunRef,
391      IN ULONG Count
392 );
393 
394 VOID
395 FASTCALL
396 ExfRundownCompleted(
397      OUT PEX_RUNDOWN_REF RunRef
398 );
399 
400 VOID
401 FASTCALL
402 ExfWaitForRundownProtectionRelease(
403      IN OUT PEX_RUNDOWN_REF RunRef
404 );
405 
406 /* HANDLE TABLE FUNCTIONS ***************************************************/
407 
408 typedef BOOLEAN
409 (NTAPI *PEX_SWEEP_HANDLE_CALLBACK)(
410     PHANDLE_TABLE_ENTRY HandleTableEntry,
411     HANDLE Handle,
412     PVOID Context
413 );
414 
415 typedef BOOLEAN
416 (NTAPI *PEX_DUPLICATE_HANDLE_CALLBACK)(
417     IN PEPROCESS Process,
418     IN PHANDLE_TABLE HandleTable,
419     IN PHANDLE_TABLE_ENTRY HandleTableEntry,
420     IN PHANDLE_TABLE_ENTRY NewEntry
421 );
422 
423 typedef BOOLEAN
424 (NTAPI *PEX_CHANGE_HANDLE_CALLBACK)(
425     PHANDLE_TABLE_ENTRY HandleTableEntry,
426     ULONG_PTR Context
427 );
428 
429 VOID
430 NTAPI
431 ExpInitializeHandleTables(
432     VOID
433 );
434 
435 PHANDLE_TABLE
436 NTAPI
437 ExCreateHandleTable(
438     IN PEPROCESS Process OPTIONAL
439 );
440 
441 VOID
442 NTAPI
443 ExUnlockHandleTableEntry(
444     IN PHANDLE_TABLE HandleTable,
445     IN PHANDLE_TABLE_ENTRY HandleTableEntry
446 );
447 
448 HANDLE
449 NTAPI
450 ExCreateHandle(
451     IN PHANDLE_TABLE HandleTable,
452     IN PHANDLE_TABLE_ENTRY HandleTableEntry
453 );
454 
455 VOID
456 NTAPI
457 ExDestroyHandleTable(
458     IN PHANDLE_TABLE HandleTable,
459     IN PVOID DestroyHandleProcedure OPTIONAL
460 );
461 
462 BOOLEAN
463 NTAPI
464 ExDestroyHandle(
465     IN PHANDLE_TABLE HandleTable,
466     IN HANDLE Handle,
467     IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
468 );
469 
470 PHANDLE_TABLE_ENTRY
471 NTAPI
472 ExMapHandleToPointer(
473     IN PHANDLE_TABLE HandleTable,
474     IN HANDLE Handle
475 );
476 
477 PHANDLE_TABLE
478 NTAPI
479 ExDupHandleTable(
480     IN PEPROCESS Process,
481     IN PHANDLE_TABLE HandleTable,
482     IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,
483     IN ULONG_PTR Mask
484 );
485 
486 BOOLEAN
487 NTAPI
488 ExChangeHandle(
489     IN PHANDLE_TABLE HandleTable,
490     IN HANDLE Handle,
491     IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,
492     IN ULONG_PTR Context
493 );
494 
495 VOID
496 NTAPI
497 ExSweepHandleTable(
498     IN PHANDLE_TABLE HandleTable,
499     IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,
500     IN PVOID Context
501 );
502 
503 PHANDLE_TABLE_ENTRY
504 NTAPI
505 ExpLookupHandleTableEntry(
506     IN PHANDLE_TABLE HandleTable,
507     IN EXHANDLE Handle
508 );
509 
510 BOOLEAN
511 NTAPI
512 ExpLockHandleTableEntry(
513     IN PHANDLE_TABLE HandleTable,
514     IN PHANDLE_TABLE_ENTRY HandleTableEntry
515 );
516 
517 /* PSEH EXCEPTION HANDLING **************************************************/
518 
519 LONG
520 NTAPI
521 ExSystemExceptionFilter(VOID);
522 
523 /* CALLBACKS *****************************************************************/
524 
525 FORCEINLINE
526 VOID
527 ExDoCallBack(IN OUT PEX_CALLBACK Callback,
528              IN PVOID Context,
529              IN PVOID Argument1,
530              IN PVOID Argument2)
531 {
532     PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock;
533     PEX_CALLBACK_FUNCTION Function;
534 
535     /* Reference the block */
536     CallbackBlock = ExReferenceCallBackBlock(Callback);
537     if (CallbackBlock)
538     {
539         /* Get the function */
540         Function = ExGetCallBackBlockRoutine(CallbackBlock);
541 
542         /* Do the callback */
543         Function(Context, Argument1, Argument2);
544 
545         /* Now dereference it */
546         ExDereferenceCallBackBlock(Callback, CallbackBlock);
547     }
548 }
549 
550 /* FAST REFS ******************************************************************/
551 
552 FORCEINLINE
553 PVOID
554 ExGetObjectFastReference(IN EX_FAST_REF FastRef)
555 {
556     /* Return the unbiased pointer */
557     return (PVOID)(FastRef.Value & ~MAX_FAST_REFS);
558 }
559 
560 FORCEINLINE
561 ULONG
562 ExGetCountFastReference(IN EX_FAST_REF FastRef)
563 {
564     /* Return the reference count */
565     return (ULONG)FastRef.RefCnt;
566 }
567 
568 FORCEINLINE
569 VOID
570 ExInitializeFastReference(OUT PEX_FAST_REF FastRef,
571                           IN OPTIONAL PVOID Object)
572 {
573     /* Sanity check */
574     ASSERT((((ULONG_PTR)Object) & MAX_FAST_REFS) == 0);
575 
576     /* Check if an object is being set */
577     if (!Object)
578     {
579         /* Clear the field */
580         FastRef->Object = NULL;
581     }
582     else
583     {
584         /* Otherwise, we assume the object was referenced and is ready */
585         FastRef->Value = (ULONG_PTR)Object | MAX_FAST_REFS;
586     }
587 }
588 
589 FORCEINLINE
590 EX_FAST_REF
591 ExAcquireFastReference(IN OUT PEX_FAST_REF FastRef)
592 {
593     EX_FAST_REF OldValue, NewValue;
594 
595     /* Start reference loop */
596     for (;;)
597     {
598         /* Get the current reference count */
599         OldValue = *FastRef;
600         if (OldValue.RefCnt)
601         {
602             /* Increase the reference count */
603             NewValue.Value = OldValue.Value - 1;
604             NewValue.Object = ExpChangePushlock(&FastRef->Object,
605                                                 NewValue.Object,
606                                                 OldValue.Object);
607             if (NewValue.Object != OldValue.Object) continue;
608         }
609 
610         /* We are done */
611         break;
612     }
613 
614     /* Return the old value */
615     return OldValue;
616 }
617 
618 FORCEINLINE
619 BOOLEAN
620 ExInsertFastReference(IN OUT PEX_FAST_REF FastRef,
621                       IN PVOID Object)
622 {
623     EX_FAST_REF OldValue, NewValue;
624 
625     /* Sanity checks */
626     ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
627 
628     /* Start update loop */
629     for (;;)
630     {
631         /* Get the current reference count */
632         OldValue = *FastRef;
633 
634         /* Check if the current count is too high or if the pointer changed */
635         if (((OldValue.RefCnt + MAX_FAST_REFS) > MAX_FAST_REFS) ||
636             ((OldValue.Value &~ MAX_FAST_REFS) != (ULONG_PTR)Object))
637         {
638             /* Fail */
639             return FALSE;
640         }
641 
642         /* Update the reference count */
643         NewValue.Value = OldValue.Value + MAX_FAST_REFS;
644         NewValue.Object = ExpChangePushlock(&FastRef->Object,
645                                             NewValue.Object,
646                                             OldValue.Object);
647         if (NewValue.Object != OldValue.Object) continue;
648 
649         /* We are done */
650         break;
651     }
652 
653     /* Return success */
654     return TRUE;
655 }
656 
657 FORCEINLINE
658 BOOLEAN
659 ExReleaseFastReference(IN PEX_FAST_REF FastRef,
660                        IN PVOID Object)
661 {
662     EX_FAST_REF OldValue, NewValue;
663 
664     /* Sanity checks */
665     ASSERT(Object != NULL);
666     ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
667 
668     /* Start reference loop */
669     for (;;)
670     {
671         /* Get the current reference count */
672         OldValue = *FastRef;
673 
674         /* Check if we're full if if the pointer changed */
675         if ((OldValue.Value ^ (ULONG_PTR)Object) >= MAX_FAST_REFS) return FALSE;
676 
677         /* Decrease the reference count */
678         NewValue.Value = OldValue.Value + 1;
679         NewValue.Object = ExpChangePushlock(&FastRef->Object,
680                                             NewValue.Object,
681                                             OldValue.Object);
682         if (NewValue.Object != OldValue.Object) continue;
683 
684         /* We are done */
685         break;
686     }
687 
688     /* Return success */
689     return TRUE;
690 }
691 
692 FORCEINLINE
693 EX_FAST_REF
694 ExSwapFastReference(IN PEX_FAST_REF FastRef,
695                     IN PVOID Object)
696 {
697     EX_FAST_REF NewValue, OldValue;
698 
699     /* Sanity check */
700     ASSERT((((ULONG_PTR)Object) & MAX_FAST_REFS) == 0);
701 
702     /* Check if an object is being set */
703     if (!Object)
704     {
705         /* Clear the field */
706         NewValue.Object = NULL;
707     }
708     else
709     {
710         /* Otherwise, we assume the object was referenced and is ready */
711         NewValue.Value = (ULONG_PTR)Object | MAX_FAST_REFS;
712     }
713 
714     /* Update the object */
715     OldValue.Object = InterlockedExchangePointer(&FastRef->Object, NewValue.Object);
716     return OldValue;
717 }
718 
719 FORCEINLINE
720 EX_FAST_REF
721 ExCompareSwapFastReference(IN PEX_FAST_REF FastRef,
722                            IN PVOID Object,
723                            IN PVOID OldObject)
724 {
725     EX_FAST_REF OldValue, NewValue;
726 
727     /* Sanity check and start swap loop */
728     ASSERT(!(((ULONG_PTR)Object) & MAX_FAST_REFS));
729     for (;;)
730     {
731         /* Get the current value */
732         OldValue = *FastRef;
733 
734         /* Make sure there's enough references to swap */
735         if (!((OldValue.Value ^ (ULONG_PTR)OldObject) <= MAX_FAST_REFS)) break;
736 
737         /* Check if we have an object to swap */
738         if (Object)
739         {
740             /* Set up the value with maximum fast references */
741             NewValue.Value = (ULONG_PTR)Object | MAX_FAST_REFS;
742         }
743         else
744         {
745             /* Write the object address itself (which is empty) */
746             NewValue.Value = (ULONG_PTR)Object;
747         }
748 
749         /* Do the actual compare exchange */
750         NewValue.Object = ExpChangePushlock(&FastRef->Object,
751                                             NewValue.Object,
752                                             OldValue.Object);
753         if (NewValue.Object != OldValue.Object) continue;
754 
755         /* All done */
756         break;
757     }
758 
759     /* Return the old value */
760     return OldValue;
761 }
762 
763 /* RUNDOWN *******************************************************************/
764 
765 FORCEINLINE
766 PEX_RUNDOWN_REF
767 ExGetRunRefForGivenProcessor(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware,
768                              IN ULONG ProcNumber)
769 {
770     return (PEX_RUNDOWN_REF)((ULONG_PTR)RunRefCacheAware->RunRefs +
771                              RunRefCacheAware->RunRefSize *
772                              (ProcNumber % RunRefCacheAware->Number));
773 }
774 
775 /*++
776  * @name ExfAcquireRundownProtection
777  * INTERNAL MACRO
778  *
779  *     The ExfAcquireRundownProtection routine acquires rundown protection for
780  *     the specified descriptor.
781  *
782  * @param RunRef
783  *        Pointer to a rundown reference descriptor.
784  *
785  * @return TRUE if access to the protected structure was granted, FALSE otherwise.
786  *
787  * @remarks This is the internal macro for system use only.In case the rundown
788  *          was active, then the slow-path will be called through the exported
789  *          function.
790  *
791  *--*/
792 FORCEINLINE
793 BOOLEAN
794 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
795 {
796     ULONG_PTR Value, NewValue;
797 
798     /* Get the current value and mask the active bit */
799     Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
800 
801     /* Add a reference */
802     NewValue = Value + EX_RUNDOWN_COUNT_INC;
803 
804     /* Change the value */
805     NewValue = ExpChangeRundown(RunRef, NewValue, Value);
806     if (NewValue != Value)
807     {
808         /* Rundown was active, use long path */
809         return ExfAcquireRundownProtection(RunRef);
810     }
811 
812     /* Success */
813     return TRUE;
814 }
815 
816 /*++
817  * @name ExReleaseRundownProtection
818  * INTERNAL MACRO
819  *
820  *     The ExReleaseRundownProtection routine releases rundown protection for
821  *     the specified descriptor.
822  *
823  * @param RunRef
824  *        Pointer to a rundown reference descriptor.
825  *
826  * @return TRUE if access to the protected structure was granted, FALSE otherwise.
827  *
828  * @remarks This is the internal macro for system use only.In case the rundown
829  *          was active, then the slow-path will be called through the exported
830  *          function.
831  *
832  *--*/
833 FORCEINLINE
834 VOID
835 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
836 {
837     ULONG_PTR Value, NewValue;
838 
839     /* Get the current value and mask the active bit */
840     Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
841 
842     /* Remove a reference */
843     NewValue = Value - EX_RUNDOWN_COUNT_INC;
844 
845     /* Change the value */
846     NewValue = ExpChangeRundown(RunRef, NewValue, Value);
847 
848     /* Check if the rundown was active */
849     if (NewValue != Value)
850     {
851         /* Rundown was active, use long path */
852         ExfReleaseRundownProtection(RunRef);
853     }
854     else
855     {
856         /* Sanity check */
857         ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
858     }
859 }
860 
861 /*++
862  * @name ExInitializeRundownProtection
863  * INTERNAL MACRO
864  *
865  *     The ExInitializeRundownProtection routine initializes a rundown
866  *     protection descriptor.
867  *
868  * @param RunRef
869  *        Pointer to a rundown reference descriptor.
870  *
871  * @return None.
872  *
873  * @remarks This is the internal macro for system use only.
874  *
875  *--*/
876 FORCEINLINE
877 VOID
878 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
879 {
880     /* Set the count to zero */
881     RunRef->Count = 0;
882 }
883 
884 /*++
885  * @name ExWaitForRundownProtectionRelease
886  * INTERNAL MACRO
887  *
888  *     The ExWaitForRundownProtectionRelease routine waits until the specified
889  *     rundown descriptor has been released.
890  *
891  * @param RunRef
892  *        Pointer to a rundown reference descriptor.
893  *
894  * @return None.
895  *
896  * @remarks This is the internal macro for system use only. If a wait is actually
897  *          necessary, then the slow path is taken through the exported function.
898  *
899  *--*/
900 FORCEINLINE
901 VOID
902 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
903 {
904     ULONG_PTR Value;
905 
906     /* Set the active bit */
907     Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
908     if ((Value) && (Value != EX_RUNDOWN_ACTIVE))
909     {
910         /* If the the rundown wasn't already active, then take the long path */
911         ExfWaitForRundownProtectionRelease(RunRef);
912     }
913 }
914 
915 /*++
916  * @name ExRundownCompleted
917  * INTERNAL MACRO
918  *
919  *     The ExRundownCompleted routine completes the rundown of the specified
920  *     descriptor by setting the active bit.
921  *
922  * @param RunRef
923  *        Pointer to a rundown reference descriptor.
924  *
925  * @return None.
926  *
927  * @remarks This is the internal macro for system use only.
928  *
929  *--*/
930 FORCEINLINE
931 VOID
932 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
933 {
934     /* Sanity check */
935     ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
936 
937     /* Mark the counter as active */
938     ExpSetRundown(RunRef, EX_RUNDOWN_ACTIVE);
939 }
940 
941 /* PUSHLOCKS *****************************************************************/
942 
943 /* FIXME: VERIFY THESE! */
944 
945 VOID
946 FASTCALL
947 ExBlockPushLock(
948     IN PEX_PUSH_LOCK PushLock,
949     IN PVOID WaitBlock
950 );
951 
952 VOID
953 FASTCALL
954 ExfUnblockPushLock(
955     IN PEX_PUSH_LOCK PushLock,
956     IN PVOID CurrentWaitBlock
957 );
958 
959 VOID
960 FASTCALL
961 ExWaitForUnblockPushLock(
962     IN PEX_PUSH_LOCK PushLock,
963     IN PVOID WaitBlock
964 );
965 
966 /*++
967  * @name _ExInitializePushLock
968  * INTERNAL MACRO
969  *
970  *     The _ExInitializePushLock macro initializes a PushLock.
971  *
972  * @params PushLock
973  *         Pointer to the pushlock which is to be initialized.
974  *
975  * @return None.
976  *
977  * @remarks None.
978  *
979  *--*/
980 FORCEINLINE
981 VOID
982 _ExInitializePushLock(OUT PEX_PUSH_LOCK PushLock)
983 {
984     /* Set the value to 0 */
985     PushLock->Ptr = 0;
986 }
987 #define ExInitializePushLock _ExInitializePushLock
988 
989 /*++
990  * @name ExAcquirePushLockExclusive
991  * INTERNAL MACRO
992  *
993  *     The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
994  *
995  * @params PushLock
996  *         Pointer to the pushlock which is to be acquired.
997  *
998  * @return None.
999  *
1000  * @remarks The function attempts the quickest route to acquire the lock, which is
1001  *          to simply set the lock bit.
1002  *          However, if the pushlock is already shared, the slower path is taken.
1003  *
1004  *          Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1005  *          This macro should usually be paired up with KeAcquireCriticalRegion.
1006  *
1007  *--*/
1008 FORCEINLINE
1009 VOID
1010 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
1011 {
1012     /* Try acquiring the lock */
1013     if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
1014     {
1015         /* Someone changed it, use the slow path */
1016         ExfAcquirePushLockExclusive(PushLock);
1017     }
1018 
1019     /* Sanity check */
1020     ASSERT(PushLock->Locked);
1021 }
1022 
1023 /*++
1024 * @name ExTryToAcquirePushLockExclusive
1025 * INTERNAL MACRO
1026 *
1027 *     The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
1028 *
1029 * @params PushLock
1030 *         Pointer to the pushlock which is to be acquired.
1031 *
1032 * @return None.
1033 *
1034 * @remarks The function attempts the quickest route to acquire the lock, which is
1035 *          to simply set the lock bit.
1036 *          However, if the pushlock is already shared, the slower path is taken.
1037 *
1038 *          Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1039 *          This macro should usually be paired up with KeAcquireCriticalRegion.
1040 *
1041 *--*/
1042 FORCEINLINE
1043 BOOLEAN
1044 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
1045 {
1046     /* Try acquiring the lock */
1047     if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
1048     {
1049         /* Can't acquire */
1050         return FALSE;
1051     }
1052 
1053     /* Got acquired */
1054     ASSERT (PushLock->Locked);
1055     return TRUE;
1056 }
1057 
1058 /*++
1059  * @name ExAcquirePushLockShared
1060  * INTERNAL MACRO
1061  *
1062  *     The ExAcquirePushLockShared macro acquires a shared PushLock.
1063  *
1064  * @params PushLock
1065  *         Pointer to the pushlock which is to be acquired.
1066  *
1067  * @return None.
1068  *
1069  * @remarks The function attempts the quickest route to acquire the lock, which is
1070  *          to simply set the lock bit and set the share count to one.
1071  *          However, if the pushlock is already shared, the slower path is taken.
1072  *
1073  *          Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
1074  *          This macro should usually be paired up with KeAcquireCriticalRegion.
1075  *
1076  *--*/
1077 FORCEINLINE
1078 VOID
1079 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
1080 {
1081     EX_PUSH_LOCK NewValue;
1082 
1083     /* Try acquiring the lock */
1084     NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1085     if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
1086     {
1087         /* Someone changed it, use the slow path */
1088         ExfAcquirePushLockShared(PushLock);
1089     }
1090 
1091     /* Sanity checks */
1092     ASSERT(PushLock->Locked);
1093 }
1094 
1095 /*++
1096  * @name ExConvertPushLockSharedToExclusive
1097  * INTERNAL MACRO
1098  *
1099  *     The ExConvertPushLockSharedToExclusive macro converts an exclusive
1100  *     pushlock to a shared pushlock.
1101  *
1102  * @params PushLock
1103  *         Pointer to the pushlock which is to be converted.
1104  *
1105  * @return FALSE if conversion failed, TRUE otherwise.
1106  *
1107  * @remarks The function attempts the quickest route to convert the lock, which is
1108  *          to simply set the lock bit and remove any other bits.
1109  *
1110  *--*/
1111 FORCEINLINE
1112 BOOLEAN
1113 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock)
1114 {
1115     EX_PUSH_LOCK OldValue;
1116 
1117     /* Set the expected old value */
1118     OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1119 
1120     /* Try converting the lock */
1121     if (ExpChangePushlock(PushLock, EX_PUSH_LOCK_LOCK, OldValue.Value) !=
1122         OldValue.Ptr)
1123     {
1124         /* Conversion failed */
1125         return FALSE;
1126     }
1127 
1128     /* Sanity check */
1129     ASSERT(PushLock->Locked);
1130     return TRUE;
1131 }
1132 
1133 /*++
1134  * @name ExWaitOnPushLock
1135  * INTERNAL MACRO
1136  *
1137  *     The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
1138  *
1139  * @params PushLock
1140  *         Pointer to a pushlock.
1141  *
1142  * @return None.
1143  *
1144  * @remarks The function attempts to get any exclusive waiters out of their slow
1145  *          path by forcing an instant acquire/release operation.
1146  *
1147  *          Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
1148  *
1149  *--*/
1150 FORCEINLINE
1151 VOID
1152 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
1153 {
1154     /* Check if we're locked */
1155     if (PushLock->Locked)
1156     {
1157         /* Acquire the lock */
1158         ExfAcquirePushLockExclusive(PushLock);
1159         ASSERT(PushLock->Locked);
1160 
1161         /* Release it */
1162         ExfReleasePushLockExclusive(PushLock);
1163     }
1164 }
1165 
1166 /*++
1167  * @name ExReleasePushLockShared
1168  * INTERNAL MACRO
1169  *
1170  *     The ExReleasePushLockShared macro releases a previously acquired PushLock.
1171  *
1172  * @params PushLock
1173  *         Pointer to a previously acquired pushlock.
1174  *
1175  * @return None.
1176  *
1177  * @remarks The function attempts the quickest route to release the lock, which is
1178  *          to simply decrease the share count and remove the lock bit.
1179  *          However, if the pushlock is being waited on then the long path is taken.
1180  *
1181  *          Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
1182  *          This macro should usually be paired up with KeLeaveCriticalRegion.
1183  *
1184  *--*/
1185 FORCEINLINE
1186 VOID
1187 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
1188 {
1189     EX_PUSH_LOCK OldValue;
1190 
1191     /* Sanity checks */
1192     ASSERT(PushLock->Locked);
1193 
1194     /* Try to clear the pushlock */
1195     OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
1196     if (ExpChangePushlock(PushLock, 0, OldValue.Ptr) != OldValue.Ptr)
1197     {
1198         /* There are still other people waiting on it */
1199         ExfReleasePushLockShared(PushLock);
1200     }
1201 }
1202 
1203 /*++
1204  * @name ExReleasePushLockExclusive
1205  * INTERNAL MACRO
1206  *
1207  *     The ExReleasePushLockExclusive macro releases a previously
1208  *     exclusively acquired PushLock.
1209  *
1210  * @params PushLock
1211  *         Pointer to a previously acquired pushlock.
1212  *
1213  * @return None.
1214  *
1215  * @remarks The function attempts the quickest route to release the lock, which is
1216  *          to simply clear the locked bit.
1217  *          However, if the pushlock is being waited on, the slow path is taken
1218  *          in an attempt to wake up the lock.
1219  *
1220  *          Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
1221  *          This macro should usually be paired up with KeLeaveCriticalRegion.
1222  *
1223  *--*/
1224 FORCEINLINE
1225 VOID
1226 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
1227 {
1228     EX_PUSH_LOCK OldValue;
1229 
1230     /* Sanity checks */
1231     ASSERT(PushLock->Locked);
1232 
1233     /* Unlock the pushlock */
1234     OldValue.Value = InterlockedExchangeAddSizeT((PSIZE_T)PushLock,
1235                                                  -(SSIZE_T)EX_PUSH_LOCK_LOCK);
1236 
1237     /* Sanity checks */
1238     ASSERT(OldValue.Locked);
1239     ASSERT(OldValue.Waiting || OldValue.Shared == 0);
1240 
1241     /* Check if anyone is waiting on it and it's not already waking*/
1242     if ((OldValue.Waiting) && !(OldValue.Waking))
1243     {
1244         /* Wake it up */
1245         ExfTryToWakePushLock(PushLock);
1246     }
1247 }
1248 
1249 /*++
1250  * @name ExReleasePushLock
1251  * INTERNAL MACRO
1252  *
1253  *     The ExReleasePushLock macro releases a previously acquired PushLock.
1254  *
1255  * @params PushLock
1256  *         Pointer to a previously acquired pushlock.
1257  *
1258  * @return None.
1259  *
1260  * @remarks The function attempts the quickest route to release the lock, which is
1261  *          to simply clear all the fields and decrease the share count if required.
1262  *          However, if the pushlock is being waited on then the long path is taken.
1263  *
1264  *          Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
1265  *          This macro should usually be paired up with KeLeaveCriticalRegion.
1266  *
1267  *--*/
1268 FORCEINLINE
1269 VOID
1270 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
1271 {
1272     EX_PUSH_LOCK OldValue = *PushLock;
1273     EX_PUSH_LOCK NewValue;
1274 
1275     /* Sanity checks */
1276     ASSERT(OldValue.Locked);
1277 
1278     /* Check if the pushlock is shared */
1279     if (OldValue.Shared > 1)
1280     {
1281         /* Decrease the share count */
1282         NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
1283     }
1284     else
1285     {
1286         /* Clear the pushlock entirely */
1287         NewValue.Value = 0;
1288     }
1289 
1290     /* Check if nobody is waiting on us and try clearing the lock here */
1291     if ((OldValue.Waiting) ||
1292         (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
1293          OldValue.Ptr))
1294     {
1295         /* We have waiters, use the long path */
1296         ExfReleasePushLock(PushLock);
1297     }
1298 }
1299 
1300 /* FAST MUTEX INLINES *********************************************************/
1301 
1302 FORCEINLINE
1303 VOID
1304 _ExAcquireFastMutexUnsafe(IN PFAST_MUTEX FastMutex)
1305 {
1306     PKTHREAD Thread = KeGetCurrentThread();
1307 
1308     /* Sanity check */
1309     ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1310            (Thread->CombinedApcDisable != 0) ||
1311            (Thread->Teb == NULL) ||
1312            (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1313     ASSERT(FastMutex->Owner != Thread);
1314 
1315     /* Decrease the count */
1316     if (InterlockedDecrement(&FastMutex->Count))
1317     {
1318         /* Someone is still holding it, use slow path */
1319         KiAcquireFastMutex(FastMutex);
1320     }
1321 
1322     /* Set the owner */
1323     FastMutex->Owner = Thread;
1324 }
1325 
1326 FORCEINLINE
1327 VOID
1328 _ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
1329 {
1330     ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
1331            (KeGetCurrentThread()->CombinedApcDisable != 0) ||
1332            (KeGetCurrentThread()->Teb == NULL) ||
1333            (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
1334     ASSERT(FastMutex->Owner == KeGetCurrentThread());
1335 
1336     /* Erase the owner */
1337     FastMutex->Owner = NULL;
1338 
1339     /* Increase the count */
1340     if (InterlockedIncrement(&FastMutex->Count) <= 0)
1341     {
1342         /* Someone was waiting for it, signal the waiter */
1343         KeSetEventBoostPriority(&FastMutex->Event, NULL);
1344     }
1345 }
1346 
1347 FORCEINLINE
1348 VOID
1349 _ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
1350 {
1351     KIRQL OldIrql;
1352     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1353 
1354     /* Raise IRQL to APC */
1355     KeRaiseIrql(APC_LEVEL, &OldIrql);
1356 
1357     /* Decrease the count */
1358     if (InterlockedDecrement(&FastMutex->Count))
1359     {
1360         /* Someone is still holding it, use slow path */
1361         KiAcquireFastMutex(FastMutex);
1362     }
1363 
1364     /* Set the owner and IRQL */
1365     FastMutex->Owner = KeGetCurrentThread();
1366     FastMutex->OldIrql = OldIrql;
1367 }
1368 
1369 FORCEINLINE
1370 VOID
1371 _ExReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex)
1372 {
1373     KIRQL OldIrql;
1374     ASSERT(KeGetCurrentIrql() == APC_LEVEL);
1375 
1376     /* Erase the owner */
1377     FastMutex->Owner = NULL;
1378     OldIrql = (KIRQL)FastMutex->OldIrql;
1379 
1380     /* Increase the count */
1381     if (InterlockedIncrement(&FastMutex->Count) <= 0)
1382     {
1383         /* Someone was waiting for it, signal the waiter */
1384         KeSetEventBoostPriority(&FastMutex->Event, NULL);
1385     }
1386 
1387     /* Lower IRQL back */
1388     KeLowerIrql(OldIrql);
1389 }
1390 
1391 FORCEINLINE
1392 BOOLEAN
1393 _ExTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex)
1394 {
1395     KIRQL OldIrql;
1396     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
1397 
1398     /* Raise to APC_LEVEL */
1399     KeRaiseIrql(APC_LEVEL, &OldIrql);
1400 
1401     /* Check if we can quickly acquire it */
1402     if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1)
1403     {
1404         /* We have, set us as owners */
1405         FastMutex->Owner = KeGetCurrentThread();
1406         FastMutex->OldIrql = OldIrql;
1407         return TRUE;
1408     }
1409     else
1410     {
1411         /* Acquire attempt failed */
1412         KeLowerIrql(OldIrql);
1413         YieldProcessor();
1414         return FALSE;
1415     }
1416 }
1417 
1418 FORCEINLINE
1419 VOID
1420 _ExEnterCriticalRegionAndAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
1421 {
1422     /* Enter the Critical Region */
1423     KeEnterCriticalRegion();
1424 
1425     /* Acquire the mutex unsafely */
1426     _ExAcquireFastMutexUnsafe(FastMutex);
1427 }
1428 
1429 FORCEINLINE
1430 VOID
1431 _ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(IN OUT PFAST_MUTEX FastMutex)
1432 {
1433     /* Release the mutex unsafely */
1434     _ExReleaseFastMutexUnsafe(FastMutex);
1435 
1436     /* Leave the critical region */
1437     KeLeaveCriticalRegion();
1438 }
1439 
1440 /* OTHER FUNCTIONS **********************************************************/
1441 
1442 BOOLEAN
1443 NTAPI
1444 ExTryToAcquireResourceExclusiveLite(
1445     IN PERESOURCE Resource
1446 );
1447 
1448 NTSTATUS
1449 ExpSetTimeZoneInformation(
1450     IN PRTL_TIME_ZONE_INFORMATION TimeZoneInformation
1451 );
1452 
1453 BOOLEAN
1454 NTAPI
1455 ExAcquireTimeRefreshLock(
1456     IN BOOLEAN Wait
1457 );
1458 
1459 VOID
1460 NTAPI
1461 ExReleaseTimeRefreshLock(
1462     VOID
1463 );
1464 
1465 VOID
1466 NTAPI
1467 ExUpdateSystemTimeFromCmos(
1468     IN BOOLEAN UpdateInterruptTime,
1469     IN ULONG MaxSepInSeconds
1470 );
1471 
1472 VOID
1473 NTAPI
1474 ExAllocateLocallyUniqueId(
1475     OUT LUID *LocallyUniqueId
1476 );
1477 
1478 VOID
1479 NTAPI
1480 ExTimerRundown(
1481     VOID
1482 );
1483 
1484 VOID
1485 NTAPI
1486 HeadlessInit(
1487     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1488 );
1489 
1490 VOID
1491 NTAPI
1492 XIPInit(
1493     IN PLOADER_PARAMETER_BLOCK LoaderBlock
1494 );
1495 
1496 #define InterlockedDecrementUL(Addend) \
1497    (ULONG)InterlockedDecrement((PLONG)(Addend))
1498 
1499 #define InterlockedIncrementUL(Addend) \
1500    (ULONG)InterlockedIncrement((PLONG)(Addend))
1501 
1502 #define InterlockedExchangeUL(Target, Value) \
1503    (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1504 
1505 #define InterlockedExchangeAddUL(Addend, Value) \
1506    (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1507 
1508 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1509    (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1510 
1511 #define InterlockedCompareExchangeSizeT(Destination, Exchange, Comperand) \
1512    (SIZE_T)InterlockedCompareExchangePointer((PVOID*)(Destination), (PVOID)(SIZE_T)(Exchange), (PVOID)(SIZE_T)(Comperand))
1513 
1514 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1515    (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
1516