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