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