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