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