Stefan Ginsberg <stefan__100__@hotmail.com>
[reactos.git] / reactos / ntoskrnl / include / internal / ex.h
1 #ifndef __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
2 #define __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H
3
4 /* GLOBAL VARIABLES *********************************************************/
5
6 extern TIME_ZONE_INFORMATION ExpTimeZoneInfo;
7 extern LARGE_INTEGER ExpTimeZoneBias;
8 extern ULONG ExpTimeZoneId;
9 extern ULONG ExpTickCountMultiplier;
10 extern ULONG ExpLastTimeZoneBias;
11 extern POBJECT_TYPE ExEventPairObjectType;
12 extern POBJECT_TYPE _ExEventObjectType, _ExSemaphoreObjectType;
13 extern ULONG NtBuildNumber;
14 extern ULONG NtMajorVersion;
15 extern ULONG NtMinorVersion;
16 extern FAST_MUTEX ExpEnvironmentLock;
17 extern ERESOURCE ExpFirmwareTableResource;
18 extern LIST_ENTRY ExpFirmwareTableProviderListHead;
19 extern BOOLEAN ExpIsWinPEMode;
20 extern LIST_ENTRY ExpSystemResourcesList;
21 ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
22 ULONG ExpUnicodeCaseTableDataOffset;
23 PVOID ExpNlsSectionPointer;
24 extern CHAR NtBuildLab[];
25 extern ULONG CmNtCSDVersion;
26 extern ULONG NtGlobalFlag;
27 extern ULONG ExpInitializationPhase;
28 extern ULONG ExpAltTimeZoneBias;
29 extern LIST_ENTRY ExSystemLookasideListHead;
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 GCC
96 //
97 #ifdef __GNUC__
98
99 #define DEFINE_WAIT_BLOCK(x) \
100 struct _AlignHack \
101 { \
102 UCHAR Hack[15]; \
103 EX_PUSH_LOCK_WAIT_BLOCK UnalignedBlock; \
104 } WaitBlockBuffer; \
105 PEX_PUSH_LOCK_WAIT_BLOCK x = (PEX_PUSH_LOCK_WAIT_BLOCK) \
106 ((ULONG_PTR)&WaitBlockBuffer.UnalignedBlock &~ 0xF);
107
108 #else
109
110 //
111 // This is only for compatibility; the compiler will optimize the extra
112 // local variable (the actual pointer) away, so we don't take any perf hit
113 // by doing this.
114 //
115 #define DEFINE_WAIT_BLOCK(x) \
116 EX_PUSH_LOCK_WAIT_BLOCK WaitBlockBuffer; \
117 PEX_PUSH_LOCK_WAIT_BLOCK x = &WaitBlockBuffer;
118
119 #endif
120
121 /* INITIALIZATION FUNCTIONS *************************************************/
122
123 VOID
124 NTAPI
125 ExpWin32kInit(VOID);
126
127 VOID
128 NTAPI
129 ExInit2(VOID);
130
131 VOID
132 NTAPI
133 Phase1Initialization(
134 IN PVOID Context
135 );
136
137 VOID
138 NTAPI
139 ExpInitializePushLocks(VOID);
140
141 BOOLEAN
142 NTAPI
143 ExRefreshTimeZoneInformation(
144 IN PLARGE_INTEGER SystemBootTime
145 );
146
147 VOID
148 NTAPI
149 ExpInitializeWorkerThreads(VOID);
150
151 VOID
152 NTAPI
153 ExpInitLookasideLists(VOID);
154
155 VOID
156 NTAPI
157 ExInitializeSystemLookasideList(
158 IN PGENERAL_LOOKASIDE List,
159 IN POOL_TYPE Type,
160 IN ULONG Size,
161 IN ULONG Tag,
162 IN USHORT MaximumDepth,
163 IN PLIST_ENTRY ListHead
164 );
165
166 BOOLEAN
167 NTAPI
168 ExpInitializeCallbacks(VOID);
169
170 VOID
171 NTAPI
172 ExpInitUuids(VOID);
173
174 VOID
175 NTAPI
176 ExpInitializeExecutive(
177 IN ULONG Cpu,
178 IN PLOADER_PARAMETER_BLOCK LoaderBlock
179 );
180
181 VOID
182 NTAPI
183 ExpInitializeEventImplementation(VOID);
184
185 VOID
186 NTAPI
187 ExpInitializeEventImplementation(VOID);
188
189 VOID
190 NTAPI
191 ExpInitializeEventPairImplementation(VOID);
192
193 VOID
194 NTAPI
195 ExpInitializeSemaphoreImplementation(VOID);
196
197 VOID
198 NTAPI
199 ExpInitializeMutantImplementation(VOID);
200
201 VOID
202 NTAPI
203 ExpInitializeTimerImplementation(VOID);
204
205 VOID
206 NTAPI
207 ExpInitializeProfileImplementation(VOID);
208
209 VOID
210 NTAPI
211 ExpResourceInitialization(VOID);
212
213 VOID
214 NTAPI
215 ExInitPoolLookasidePointers(VOID);
216
217 /* Callback Functions ********************************************************/
218
219 VOID
220 NTAPI
221 ExInitializeCallBack(
222 IN OUT PEX_CALLBACK Callback
223 );
224
225 PEX_CALLBACK_ROUTINE_BLOCK
226 NTAPI
227 ExAllocateCallBack(
228 IN PEX_CALLBACK_FUNCTION Function,
229 IN PVOID Context
230 );
231
232 VOID
233 NTAPI
234 ExFreeCallBack(
235 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
236 );
237
238 BOOLEAN
239 NTAPI
240 ExCompareExchangeCallBack (
241 IN OUT PEX_CALLBACK CallBack,
242 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
243 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
244 );
245
246 PEX_CALLBACK_ROUTINE_BLOCK
247 NTAPI
248 ExReferenceCallBackBlock(
249 IN OUT PEX_CALLBACK CallBack
250 );
251
252 VOID
253 NTAPI
254 ExDereferenceCallBackBlock(
255 IN OUT PEX_CALLBACK CallBack,
256 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
257 );
258
259 PEX_CALLBACK_FUNCTION
260 NTAPI
261 ExGetCallBackBlockRoutine(
262 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
263 );
264
265 PVOID
266 NTAPI
267 ExGetCallBackBlockContext(
268 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
269 );
270
271 VOID
272 NTAPI
273 ExWaitForCallBacks(
274 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock
275 );
276
277 /* Rundown Functions ********************************************************/
278
279 VOID
280 FASTCALL
281 ExfInitializeRundownProtection(
282 OUT PEX_RUNDOWN_REF RunRef
283 );
284
285 VOID
286 FASTCALL
287 ExfReInitializeRundownProtection(
288 OUT PEX_RUNDOWN_REF RunRef
289 );
290
291 BOOLEAN
292 FASTCALL
293 ExfAcquireRundownProtection(
294 IN OUT PEX_RUNDOWN_REF RunRef
295 );
296
297 BOOLEAN
298 FASTCALL
299 ExfAcquireRundownProtectionEx(
300 IN OUT PEX_RUNDOWN_REF RunRef,
301 IN ULONG Count
302 );
303
304 VOID
305 FASTCALL
306 ExfReleaseRundownProtection(
307 IN OUT PEX_RUNDOWN_REF RunRef
308 );
309
310 VOID
311 FASTCALL
312 ExfReleaseRundownProtectionEx(
313 IN OUT PEX_RUNDOWN_REF RunRef,
314 IN ULONG Count
315 );
316
317 VOID
318 FASTCALL
319 ExfRundownCompleted(
320 OUT PEX_RUNDOWN_REF RunRef
321 );
322
323 VOID
324 FASTCALL
325 ExfWaitForRundownProtectionRelease(
326 IN OUT PEX_RUNDOWN_REF RunRef
327 );
328
329 /* HANDLE TABLE FUNCTIONS ***************************************************/
330
331 typedef BOOLEAN
332 (NTAPI *PEX_SWEEP_HANDLE_CALLBACK)(
333 PHANDLE_TABLE_ENTRY HandleTableEntry,
334 HANDLE Handle,
335 PVOID Context
336 );
337
338 typedef BOOLEAN
339 (NTAPI *PEX_DUPLICATE_HANDLE_CALLBACK)(
340 IN PEPROCESS Process,
341 IN PHANDLE_TABLE HandleTable,
342 IN PHANDLE_TABLE_ENTRY HandleTableEntry,
343 IN PHANDLE_TABLE_ENTRY NewEntry
344 );
345
346 typedef BOOLEAN
347 (NTAPI *PEX_CHANGE_HANDLE_CALLBACK)(
348 PHANDLE_TABLE_ENTRY HandleTableEntry,
349 ULONG_PTR Context
350 );
351
352 VOID
353 NTAPI
354 ExpInitializeHandleTables(
355 VOID
356 );
357
358 PHANDLE_TABLE
359 NTAPI
360 ExCreateHandleTable(
361 IN PEPROCESS Process OPTIONAL
362 );
363
364 VOID
365 NTAPI
366 ExUnlockHandleTableEntry(
367 IN PHANDLE_TABLE HandleTable,
368 IN PHANDLE_TABLE_ENTRY HandleTableEntry
369 );
370
371 HANDLE
372 NTAPI
373 ExCreateHandle(
374 IN PHANDLE_TABLE HandleTable,
375 IN PHANDLE_TABLE_ENTRY HandleTableEntry
376 );
377
378 VOID
379 NTAPI
380 ExDestroyHandleTable(
381 IN PHANDLE_TABLE HandleTable,
382 IN PVOID DestroyHandleProcedure OPTIONAL
383 );
384
385 BOOLEAN
386 NTAPI
387 ExDestroyHandle(
388 IN PHANDLE_TABLE HandleTable,
389 IN HANDLE Handle,
390 IN PHANDLE_TABLE_ENTRY HandleTableEntry OPTIONAL
391 );
392
393 PHANDLE_TABLE_ENTRY
394 NTAPI
395 ExMapHandleToPointer(
396 IN PHANDLE_TABLE HandleTable,
397 IN HANDLE Handle
398 );
399
400 PHANDLE_TABLE
401 NTAPI
402 ExDupHandleTable(
403 IN PEPROCESS Process,
404 IN PHANDLE_TABLE HandleTable,
405 IN PEX_DUPLICATE_HANDLE_CALLBACK DupHandleProcedure,
406 IN ULONG_PTR Mask
407 );
408
409 BOOLEAN
410 NTAPI
411 ExChangeHandle(
412 IN PHANDLE_TABLE HandleTable,
413 IN HANDLE Handle,
414 IN PEX_CHANGE_HANDLE_CALLBACK ChangeRoutine,
415 IN ULONG_PTR Context
416 );
417
418 VOID
419 NTAPI
420 ExSweepHandleTable(
421 IN PHANDLE_TABLE HandleTable,
422 IN PEX_SWEEP_HANDLE_CALLBACK EnumHandleProcedure,
423 IN PVOID Context
424 );
425
426 /* PSEH EXCEPTION HANDLING **************************************************/
427
428 LONG
429 NTAPI
430 ExSystemExceptionFilter(VOID);
431
432 static __inline _SEH_FILTER(_SEH_ExSystemExceptionFilter)
433 {
434 return ExSystemExceptionFilter();
435 }
436
437 /* CALLBACKS *****************************************************************/
438
439 VOID
440 FORCEINLINE
441 ExDoCallBack(IN OUT PEX_CALLBACK Callback,
442 IN PVOID Context,
443 IN PVOID Argument1,
444 IN PVOID Argument2)
445 {
446 PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock;
447 PEX_CALLBACK_FUNCTION Function;
448
449 /* Reference the block */
450 CallbackRoutineBlock = ExReferenceCallBackBlock(Callback);
451 if (CallbackRoutineBlock)
452 {
453 /* Get the function */
454 Function = ExGetCallBackBlockRoutine(CallbackRoutineBlock);
455
456 /* Do the callback */
457 Function(Context, Argument1, Argument2);
458
459 /* Now dereference it */
460 ExDereferenceCallBackBlock(Callback, CallbackRoutineBlock);
461 }
462 }
463
464 /* RUNDOWN *******************************************************************/
465
466 #ifdef _WIN64
467 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
468 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
469 #else
470 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z))
471 #define ExpChangePushlock(x, y, z) LongToPtr(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
472 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
473 #endif
474
475 /*++
476 * @name ExfAcquireRundownProtection
477 * INTERNAL MACRO
478 *
479 * The ExfAcquireRundownProtection routine acquires rundown protection for
480 * the specified descriptor.
481 *
482 * @param RunRef
483 * Pointer to a rundown reference descriptor.
484 *
485 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
486 *
487 * @remarks This is the internal macro for system use only.In case the rundown
488 * was active, then the slow-path will be called through the exported
489 * function.
490 *
491 *--*/
492 BOOLEAN
493 FORCEINLINE
494 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
495 {
496 ULONG_PTR Value, NewValue;
497
498 /* Get the current value and mask the active bit */
499 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
500
501 /* Add a reference */
502 NewValue = Value + EX_RUNDOWN_COUNT_INC;
503
504 /* Change the value */
505 NewValue = ExpChangeRundown(RunRef, NewValue, Value);
506 if (NewValue != Value)
507 {
508 /* Rundown was active, use long path */
509 return ExfAcquireRundownProtection(RunRef);
510 }
511
512 /* Success */
513 return TRUE;
514 }
515
516 /*++
517 * @name ExReleaseRundownProtection
518 * INTERNAL MACRO
519 *
520 * The ExReleaseRundownProtection routine releases rundown protection for
521 * the specified descriptor.
522 *
523 * @param RunRef
524 * Pointer to a rundown reference descriptor.
525 *
526 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
527 *
528 * @remarks This is the internal macro for system use only.In case the rundown
529 * was active, then the slow-path will be called through the exported
530 * function.
531 *
532 *--*/
533 VOID
534 FORCEINLINE
535 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
536 {
537 ULONG_PTR Value, NewValue;
538
539 /* Get the current value and mask the active bit */
540 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
541
542 /* Remove a reference */
543 NewValue = Value - EX_RUNDOWN_COUNT_INC;
544
545 /* Change the value */
546 NewValue = ExpChangeRundown(RunRef, NewValue, Value);
547
548 /* Check if the rundown was active */
549 if (NewValue != Value)
550 {
551 /* Rundown was active, use long path */
552 ExfReleaseRundownProtection(RunRef);
553 }
554 else
555 {
556 /* Sanity check */
557 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
558 }
559 }
560
561 /*++
562 * @name ExInitializeRundownProtection
563 * INTERNAL MACRO
564 *
565 * The ExInitializeRundownProtection routine initializes a rundown
566 * protection descriptor.
567 *
568 * @param RunRef
569 * Pointer to a rundown reference descriptor.
570 *
571 * @return None.
572 *
573 * @remarks This is the internal macro for system use only.
574 *
575 *--*/
576 VOID
577 FORCEINLINE
578 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
579 {
580 /* Set the count to zero */
581 RunRef->Count = 0;
582 }
583
584 /*++
585 * @name ExWaitForRundownProtectionRelease
586 * INTERNAL MACRO
587 *
588 * The ExWaitForRundownProtectionRelease routine waits until the specified
589 * rundown descriptor has been released.
590 *
591 * @param RunRef
592 * Pointer to a rundown reference descriptor.
593 *
594 * @return None.
595 *
596 * @remarks This is the internal macro for system use only. If a wait is actually
597 * necessary, then the slow path is taken through the exported function.
598 *
599 *--*/
600 VOID
601 FORCEINLINE
602 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
603 {
604 ULONG_PTR Value;
605
606 /* Set the active bit */
607 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
608 if ((Value) && (Value != EX_RUNDOWN_ACTIVE))
609 {
610 /* If the the rundown wasn't already active, then take the long path */
611 ExfWaitForRundownProtectionRelease(RunRef);
612 }
613 }
614
615 /*++
616 * @name ExRundownCompleted
617 * INTERNAL MACRO
618 *
619 * The ExRundownCompleted routine completes the rundown of the specified
620 * descriptor by setting the active bit.
621 *
622 * @param RunRef
623 * Pointer to a rundown reference descriptor.
624 *
625 * @return None.
626 *
627 * @remarks This is the internal macro for system use only.
628 *
629 *--*/
630 VOID
631 FORCEINLINE
632 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
633 {
634 /* Sanity check */
635 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
636
637 /* Mark the counter as active */
638 ExpSetRundown(&RunRef->Count, EX_RUNDOWN_ACTIVE);
639 }
640
641 /* PUSHLOCKS *****************************************************************/
642
643 /* FIXME: VERIFY THESE! */
644
645 VOID
646 FASTCALL
647 ExBlockPushLock(
648 IN PEX_PUSH_LOCK PushLock,
649 IN PVOID WaitBlock
650 );
651
652 VOID
653 FASTCALL
654 ExfUnblockPushLock(
655 IN PEX_PUSH_LOCK PushLock,
656 IN PVOID CurrentWaitBlock
657 );
658
659 VOID
660 FASTCALL
661 ExWaitForUnblockPushLock(
662 IN PEX_PUSH_LOCK PushLock,
663 IN PVOID WaitBlock
664 );
665
666 /*++
667 * @name ExInitializePushLock
668 * INTERNAL MACRO
669 *
670 * The ExInitializePushLock macro initializes a PushLock.
671 *
672 * @params PushLock
673 * Pointer to the pushlock which is to be initialized.
674 *
675 * @return None.
676 *
677 * @remarks None.
678 *
679 *--*/
680 VOID
681 FORCEINLINE
682 ExInitializePushLock(IN PULONG_PTR PushLock)
683 {
684 /* Set the value to 0 */
685 *PushLock = 0;
686 }
687
688 /*++
689 * @name ExAcquirePushLockExclusive
690 * INTERNAL MACRO
691 *
692 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
693 *
694 * @params PushLock
695 * Pointer to the pushlock which is to be acquired.
696 *
697 * @return None.
698 *
699 * @remarks The function attempts the quickest route to acquire the lock, which is
700 * to simply set the lock bit.
701 * However, if the pushlock is already shared, the slower path is taken.
702 *
703 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
704 * This macro should usually be paired up with KeAcquireCriticalRegion.
705 *
706 *--*/
707 VOID
708 FORCEINLINE
709 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
710 {
711 /* Try acquiring the lock */
712 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
713 {
714 /* Someone changed it, use the slow path */
715 ExfAcquirePushLockExclusive(PushLock);
716 }
717
718 /* Sanity check */
719 ASSERT(PushLock->Locked);
720 }
721
722 /*++
723 * @name ExTryToAcquirePushLockExclusive
724 * INTERNAL MACRO
725 *
726 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
727 *
728 * @params PushLock
729 * Pointer to the pushlock which is to be acquired.
730 *
731 * @return None.
732 *
733 * @remarks The function attempts the quickest route to acquire the lock, which is
734 * to simply set the lock bit.
735 * However, if the pushlock is already shared, the slower path is taken.
736 *
737 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
738 * This macro should usually be paired up with KeAcquireCriticalRegion.
739 *
740 *--*/
741 BOOLEAN
742 FORCEINLINE
743 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
744 {
745 /* Try acquiring the lock */
746 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
747 {
748 /* Can't acquire */
749 return FALSE;
750 }
751
752 /* Got acquired */
753 ASSERT (PushLock->Locked);
754 return TRUE;
755 }
756
757 /*++
758 * @name ExAcquirePushLockShared
759 * INTERNAL MACRO
760 *
761 * The ExAcquirePushLockShared macro acquires a shared PushLock.
762 *
763 * @params PushLock
764 * Pointer to the pushlock which is to be acquired.
765 *
766 * @return None.
767 *
768 * @remarks The function attempts the quickest route to acquire the lock, which is
769 * to simply set the lock bit and set the share count to one.
770 * However, if the pushlock is already shared, the slower path is taken.
771 *
772 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
773 * This macro should usually be paired up with KeAcquireCriticalRegion.
774 *
775 *--*/
776 VOID
777 FORCEINLINE
778 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
779 {
780 EX_PUSH_LOCK NewValue;
781
782 /* Try acquiring the lock */
783 NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
784 if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
785 {
786 /* Someone changed it, use the slow path */
787 ExfAcquirePushLockShared(PushLock);
788 }
789
790 /* Sanity checks */
791 ASSERT(PushLock->Locked);
792 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
793 }
794
795 /*++
796 * @name ExConvertPushLockSharedToExclusive
797 * INTERNAL MACRO
798 *
799 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
800 * pushlock to a shared pushlock.
801 *
802 * @params PushLock
803 * Pointer to the pushlock which is to be converted.
804 *
805 * @return FALSE if conversion failed, TRUE otherwise.
806 *
807 * @remarks The function attempts the quickest route to convert the lock, which is
808 * to simply set the lock bit and remove any other bits.
809 *
810 *--*/
811 BOOLEAN
812 FORCEINLINE
813 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock)
814 {
815 EX_PUSH_LOCK OldValue;
816
817 /* Set the expected old value */
818 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
819
820 /* Try converting the lock */
821 if (ExpChangePushlock(PushLock, EX_PUSH_LOCK_LOCK, OldValue.Value) !=
822 OldValue.Ptr)
823 {
824 /* Conversion failed */
825 return FALSE;
826 }
827
828 /* Sanity check */
829 ASSERT(PushLock->Locked);
830 return TRUE;
831 }
832
833 /*++
834 * @name ExWaitOnPushLock
835 * INTERNAL MACRO
836 *
837 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
838 *
839 * @params PushLock
840 * Pointer to a pushlock.
841 *
842 * @return None.
843 *
844 * @remarks The function attempts to get any exclusive waiters out of their slow
845 * path by forcing an instant acquire/release operation.
846 *
847 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
848 *
849 *--*/
850 VOID
851 FORCEINLINE
852 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
853 {
854 /* Check if we're locked */
855 if (PushLock->Locked)
856 {
857 /* Acquire the lock */
858 ExfAcquirePushLockExclusive(PushLock);
859 ASSERT(PushLock->Locked);
860
861 /* Release it */
862 ExfReleasePushLockExclusive(PushLock);
863 }
864 }
865
866 /*++
867 * @name ExReleasePushLockShared
868 * INTERNAL MACRO
869 *
870 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
871 *
872 * @params PushLock
873 * Pointer to a previously acquired pushlock.
874 *
875 * @return None.
876 *
877 * @remarks The function attempts the quickest route to release the lock, which is
878 * to simply decrease the share count and remove the lock bit.
879 * However, if the pushlock is being waited on then the long path is taken.
880 *
881 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
882 * This macro should usually be paired up with KeLeaveCriticalRegion.
883 *
884 *--*/
885 VOID
886 FORCEINLINE
887 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
888 {
889 EX_PUSH_LOCK OldValue;
890
891 /* Sanity checks */
892 ASSERT(PushLock->Locked);
893 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
894
895 /* Try to clear the pushlock */
896 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
897 if (ExpChangePushlock(PushLock, 0, OldValue.Ptr) != OldValue.Ptr)
898 {
899 /* There are still other people waiting on it */
900 ExfReleasePushLockShared(PushLock);
901 }
902 }
903
904 /*++
905 * @name ExReleasePushLockExclusive
906 * INTERNAL MACRO
907 *
908 * The ExReleasePushLockExclusive macro releases a previously
909 * exclusively acquired PushLock.
910 *
911 * @params PushLock
912 * Pointer to a previously acquired pushlock.
913 *
914 * @return None.
915 *
916 * @remarks The function attempts the quickest route to release the lock, which is
917 * to simply clear the locked bit.
918 * However, if the pushlock is being waited on, the slow path is taken
919 * in an attempt to wake up the lock.
920 *
921 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
922 * This macro should usually be paired up with KeLeaveCriticalRegion.
923 *
924 *--*/
925 VOID
926 FORCEINLINE
927 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
928 {
929 EX_PUSH_LOCK OldValue;
930
931 /* Sanity checks */
932 ASSERT(PushLock->Locked);
933 ASSERT(PushLock->Waiting || PushLock->Shared == 0);
934
935 /* Unlock the pushlock */
936 OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock,
937 -(LONG)EX_PUSH_LOCK_LOCK);
938
939 /* Sanity checks */
940 ASSERT(OldValue.Locked);
941 ASSERT(OldValue.Waiting || OldValue.Shared == 0);
942
943 /* Check if anyone is waiting on it and it's not already waking*/
944 if ((OldValue.Waiting) && !(OldValue.Waking))
945 {
946 /* Wake it up */
947 ExfTryToWakePushLock(PushLock);
948 }
949 }
950
951 /*++
952 * @name ExReleasePushLock
953 * INTERNAL MACRO
954 *
955 * The ExReleasePushLock macro releases a previously acquired PushLock.
956 *
957 * @params PushLock
958 * Pointer to a previously acquired pushlock.
959 *
960 * @return None.
961 *
962 * @remarks The function attempts the quickest route to release the lock, which is
963 * to simply clear all the fields and decrease the share count if required.
964 * However, if the pushlock is being waited on then the long path is taken.
965 *
966 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
967 * This macro should usually be paired up with KeLeaveCriticalRegion.
968 *
969 *--*/
970 VOID
971 FORCEINLINE
972 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
973 {
974 EX_PUSH_LOCK OldValue = *PushLock;
975 EX_PUSH_LOCK NewValue;
976
977 /* Sanity checks */
978 ASSERT(OldValue.Locked);
979
980 /* Check if the pushlock is shared */
981 if (OldValue.Shared > 1)
982 {
983 /* Decrease the share count */
984 NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
985 }
986 else
987 {
988 /* Clear the pushlock entirely */
989 NewValue.Value = 0;
990 }
991
992 /* Check if nobody is waiting on us and try clearing the lock here */
993 if ((OldValue.Waiting) ||
994 (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
995 OldValue.Ptr))
996 {
997 /* We have waiters, use the long path */
998 ExfReleasePushLock(PushLock);
999 }
1000 }
1001
1002 /* OTHER FUNCTIONS **********************************************************/
1003
1004 BOOLEAN
1005 NTAPI
1006 ExTryToAcquireResourceExclusiveLite(
1007 IN PERESOURCE Resource
1008 );
1009
1010 LONGLONG
1011 FASTCALL
1012 ExfpInterlockedExchange64(
1013 LONGLONG volatile * Destination,
1014 PLONGLONG Exchange
1015 );
1016
1017 NTSTATUS
1018 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation);
1019
1020 BOOLEAN
1021 NTAPI
1022 ExAcquireTimeRefreshLock(BOOLEAN Wait);
1023
1024 VOID
1025 NTAPI
1026 ExReleaseTimeRefreshLock(VOID);
1027
1028 VOID
1029 NTAPI
1030 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime,
1031 IN ULONG MaxSepInSeconds);
1032
1033 NTSTATUS
1034 NTAPI
1035 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId);
1036
1037 VOID
1038 NTAPI
1039 ExTimerRundown(VOID);
1040
1041 VOID
1042 NTAPI
1043 HeadlessInit(
1044 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1045 );
1046
1047 VOID
1048 NTAPI
1049 XIPInit(
1050 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1051 );
1052
1053 #define InterlockedDecrementUL(Addend) \
1054 (ULONG)InterlockedDecrement((PLONG)(Addend))
1055
1056 #define InterlockedIncrementUL(Addend) \
1057 (ULONG)InterlockedIncrement((PLONG)(Addend))
1058
1059 #define InterlockedExchangeUL(Target, Value) \
1060 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1061
1062 #define InterlockedExchangeAddUL(Addend, Value) \
1063 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1064
1065 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1066 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1067
1068 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1069 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
1070
1071 #define ExfpInterlockedExchange64UL(Target, Value) \
1072 (ULONGLONG)ExfpInterlockedExchange64((PLONGLONG)(Target), (PLONGLONG)(Value))
1073
1074 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */