Sync to trunk head(r38096)
[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 old GCC
96 //
97 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40300)
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 /* CALLBACKS *****************************************************************/
433
434 FORCEINLINE
435 VOID
436 ExDoCallBack(IN OUT PEX_CALLBACK Callback,
437 IN PVOID Context,
438 IN PVOID Argument1,
439 IN PVOID Argument2)
440 {
441 PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock;
442 PEX_CALLBACK_FUNCTION Function;
443
444 /* Reference the block */
445 CallbackRoutineBlock = ExReferenceCallBackBlock(Callback);
446 if (CallbackRoutineBlock)
447 {
448 /* Get the function */
449 Function = ExGetCallBackBlockRoutine(CallbackRoutineBlock);
450
451 /* Do the callback */
452 Function(Context, Argument1, Argument2);
453
454 /* Now dereference it */
455 ExDereferenceCallBackBlock(Callback, CallbackRoutineBlock);
456 }
457 }
458
459 /* RUNDOWN *******************************************************************/
460
461 #ifdef _WIN64
462 #define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z)
463 #define ExpChangePushlock(lock, new, old) InterlockedCompareExchangePointer((PVOID*)lock, (PVOID)new, (PVOID)old)
464 #define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y)
465 #else
466 #define ExpChangeRundown(x, y, z) PtrToUlong(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
467 #define ExpChangePushlock(x, y, z) LongToPtr(InterlockedCompareExchange((PLONG)x, PtrToLong(y), PtrToLong(z)))
468 #define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y)
469 #endif
470
471 /*++
472 * @name ExfAcquireRundownProtection
473 * INTERNAL MACRO
474 *
475 * The ExfAcquireRundownProtection routine acquires rundown protection for
476 * the specified descriptor.
477 *
478 * @param RunRef
479 * Pointer to a rundown reference descriptor.
480 *
481 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
482 *
483 * @remarks This is the internal macro for system use only.In case the rundown
484 * was active, then the slow-path will be called through the exported
485 * function.
486 *
487 *--*/
488 FORCEINLINE
489 BOOLEAN
490 _ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef)
491 {
492 ULONG_PTR Value, NewValue;
493
494 /* Get the current value and mask the active bit */
495 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
496
497 /* Add a reference */
498 NewValue = Value + EX_RUNDOWN_COUNT_INC;
499
500 /* Change the value */
501 NewValue = ExpChangeRundown(RunRef, NewValue, Value);
502 if (NewValue != Value)
503 {
504 /* Rundown was active, use long path */
505 return ExfAcquireRundownProtection(RunRef);
506 }
507
508 /* Success */
509 return TRUE;
510 }
511
512 /*++
513 * @name ExReleaseRundownProtection
514 * INTERNAL MACRO
515 *
516 * The ExReleaseRundownProtection routine releases rundown protection for
517 * the specified descriptor.
518 *
519 * @param RunRef
520 * Pointer to a rundown reference descriptor.
521 *
522 * @return TRUE if access to the protected structure was granted, FALSE otherwise.
523 *
524 * @remarks This is the internal macro for system use only.In case the rundown
525 * was active, then the slow-path will be called through the exported
526 * function.
527 *
528 *--*/
529 FORCEINLINE
530 VOID
531 _ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef)
532 {
533 ULONG_PTR Value, NewValue;
534
535 /* Get the current value and mask the active bit */
536 Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE;
537
538 /* Remove a reference */
539 NewValue = Value - EX_RUNDOWN_COUNT_INC;
540
541 /* Change the value */
542 NewValue = ExpChangeRundown(RunRef, NewValue, Value);
543
544 /* Check if the rundown was active */
545 if (NewValue != Value)
546 {
547 /* Rundown was active, use long path */
548 ExfReleaseRundownProtection(RunRef);
549 }
550 else
551 {
552 /* Sanity check */
553 ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
554 }
555 }
556
557 /*++
558 * @name ExInitializeRundownProtection
559 * INTERNAL MACRO
560 *
561 * The ExInitializeRundownProtection routine initializes a rundown
562 * protection descriptor.
563 *
564 * @param RunRef
565 * Pointer to a rundown reference descriptor.
566 *
567 * @return None.
568 *
569 * @remarks This is the internal macro for system use only.
570 *
571 *--*/
572 FORCEINLINE
573 VOID
574 _ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef)
575 {
576 /* Set the count to zero */
577 RunRef->Count = 0;
578 }
579
580 /*++
581 * @name ExWaitForRundownProtectionRelease
582 * INTERNAL MACRO
583 *
584 * The ExWaitForRundownProtectionRelease routine waits until the specified
585 * rundown descriptor has been released.
586 *
587 * @param RunRef
588 * Pointer to a rundown reference descriptor.
589 *
590 * @return None.
591 *
592 * @remarks This is the internal macro for system use only. If a wait is actually
593 * necessary, then the slow path is taken through the exported function.
594 *
595 *--*/
596 FORCEINLINE
597 VOID
598 _ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
599 {
600 ULONG_PTR Value;
601
602 /* Set the active bit */
603 Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0);
604 if ((Value) && (Value != EX_RUNDOWN_ACTIVE))
605 {
606 /* If the the rundown wasn't already active, then take the long path */
607 ExfWaitForRundownProtectionRelease(RunRef);
608 }
609 }
610
611 /*++
612 * @name ExRundownCompleted
613 * INTERNAL MACRO
614 *
615 * The ExRundownCompleted routine completes the rundown of the specified
616 * descriptor by setting the active bit.
617 *
618 * @param RunRef
619 * Pointer to a rundown reference descriptor.
620 *
621 * @return None.
622 *
623 * @remarks This is the internal macro for system use only.
624 *
625 *--*/
626 FORCEINLINE
627 VOID
628 _ExRundownCompleted(IN PEX_RUNDOWN_REF RunRef)
629 {
630 /* Sanity check */
631 ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
632
633 /* Mark the counter as active */
634 ExpSetRundown(&RunRef->Count, EX_RUNDOWN_ACTIVE);
635 }
636
637 /* PUSHLOCKS *****************************************************************/
638
639 /* FIXME: VERIFY THESE! */
640
641 VOID
642 FASTCALL
643 ExBlockPushLock(
644 IN PEX_PUSH_LOCK PushLock,
645 IN PVOID WaitBlock
646 );
647
648 VOID
649 FASTCALL
650 ExfUnblockPushLock(
651 IN PEX_PUSH_LOCK PushLock,
652 IN PVOID CurrentWaitBlock
653 );
654
655 VOID
656 FASTCALL
657 ExWaitForUnblockPushLock(
658 IN PEX_PUSH_LOCK PushLock,
659 IN PVOID WaitBlock
660 );
661
662 /*++
663 * @name ExInitializePushLock
664 * INTERNAL MACRO
665 *
666 * The ExInitializePushLock macro initializes a PushLock.
667 *
668 * @params PushLock
669 * Pointer to the pushlock which is to be initialized.
670 *
671 * @return None.
672 *
673 * @remarks None.
674 *
675 *--*/
676 FORCEINLINE
677 VOID
678 ExInitializePushLock(IN PULONG_PTR PushLock)
679 {
680 /* Set the value to 0 */
681 *PushLock = 0;
682 }
683
684 /*++
685 * @name ExAcquirePushLockExclusive
686 * INTERNAL MACRO
687 *
688 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
689 *
690 * @params PushLock
691 * Pointer to the pushlock which is to be acquired.
692 *
693 * @return None.
694 *
695 * @remarks The function attempts the quickest route to acquire the lock, which is
696 * to simply set the lock bit.
697 * However, if the pushlock is already shared, the slower path is taken.
698 *
699 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
700 * This macro should usually be paired up with KeAcquireCriticalRegion.
701 *
702 *--*/
703 FORCEINLINE
704 VOID
705 ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
706 {
707 /* Try acquiring the lock */
708 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
709 {
710 /* Someone changed it, use the slow path */
711 ExfAcquirePushLockExclusive(PushLock);
712 }
713
714 /* Sanity check */
715 ASSERT(PushLock->Locked);
716 }
717
718 /*++
719 * @name ExTryToAcquirePushLockExclusive
720 * INTERNAL MACRO
721 *
722 * The ExAcquirePushLockExclusive macro exclusively acquires a PushLock.
723 *
724 * @params PushLock
725 * Pointer to the pushlock which is to be acquired.
726 *
727 * @return None.
728 *
729 * @remarks The function attempts the quickest route to acquire the lock, which is
730 * to simply set the lock bit.
731 * However, if the pushlock is already shared, the slower path is taken.
732 *
733 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
734 * This macro should usually be paired up with KeAcquireCriticalRegion.
735 *
736 *--*/
737 FORCEINLINE
738 BOOLEAN
739 ExTryToAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
740 {
741 /* Try acquiring the lock */
742 if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
743 {
744 /* Can't acquire */
745 return FALSE;
746 }
747
748 /* Got acquired */
749 ASSERT (PushLock->Locked);
750 return TRUE;
751 }
752
753 /*++
754 * @name ExAcquirePushLockShared
755 * INTERNAL MACRO
756 *
757 * The ExAcquirePushLockShared macro acquires a shared PushLock.
758 *
759 * @params PushLock
760 * Pointer to the pushlock which is to be acquired.
761 *
762 * @return None.
763 *
764 * @remarks The function attempts the quickest route to acquire the lock, which is
765 * to simply set the lock bit and set the share count to one.
766 * However, if the pushlock is already shared, the slower path is taken.
767 *
768 * Callers of ExAcquirePushLockShared must be running at IRQL <= APC_LEVEL.
769 * This macro should usually be paired up with KeAcquireCriticalRegion.
770 *
771 *--*/
772 FORCEINLINE
773 VOID
774 ExAcquirePushLockShared(PEX_PUSH_LOCK PushLock)
775 {
776 EX_PUSH_LOCK NewValue;
777
778 /* Try acquiring the lock */
779 NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
780 if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
781 {
782 /* Someone changed it, use the slow path */
783 ExfAcquirePushLockShared(PushLock);
784 }
785
786 /* Sanity checks */
787 ASSERT(PushLock->Locked);
788 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
789 }
790
791 /*++
792 * @name ExConvertPushLockSharedToExclusive
793 * INTERNAL MACRO
794 *
795 * The ExConvertPushLockSharedToExclusive macro converts an exclusive
796 * pushlock to a shared pushlock.
797 *
798 * @params PushLock
799 * Pointer to the pushlock which is to be converted.
800 *
801 * @return FALSE if conversion failed, TRUE otherwise.
802 *
803 * @remarks The function attempts the quickest route to convert the lock, which is
804 * to simply set the lock bit and remove any other bits.
805 *
806 *--*/
807 FORCEINLINE
808 BOOLEAN
809 ExConvertPushLockSharedToExclusive(IN PEX_PUSH_LOCK PushLock)
810 {
811 EX_PUSH_LOCK OldValue;
812
813 /* Set the expected old value */
814 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
815
816 /* Try converting the lock */
817 if (ExpChangePushlock(PushLock, EX_PUSH_LOCK_LOCK, OldValue.Value) !=
818 OldValue.Ptr)
819 {
820 /* Conversion failed */
821 return FALSE;
822 }
823
824 /* Sanity check */
825 ASSERT(PushLock->Locked);
826 return TRUE;
827 }
828
829 /*++
830 * @name ExWaitOnPushLock
831 * INTERNAL MACRO
832 *
833 * The ExWaitOnPushLock macro acquires and instantly releases a pushlock.
834 *
835 * @params PushLock
836 * Pointer to a pushlock.
837 *
838 * @return None.
839 *
840 * @remarks The function attempts to get any exclusive waiters out of their slow
841 * path by forcing an instant acquire/release operation.
842 *
843 * Callers of ExWaitOnPushLock must be running at IRQL <= APC_LEVEL.
844 *
845 *--*/
846 FORCEINLINE
847 VOID
848 ExWaitOnPushLock(PEX_PUSH_LOCK PushLock)
849 {
850 /* Check if we're locked */
851 if (PushLock->Locked)
852 {
853 /* Acquire the lock */
854 ExfAcquirePushLockExclusive(PushLock);
855 ASSERT(PushLock->Locked);
856
857 /* Release it */
858 ExfReleasePushLockExclusive(PushLock);
859 }
860 }
861
862 /*++
863 * @name ExReleasePushLockShared
864 * INTERNAL MACRO
865 *
866 * The ExReleasePushLockShared macro releases a previously acquired PushLock.
867 *
868 * @params PushLock
869 * Pointer to a previously acquired pushlock.
870 *
871 * @return None.
872 *
873 * @remarks The function attempts the quickest route to release the lock, which is
874 * to simply decrease the share count and remove the lock bit.
875 * However, if the pushlock is being waited on then the long path is taken.
876 *
877 * Callers of ExReleasePushLockShared must be running at IRQL <= APC_LEVEL.
878 * This macro should usually be paired up with KeLeaveCriticalRegion.
879 *
880 *--*/
881 FORCEINLINE
882 VOID
883 ExReleasePushLockShared(PEX_PUSH_LOCK PushLock)
884 {
885 EX_PUSH_LOCK OldValue;
886
887 /* Sanity checks */
888 ASSERT(PushLock->Locked);
889 ASSERT(PushLock->Waiting || PushLock->Shared > 0);
890
891 /* Try to clear the pushlock */
892 OldValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
893 if (ExpChangePushlock(PushLock, 0, OldValue.Ptr) != OldValue.Ptr)
894 {
895 /* There are still other people waiting on it */
896 ExfReleasePushLockShared(PushLock);
897 }
898 }
899
900 /*++
901 * @name ExReleasePushLockExclusive
902 * INTERNAL MACRO
903 *
904 * The ExReleasePushLockExclusive macro releases a previously
905 * exclusively acquired PushLock.
906 *
907 * @params PushLock
908 * Pointer to a previously acquired pushlock.
909 *
910 * @return None.
911 *
912 * @remarks The function attempts the quickest route to release the lock, which is
913 * to simply clear the locked bit.
914 * However, if the pushlock is being waited on, the slow path is taken
915 * in an attempt to wake up the lock.
916 *
917 * Callers of ExReleasePushLockExclusive must be running at IRQL <= APC_LEVEL.
918 * This macro should usually be paired up with KeLeaveCriticalRegion.
919 *
920 *--*/
921 FORCEINLINE
922 VOID
923 ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
924 {
925 EX_PUSH_LOCK OldValue;
926
927 /* Sanity checks */
928 ASSERT(PushLock->Locked);
929 ASSERT(PushLock->Waiting || PushLock->Shared == 0);
930
931 /* Unlock the pushlock */
932 OldValue.Value = InterlockedExchangeAddSizeT((PSIZE_T)PushLock,
933 -(SIZE_T)EX_PUSH_LOCK_LOCK);
934
935 /* Sanity checks */
936 ASSERT(OldValue.Locked);
937 ASSERT(OldValue.Waiting || OldValue.Shared == 0);
938
939 /* Check if anyone is waiting on it and it's not already waking*/
940 if ((OldValue.Waiting) && !(OldValue.Waking))
941 {
942 /* Wake it up */
943 ExfTryToWakePushLock(PushLock);
944 }
945 }
946
947 /*++
948 * @name ExReleasePushLock
949 * INTERNAL MACRO
950 *
951 * The ExReleasePushLock macro releases a previously acquired PushLock.
952 *
953 * @params PushLock
954 * Pointer to a previously acquired pushlock.
955 *
956 * @return None.
957 *
958 * @remarks The function attempts the quickest route to release the lock, which is
959 * to simply clear all the fields and decrease the share count if required.
960 * However, if the pushlock is being waited on then the long path is taken.
961 *
962 * Callers of ExReleasePushLock must be running at IRQL <= APC_LEVEL.
963 * This macro should usually be paired up with KeLeaveCriticalRegion.
964 *
965 *--*/
966 FORCEINLINE
967 VOID
968 ExReleasePushLock(PEX_PUSH_LOCK PushLock)
969 {
970 EX_PUSH_LOCK OldValue = *PushLock;
971 EX_PUSH_LOCK NewValue;
972
973 /* Sanity checks */
974 ASSERT(OldValue.Locked);
975
976 /* Check if the pushlock is shared */
977 if (OldValue.Shared > 1)
978 {
979 /* Decrease the share count */
980 NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
981 }
982 else
983 {
984 /* Clear the pushlock entirely */
985 NewValue.Value = 0;
986 }
987
988 /* Check if nobody is waiting on us and try clearing the lock here */
989 if ((OldValue.Waiting) ||
990 (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
991 OldValue.Ptr))
992 {
993 /* We have waiters, use the long path */
994 ExfReleasePushLock(PushLock);
995 }
996 }
997
998 /* OTHER FUNCTIONS **********************************************************/
999
1000 BOOLEAN
1001 NTAPI
1002 ExTryToAcquireResourceExclusiveLite(
1003 IN PERESOURCE Resource
1004 );
1005
1006 NTSTATUS
1007 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation);
1008
1009 BOOLEAN
1010 NTAPI
1011 ExAcquireTimeRefreshLock(BOOLEAN Wait);
1012
1013 VOID
1014 NTAPI
1015 ExReleaseTimeRefreshLock(VOID);
1016
1017 VOID
1018 NTAPI
1019 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime,
1020 IN ULONG MaxSepInSeconds);
1021
1022 NTSTATUS
1023 NTAPI
1024 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId);
1025
1026 VOID
1027 NTAPI
1028 ExTimerRundown(VOID);
1029
1030 VOID
1031 NTAPI
1032 HeadlessInit(
1033 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1034 );
1035
1036 VOID
1037 NTAPI
1038 XIPInit(
1039 IN PLOADER_PARAMETER_BLOCK LoaderBlock
1040 );
1041
1042 #define InterlockedDecrementUL(Addend) \
1043 (ULONG)InterlockedDecrement((PLONG)(Addend))
1044
1045 #define InterlockedIncrementUL(Addend) \
1046 (ULONG)InterlockedIncrement((PLONG)(Addend))
1047
1048 #define InterlockedExchangeUL(Target, Value) \
1049 (ULONG)InterlockedExchange((PLONG)(Target), (LONG)(Value))
1050
1051 #define InterlockedExchangeAddUL(Addend, Value) \
1052 (ULONG)InterlockedExchangeAdd((PLONG)(Addend), (LONG)(Value))
1053
1054 #define InterlockedCompareExchangeUL(Destination, Exchange, Comperand) \
1055 (ULONG)InterlockedCompareExchange((PLONG)(Destination), (LONG)(Exchange), (LONG)(Comperand))
1056
1057 #define ExfInterlockedCompareExchange64UL(Destination, Exchange, Comperand) \
1058 (ULONGLONG)ExfInterlockedCompareExchange64((PLONGLONG)(Destination), (PLONGLONG)(Exchange), (PLONGLONG)(Comperand))
1059
1060 #endif /* __NTOSKRNL_INCLUDE_INTERNAL_EXECUTIVE_H */