ReactOS 0.4.15-dev-8339-g4028de8
apc.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for apc.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

VOID NTAPI KiCheckForKernelApcDelivery (VOID)
 
VOID FASTCALL KiInsertQueueApc (IN PKAPC Apc, IN KPRIORITY PriorityBoost)
 
VOID NTAPI KiDeliverApc (IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
 
FORCEINLINE VOID RepairList (IN PLIST_ENTRY Original, IN PLIST_ENTRY Copy, IN KPROCESSOR_MODE Mode)
 
VOID NTAPI KiMoveApcState (PKAPC_STATE OldState, PKAPC_STATE NewState)
 
VOID NTAPI _KeEnterCriticalRegion (VOID)
 
VOID NTAPI _KeLeaveCriticalRegion (VOID)
 
VOID NTAPI KeInitializeApc (IN PKAPC Apc, IN PKTHREAD Thread, IN KAPC_ENVIRONMENT TargetEnvironment, IN PKKERNEL_ROUTINE KernelRoutine, IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, IN PKNORMAL_ROUTINE NormalRoutine, IN KPROCESSOR_MODE Mode, IN PVOID Context)
 
BOOLEAN NTAPI KeInsertQueueApc (IN PKAPC Apc, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN KPRIORITY PriorityBoost)
 
PLIST_ENTRY NTAPI KeFlushQueueApc (IN PKTHREAD Thread, IN KPROCESSOR_MODE PreviousMode)
 
BOOLEAN NTAPI KeRemoveQueueApc (IN PKAPC Apc)
 
BOOLEAN NTAPI KeAreApcsDisabled (VOID)
 
BOOLEAN NTAPI KeAreAllApcsDisabled (VOID)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file apc.c.

Function Documentation

◆ _KeEnterCriticalRegion()

VOID NTAPI _KeEnterCriticalRegion ( VOID  )

Definition at line 573 of file apc.c.

574{
575 /* Use inlined function */
577}
#define KeEnterCriticalRegion()
Definition: ke_x.h:88

◆ _KeLeaveCriticalRegion()

VOID NTAPI _KeLeaveCriticalRegion ( VOID  )

Definition at line 599 of file apc.c.

600{
601 /* Use inlined version */
603}
#define KeLeaveCriticalRegion()
Definition: ke_x.h:119

◆ KeAreAllApcsDisabled()

BOOLEAN NTAPI KeAreAllApcsDisabled ( VOID  )

Definition at line 985 of file apc.c.

986{
987 /* Return the Special APC State */
988 return ((KeGetCurrentThread()->SpecialApcDisable) ||
990}
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define KeGetCurrentThread
Definition: hal.h:55

Referenced by _IRQL_requires_(), _Requires_lock_held_(), IopSynchronousCall(), IopUnQueueIrpFromThread(), MiCheckForUserStackOverflow(), MiDispatchFault(), MiLockProcessWorkingSetUnsafe(), MiMakePdeExistAndMakeValid(), MiMakeSystemAddressValid(), MiUnlockProcessWorkingSetUnsafe(), MmArmAccessFault(), and ObfDereferenceObject().

◆ KeAreApcsDisabled()

BOOLEAN NTAPI KeAreApcsDisabled ( VOID  )

Definition at line 958 of file apc.c.

959{
960 /* Return the Kernel APC State */
961 return KeGetCurrentThread()->CombinedApcDisable ? TRUE : FALSE;
962}

Referenced by START_TEST(), TestFastMutex(), TestResourceUndocumentedShortcuts(), TestSeAssignSecurity(), VerifyCriticalRegionEntry(), and VerifyCriticalRegionExit().

◆ KeFlushQueueApc()

PLIST_ENTRY NTAPI KeFlushQueueApc ( IN PKTHREAD  Thread,
IN KPROCESSOR_MODE  PreviousMode 
)

Definition at line 793 of file apc.c.

795{
796 PKAPC Apc;
797 PLIST_ENTRY FirstEntry, CurrentEntry;
798 KLOCK_QUEUE_HANDLE ApcLock;
800
801 /* Check if this was user mode */
802 if (PreviousMode == UserMode)
803 {
804 /* Get the APC lock */
806
807 /* Select user list and check if it's empty */
808 if (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))
809 {
810 /* Don't return anything */
811 FirstEntry = NULL;
812 goto FlushDone;
813 }
814 }
815 else
816 {
817 /* Select kernel list and check if it's empty */
818 if (IsListEmpty( &Thread->ApcState.ApcListHead[KernelMode]))
819 {
820 /* Don't return anything */
821 return NULL;
822 }
823
824 /* Otherwise, acquire the APC lock */
826 }
827
828 /* Get the first entry and check if the list is empty now */
829 FirstEntry = Thread->ApcState.ApcListHead[PreviousMode].Flink;
830 if (FirstEntry == &Thread->ApcState.ApcListHead[PreviousMode])
831 {
832 /* It is, clear the returned entry */
833 FirstEntry = NULL;
834 }
835 else
836 {
837 /* It's not, remove the first entry */
838 RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]);
839
840 /* Loop all the entries */
841 CurrentEntry = FirstEntry;
842 do
843 {
844 /* Get the APC and make it un-inserted */
845 Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
846 Apc->Inserted = FALSE;
847
848 /* Get the next entry */
849 CurrentEntry = CurrentEntry->Flink;
850 } while (CurrentEntry != FirstEntry);
851
852 /* Re-initialize the list */
853 InitializeListHead(&Thread->ApcState.ApcListHead[PreviousMode]);
854 }
855
856 /* Release the lock */
857FlushDone:
858 KiReleaseApcLock(&ApcLock);
859
860 /* Return the first entry */
861 return FirstEntry;
862}
#define NULL
Definition: types.h:112
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
FORCEINLINE VOID KiAcquireApcLockRaiseToSynch(IN PKTHREAD Thread, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:607
FORCEINLINE VOID KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:635
#define KernelMode
Definition: asm.h:34
#define UserMode
Definition: asm.h:35
#define ASSERT_IRQL_LESS_OR_EQUAL(x)
Definition: debug.h:251
Definition: ketypes.h:547
BOOLEAN Inserted
Definition: ketypes.h:567
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103

Referenced by PspExitThread().

◆ KeInitializeApc()

VOID NTAPI KeInitializeApc ( IN PKAPC  Apc,
IN PKTHREAD  Thread,
IN KAPC_ENVIRONMENT  TargetEnvironment,
IN PKKERNEL_ROUTINE  KernelRoutine,
IN PKRUNDOWN_ROUTINE RundownRoutine  OPTIONAL,
IN PKNORMAL_ROUTINE  NormalRoutine,
IN KPROCESSOR_MODE  Mode,
IN PVOID  Context 
)

Definition at line 651 of file apc.c.

659{
660 /* Sanity check */
661 ASSERT(TargetEnvironment <= InsertApcEnvironment);
662
663 /* Set up the basic APC Structure Data */
664 Apc->Type = ApcObject;
665 Apc->Size = sizeof(KAPC);
666
667 /* Set the Environment */
668 if (TargetEnvironment == CurrentApcEnvironment)
669 {
670 /* Use the current one for the thread */
671 Apc->ApcStateIndex = Thread->ApcStateIndex;
672 }
673 else
674 {
675 /* Sanity check */
676 ASSERT((TargetEnvironment <= Thread->ApcStateIndex) ||
677 (TargetEnvironment == InsertApcEnvironment));
678
679 /* Use the one that was given */
680 Apc->ApcStateIndex = TargetEnvironment;
681 }
682
683 /* Set the Thread and Routines */
684 Apc->Thread = Thread;
685 Apc->KernelRoutine = KernelRoutine;
686 Apc->RundownRoutine = RundownRoutine;
687 Apc->NormalRoutine = NormalRoutine;
688
689 /* Check if this is a special APC */
690 if (NormalRoutine)
691 {
692 /* It's a normal one. Set the context and mode */
693 Apc->ApcMode = Mode;
694 Apc->NormalContext = Context;
695 }
696 else
697 {
698 /* It's a special APC, which can only be kernel mode */
699 Apc->ApcMode = KernelMode;
700 Apc->NormalContext = NULL;
701 }
702
703 /* The APC is not inserted */
704 Apc->Inserted = FALSE;
705}
_In_ ULONG Mode
Definition: hubbusif.h:303
#define ASSERT(a)
Definition: mode.c:44
@ ApcObject
Definition: ketypes.h:424
@ CurrentApcEnvironment
Definition: ketypes.h:769
@ InsertApcEnvironment
Definition: ketypes.h:770
struct _KAPC KAPC

Referenced by ExSwapinWorkerThreads(), IofCompleteRequest(), IopCompleteRequest(), IoRaiseHardError(), KeInitThread(), NtQueueApcThreadEx(), NtSetTimer(), PsGetContextThread(), PspExitNormalApc(), PspTerminateThreadByPointer(), and PsSetContextThread().

◆ KeInsertQueueApc()

BOOLEAN NTAPI KeInsertQueueApc ( IN PKAPC  Apc,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2,
IN KPRIORITY  PriorityBoost 
)

Definition at line 735 of file apc.c.

739{
740 PKTHREAD Thread = Apc->Thread;
741 KLOCK_QUEUE_HANDLE ApcLock;
743 ASSERT_APC(Apc);
745
746 /* Get the APC lock */
748
749 /* Make sure we can Queue APCs and that this one isn't already inserted */
750 if (!(Thread->ApcQueueable) || (Apc->Inserted))
751 {
752 /* Fail */
753 State = FALSE;
754 }
755 else
756 {
757 /* Set the System Arguments and set it as inserted */
758 Apc->SystemArgument1 = SystemArgument1;
759 Apc->SystemArgument2 = SystemArgument2;
760 Apc->Inserted = TRUE;
761
762 /* Call the Internal Function */
764 }
765
766 /* Release the APC lock and return success */
768 KiExitDispatcher(ApcLock.OldIrql);
769 return State;
770}
unsigned char BOOLEAN
FORCEINLINE VOID KiReleaseApcLockFromSynchLevel(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:643
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
VOID FASTCALL KiInsertQueueApc(IN PKAPC Apc, IN KPRIORITY PriorityBoost)
Definition: apc.c:85
_In_ WDFREQUEST _In_ NTSTATUS _In_ CCHAR PriorityBoost
Definition: wdfrequest.h:1016
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
#define ASSERT_APC(Object)
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689

Referenced by _Function_class_(), ExSwapinWorkerThreads(), IofCompleteRequest(), IopCompleteRequest(), IoRaiseHardError(), NtQueueApcThreadEx(), PsGetContextThread(), PspExitNormalApc(), PspTerminateThreadByPointer(), and PsSetContextThread().

◆ KeRemoveQueueApc()

BOOLEAN NTAPI KeRemoveQueueApc ( IN PKAPC  Apc)

Definition at line 886 of file apc.c.

887{
888 PKTHREAD Thread = Apc->Thread;
890 BOOLEAN Inserted;
891 KLOCK_QUEUE_HANDLE ApcLock;
892 ASSERT_APC(Apc);
894
895 /* Get the APC lock (this raises IRQL to SYNCH_LEVEL) */
897
898 /* Check if it's inserted */
899 Inserted = Apc->Inserted;
900 if (Inserted)
901 {
902 /* Set it as non-inserted and get the APC state */
903 Apc->Inserted = FALSE;
904 ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex];
905
906 /* Acquire the dispatcher lock and remove it from the list */
908 if (RemoveEntryList(&Apc->ApcListEntry))
909 {
910 /* Set the correct state based on the APC Mode */
911 if (Apc->ApcMode == KernelMode)
912 {
913 /* No more pending kernel APCs */
914 ApcState->KernelApcPending = FALSE;
915 }
916 else
917 {
918 /* No more pending user APCs */
919 ApcState->UserApcPending = FALSE;
920 }
921 }
922
923 /* Release dispatcher lock */
925 }
926
927 /* Release the lock and return */
928 KiReleaseApcLock(&ApcLock);
929 return Inserted;
930}
FORCEINLINE VOID KiReleaseDispatcherLockFromSynchLevel(VOID)
Definition: ke_x.h:174
FORCEINLINE VOID KiAcquireDispatcherLockAtSynchLevel(VOID)
Definition: ke_x.h:165
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
* PKAPC_STATE
Definition: ketypes.h:1409
unsigned char UCHAR
Definition: xmlstorage.h:181

◆ KiCheckForKernelApcDelivery()

VOID NTAPI KiCheckForKernelApcDelivery ( VOID  )

Definition at line 36 of file apc.c.

37{
39
40 /* We should only deliver at passive */
42 {
43 /* Raise to APC and Deliver APCs, then lower back to Passive */
47 }
48 else
49 {
50 /*
51 * If we're not at passive level it means someone raised IRQL
52 * to APC level before the critical or guarded section was entered
53 * (e.g) by a fast mutex). This implies that the APCs shouldn't
54 * be delivered now, but after the IRQL is lowered to passive
55 * level again.
56 */
57 KeGetCurrentThread()->ApcState.KernelApcPending = TRUE;
59 }
60}
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

◆ KiDeliverApc()

VOID NTAPI KiDeliverApc ( IN KPROCESSOR_MODE  DeliveryMode,
IN PKEXCEPTION_FRAME  ExceptionFrame,
IN PKTRAP_FRAME  TrapFrame 
)

Definition at line 302 of file apc.c.

305{
307 PKPROCESS Process = Thread->ApcState.Process;
308 PKTRAP_FRAME OldTrapFrame;
309 PLIST_ENTRY ApcListEntry;
310 PKAPC Apc;
311 KLOCK_QUEUE_HANDLE ApcLock;
312 PKKERNEL_ROUTINE KernelRoutine;
313 PVOID NormalContext;
314 PKNORMAL_ROUTINE NormalRoutine;
318
319 /* Save the old trap frame and set current one */
320 OldTrapFrame = Thread->TrapFrame;
321 Thread->TrapFrame = TrapFrame;
322
323 /* Clear Kernel APC Pending */
324 Thread->ApcState.KernelApcPending = FALSE;
325
326 /* Check if Special APCs are disabled */
327 if (Thread->SpecialApcDisable) goto Quickie;
328
329 /* Do the Kernel APCs first */
330 while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
331 {
332 /* Lock the APC Queue */
334
335 /* Check if the list became empty now */
336 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
337 {
338 /* It is, release the lock and break out */
339 KiReleaseApcLock(&ApcLock);
340 break;
341 }
342
343 /* Kernel APC is not pending anymore */
344 Thread->ApcState.KernelApcPending = FALSE;
345
346 /* Get the next Entry */
347 ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
348 Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
349
350 /* Save Parameters so that it's safe to free the Object in the Kernel Routine*/
351 NormalRoutine = Apc->NormalRoutine;
352 KernelRoutine = Apc->KernelRoutine;
353 NormalContext = Apc->NormalContext;
356
357 /* Special APC */
358 if (!NormalRoutine)
359 {
360 /* Remove the APC from the list */
361 RemoveEntryList(ApcListEntry);
362 Apc->Inserted = FALSE;
363
364 /* Release the APC lock */
365 KiReleaseApcLock(&ApcLock);
366
367 /* Call the Special APC */
368 KernelRoutine(Apc,
369 &NormalRoutine,
370 &NormalContext,
373
374 /* Make sure it returned correctly */
375 if (KeGetCurrentIrql() != ApcLock.OldIrql)
376 {
377 KeBugCheckEx(IRQL_UNEXPECTED_VALUE,
378 (KeGetCurrentIrql() << 16) |
379 (ApcLock.OldIrql << 8),
380 (ULONG_PTR)KernelRoutine,
381 (ULONG_PTR)Apc,
382 (ULONG_PTR)NormalRoutine);
383 }
384 }
385 else
386 {
387 /* Normal Kernel APC, make sure it's safe to deliver */
388 if ((Thread->ApcState.KernelApcInProgress) ||
389 (Thread->KernelApcDisable))
390 {
391 /* Release lock and return */
392 KiReleaseApcLock(&ApcLock);
393 goto Quickie;
394 }
395
396 /* Dequeue the APC */
397 RemoveEntryList(ApcListEntry);
398 Apc->Inserted = FALSE;
399
400 /* Go back to APC_LEVEL */
401 KiReleaseApcLock(&ApcLock);
402
403 /* Call the Kernel APC */
404 KernelRoutine(Apc,
405 &NormalRoutine,
406 &NormalContext,
409
410 /* Make sure it returned correctly */
411 if (KeGetCurrentIrql() != ApcLock.OldIrql)
412 {
413 KeBugCheckEx(IRQL_UNEXPECTED_VALUE,
414 (KeGetCurrentIrql() << 16) |
415 (ApcLock.OldIrql << 8),
416 (ULONG_PTR)KernelRoutine,
417 (ULONG_PTR)Apc,
418 (ULONG_PTR)NormalRoutine);
419 }
420
421 /* Check if there still is a Normal Routine */
422 if (NormalRoutine)
423 {
424 /* At Passive Level, an APC can be prempted by a Special APC */
425 Thread->ApcState.KernelApcInProgress = TRUE;
427
428 /* Call and Raise IRQL back to APC_LEVEL */
429 NormalRoutine(NormalContext, SystemArgument1, SystemArgument2);
430 KeRaiseIrql(APC_LEVEL, &ApcLock.OldIrql);
431 }
432
433 /* Set Kernel APC in progress to false and loop again */
434 Thread->ApcState.KernelApcInProgress = FALSE;
435 }
436 }
437
438 /* Now we do the User APCs */
439 if ((DeliveryMode == UserMode) &&
440 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
441 (Thread->ApcState.UserApcPending))
442 {
443 /* Lock the APC Queue */
445
446 /* It's not pending anymore */
447 Thread->ApcState.UserApcPending = FALSE;
448
449 /* Check if the list became empty now */
450 if (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))
451 {
452 /* It is, release the lock and break out */
453 KiReleaseApcLock(&ApcLock);
454 goto Quickie;
455 }
456
457 /* Get the actual APC object */
458 ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
459 Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
460
461 /* Save Parameters so that it's safe to free the Object in the Kernel Routine*/
462 NormalRoutine = Apc->NormalRoutine;
463 KernelRoutine = Apc->KernelRoutine;
464 NormalContext = Apc->NormalContext;
467
468 /* Remove the APC from Queue, and release the lock */
469 RemoveEntryList(ApcListEntry);
470 Apc->Inserted = FALSE;
471 KiReleaseApcLock(&ApcLock);
472
473 /* Call the kernel routine */
474 KernelRoutine(Apc,
475 &NormalRoutine,
476 &NormalContext,
479
480 /* Check if there's no normal routine */
481 if (!NormalRoutine)
482 {
483 /* Check if more User APCs are Pending */
485 }
486 else
487 {
488 /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
489 KiInitializeUserApc(ExceptionFrame,
490 TrapFrame,
491 NormalRoutine,
492 NormalContext,
495 }
496 }
497
498Quickie:
499 /* Make sure we're still in the same process */
500 if (Process != Thread->ApcState.Process)
501 {
502 /* Erm, we got attached or something! BAD! */
503 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
505 (ULONG_PTR)Thread->ApcState.Process,
506 Thread->ApcStateIndex,
507 KeGetCurrentPrcb()->DpcRoutineActive);
508 }
509
510 /* Restore the trap frame */
511 Thread->TrapFrame = OldTrapFrame;
512}
#define ASSERT_IRQL_EQUAL(x)
Definition: debug.h:43
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
FORCEINLINE VOID KiAcquireApcLockRaiseToDpc(IN PKTHREAD Thread, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:626
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1161
VOID(NTAPI * PKKERNEL_ROUTINE)(IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine OPTIONAL, IN OUT PVOID *NormalContext OPTIONAL, IN OUT PVOID *SystemArgument1 OPTIONAL, IN OUT PVOID *SystemArgument2 OPTIONAL)
Definition: ketypes.h:754
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:744
BOOLEAN NTAPI KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
Definition: thrdobj.c:722
VOID NTAPI KiInitializeUserApc(IN PKEXCEPTION_FRAME Reserved, IN PKTRAP_FRAME TrapFrame, IN PKNORMAL_ROUTINE NormalRoutine, IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: usercall.c:266
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
PVOID NormalContext
Definition: ketypes.h:562
PVOID SystemArgument1
Definition: ketypes.h:563
PVOID SystemArgument2
Definition: ketypes.h:564
uint32_t ULONG_PTR
Definition: typedefs.h:65

Referenced by _HalpApcInterruptHandler(), HalpApcInterruptHandler(), HalpLowerIrql(), KiApcInterrupt(), KiCheckForApcDelivery(), KiCheckForKernelApcDelivery(), KiExitDispatcher(), KiExitV86Trap(), and KiSwapThread().

◆ KiInsertQueueApc()

VOID FASTCALL KiInsertQueueApc ( IN PKAPC  Apc,
IN KPRIORITY  PriorityBoost 
)

Definition at line 85 of file apc.c.

87{
88 PKTHREAD Thread = Apc->Thread;
90 KPROCESSOR_MODE ApcMode;
91 PLIST_ENTRY ListHead, NextEntry;
92 PKAPC QueuedApc;
93 PKGATE Gate;
95 BOOLEAN RequestInterrupt = FALSE;
96
97 /*
98 * Check if the caller wanted this APC to use the thread's environment at
99 * insertion time.
100 */
101 if (Apc->ApcStateIndex == InsertApcEnvironment)
102 {
103 /* Copy it over */
104 Apc->ApcStateIndex = Thread->ApcStateIndex;
105 }
106
107 /* Get the APC State for this Index, and the mode too */
108 ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex];
109 ApcMode = Apc->ApcMode;
110
111 /* The APC must be "inserted" already */
112 ASSERT(Apc->Inserted == TRUE);
113
114 /* Three scenarios:
115 * 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List
116 * 2) User APC which is PsExitSpecialApc = Put it at the front of the List
117 * 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list
118 */
119 if (Apc->NormalRoutine)
120 {
121 /* Normal APC; is it the Thread Termination APC? */
122 if ((ApcMode != KernelMode) &&
123 (Apc->KernelRoutine == PsExitSpecialApc))
124 {
125 /* Set User APC pending to true */
126 Thread->ApcState.UserApcPending = TRUE;
127
128 /* Insert it at the top of the list */
129 InsertHeadList(&ApcState->ApcListHead[ApcMode],
130 &Apc->ApcListEntry);
131 }
132 else
133 {
134 /* Regular user or kernel Normal APC */
135 InsertTailList(&ApcState->ApcListHead[ApcMode],
136 &Apc->ApcListEntry);
137 }
138 }
139 else
140 {
141 /* Special APC, find the last one in the list */
142 ListHead = &ApcState->ApcListHead[ApcMode];
143 NextEntry = ListHead->Blink;
144 while (NextEntry != ListHead)
145 {
146 /* Get the APC */
147 QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
148
149 /* Is this a No-Normal APC? If so, break */
150 if (!QueuedApc->NormalRoutine) break;
151
152 /* Move to the previous APC in the Queue */
153 NextEntry = NextEntry->Blink;
154 }
155
156 /* Insert us here */
157 InsertHeadList(NextEntry, &Apc->ApcListEntry);
158 }
159
160 /* Now check if the Apc State Indexes match */
161 if (Thread->ApcStateIndex == Apc->ApcStateIndex)
162 {
163 /* Check that the thread matches */
164 if (Thread == KeGetCurrentThread())
165 {
166 /* Sanity check */
167 ASSERT(Thread->State == Running);
168
169 /* Check if this is kernel mode */
170 if (ApcMode == KernelMode)
171 {
172 /* All valid, a Kernel APC is pending now */
173 Thread->ApcState.KernelApcPending = TRUE;
174
175 /* Check if Special APCs are disabled */
176 if (!Thread->SpecialApcDisable)
177 {
178 /* They're not, so request the interrupt */
180 }
181 }
182 }
183 else
184 {
185 /* Acquire the dispatcher lock */
187
188 /* Check if this is a kernel-mode APC */
189 if (ApcMode == KernelMode)
190 {
191 /* Kernel-mode APC, set us pending */
192 Thread->ApcState.KernelApcPending = TRUE;
193
194 /* Are we currently running? */
195 if (Thread->State == Running)
196 {
197 /* The thread is running, so remember to send a request */
198 RequestInterrupt = TRUE;
199 }
200 else if ((Thread->State == Waiting) &&
201 (Thread->WaitIrql == PASSIVE_LEVEL) &&
202 !(Thread->SpecialApcDisable) &&
203 (!(Apc->NormalRoutine) ||
204 (!(Thread->KernelApcDisable) &&
205 !(Thread->ApcState.KernelApcInProgress))))
206 {
207 /* We'll unwait with this status */
209
210 /* Wake up the thread */
212 }
213 else if (Thread->State == GateWait)
214 {
215 /* Lock the thread */
217
218 /* Essentially do the same check as above */
219 if ((Thread->State == GateWait) &&
220 (Thread->WaitIrql == PASSIVE_LEVEL) &&
221 !(Thread->SpecialApcDisable) &&
222 (!(Apc->NormalRoutine) ||
223 (!(Thread->KernelApcDisable) &&
224 !(Thread->ApcState.KernelApcInProgress))))
225 {
226 /* We were in a gate wait. Handle this. */
227 DPRINT1("A thread was in a gate wait\n");
228
229 /* Get the gate */
230 Gate = Thread->GateObject;
231
232 /* Lock the gate */
234
235 /* Remove it from the waiters list */
236 RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry);
237
238 /* Unlock the gate */
240
241 /* Increase the queue counter if needed */
242 if (Thread->Queue) Thread->Queue->CurrentCount++;
243
244 /* Put into deferred ready list with this status */
245 Thread->WaitStatus = STATUS_KERNEL_APC;
247 }
248
249 /* Release the thread lock */
251 }
252 }
253 else if ((Thread->State == Waiting) &&
254 (Thread->WaitMode == UserMode) &&
255 ((Thread->Alertable) ||
256 (Thread->ApcState.UserApcPending)))
257 {
258 /* Set user-mode APC pending */
259 Thread->ApcState.UserApcPending = TRUE;
261
262 /* Wake up the thread */
264 }
265
266 /* Release dispatcher lock */
268
269 /* Check if an interrupt was requested */
270 KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor);
271 }
272 }
273}
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
Status
Definition: gdiplustypes.h:25
FORCEINLINE VOID KiRequestApcInterrupt(IN BOOLEAN NeedApc, IN UCHAR Processor)
Definition: ke_x.h:276
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:240
FORCEINLINE VOID KiReleaseDispatcherObject(IN DISPATCHER_HEADER *Object)
Definition: ke_x.h:142
FORCEINLINE VOID KiInsertDeferredReadyList(IN PKTHREAD Thread)
Definition: ke_x.h:185
FORCEINLINE VOID KiAcquireDispatcherObject(IN DISPATCHER_HEADER *Object)
Definition: ke_x.h:132
FORCEINLINE VOID KiReleaseThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:250
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:149
@ Running
Definition: ketypes.h:390
@ GateWait
Definition: ketypes.h:397
@ Waiting
Definition: ketypes.h:393
VOID FASTCALL KiUnwaitThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus, IN KPRIORITY Increment)
Definition: wait.c:89
#define STATUS_USER_APC
Definition: ntstatus.h:78
#define STATUS_KERNEL_APC
Definition: ntstatus.h:79
VOID NTAPI PsExitSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE *NormalRoutine, PVOID *NormalContext, PVOID *SystemArgument1, PVOID *SystemArgument2)
DISPATCHER_HEADER Header
Definition: ketypes.h:823
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7

