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