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