Referenced by KeFreezeAllThreads(), KeInsertQueueApc(), and KeSuspendThread().

◆ KiMoveApcState()

VOID NTAPI KiMoveApcState ( PKAPC_STATE  OldState,
PKAPC_STATE  NewState 
)

Definition at line 538 of file apc.c.

540{
541 /* Restore backup of Original Environment */
542 RtlCopyMemory(NewState, OldState, KAPC_STATE_ACTUAL_LENGTH);
543
544 /* Repair Lists */
545 RepairList(OldState->ApcListHead, NewState->ApcListHead, KernelMode);
546 RepairList(OldState->ApcListHead, NewState->ApcListHead, UserMode);
547}
FORCEINLINE VOID RepairList(IN PLIST_ENTRY Original, IN PLIST_ENTRY Copy, IN KPROCESSOR_MODE Mode)
Definition: apc.c:516
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define KAPC_STATE_ACTUAL_LENGTH
Definition: ketypes.h:1411

Referenced by KeDetachProcess(), KeUnstackDetachProcess(), and KiAttachProcess().

◆ RepairList()

FORCEINLINE VOID RepairList ( IN PLIST_ENTRY  Original,
IN PLIST_ENTRY  Copy,
IN KPROCESSOR_MODE  Mode 
)

Definition at line 516 of file apc.c.

519{
520 /* Check if the list for this mode is empty */
521 if (IsListEmpty(&Original[Mode]))
522 {
523 /* It is, all we need to do is initialize it */
525 }
526 else
527 {
528 /* Copy the lists */
529 Copy[Mode].Flink = Original[Mode].Flink;
530 Copy[Mode].Blink = Original[Mode].Blink;
531 Original[Mode].Flink->Blink = &Copy[Mode];
532 Original[Mode].Blink->Flink = &Copy[Mode];
533 }
534}
VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
Definition: mmixer.c:126

Referenced by KiMoveApcState().