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