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