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