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