ReactOS  r74431
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

#define NDEBUG

Definition at line 12 of file apc.c.

Function Documentation

VOID NTAPI _KeEnterCriticalRegion ( VOID  )

Definition at line 573 of file apc.c.

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

Definition at line 599 of file apc.c.

600 {
601  /* Use inlined version */
603 }
#define KeLeaveCriticalRegion()
Definition: ke_x.h:114
BOOLEAN NTAPI KeAreAllApcsDisabled ( VOID  )

Definition at line 985 of file apc.c.

Referenced by MiCheckForUserStackOverflow(), MiDispatchFault(), MiLockProcessWorkingSetUnsafe(), MiMakePdeExistAndMakeValid(), MiMakeSystemAddressValid(), MiUnlockProcessWorkingSetUnsafe(), MmArmAccessFault(), MmGetPageTableForProcess(), and ObfDereferenceObject().

986 {
987  /* Return the Special APC State */
988  return ((KeGetCurrentThread()->SpecialApcDisable) ||
989  (KeGetCurrentIrql() >= APC_LEVEL)) ? TRUE : FALSE;
990 }
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define TRUE
Definition: numbers.c:17
#define FALSE
Definition: numbers.c:16
#define KeGetCurrentThread
Definition: hal.h:44
#define APC_LEVEL
Definition: env_spec_w32.h:695
BOOLEAN NTAPI KeAreApcsDisabled ( VOID  )

Definition at line 958 of file apc.c.

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

959 {
960  /* Return the Kernel APC State */
961  return KeGetCurrentThread()->CombinedApcDisable ? TRUE : FALSE;
962 }
#define TRUE
Definition: numbers.c:17
#define FALSE
Definition: numbers.c:16
#define KeGetCurrentThread
Definition: hal.h:44
PLIST_ENTRY NTAPI KeFlushQueueApc ( IN PKTHREAD  Thread,
IN KPROCESSOR_MODE  PreviousMode 
)

Definition at line 793 of file apc.c.

Referenced by PspExitThread().

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 */
805  KiAcquireApcLock(Thread, &ApcLock);
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 */
825  KiAcquireApcLock(Thread, &ApcLock);
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 */
857 FlushDone:
858  KiReleaseApcLock(&ApcLock);
859 
860  /* Return the first entry */
861  return FirstEntry;
862 }
#define ASSERT_IRQL_LESS_OR_EQUAL(x)
Definition: debug.h:250
FORCEINLINE VOID KiAcquireApcLock(IN PKTHREAD Thread, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:600
FORCEINLINE VOID KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:627
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
smooth NULL
Definition: ftsmooth.c:464
struct _LIST_ENTRY * Flink
Definition: typedefs.h:120
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
Definition: ketypes.h:520
Definition: typedefs.h:118
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define FALSE
Definition: numbers.c:16
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
BOOLEAN Inserted
Definition: ketypes.h:540
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.

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

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 }
struct _KAPC KAPC
_In_ ULONG Mode
Definition: hubbusif.h:303
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
smooth NULL
Definition: ftsmooth.c:464
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
#define FALSE
Definition: numbers.c:16
struct tagContext Context
Definition: acpixf.h:1013
BOOLEAN NTAPI KeInsertQueueApc ( IN PKAPC  Apc,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2,
IN KPRIORITY  PriorityBoost 
)

Definition at line 735 of file apc.c.

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

739 {
740  PKTHREAD Thread = Apc->Thread;
741  KLOCK_QUEUE_HANDLE ApcLock;
742  BOOLEAN State = TRUE;
743  ASSERT_APC(Apc);
745 
746  /* Get the APC lock */
747  KiAcquireApcLock(Thread, &ApcLock);
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 }
#define ASSERT_IRQL_LESS_OR_EQUAL(x)
Definition: debug.h:250
#define ASSERT_APC(Object)
#define TRUE
Definition: numbers.c:17
FORCEINLINE VOID KiAcquireApcLock(IN PKTHREAD Thread, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:600
VOID FASTCALL KiInsertQueueApc(IN PKAPC Apc, IN KPRIORITY PriorityBoost)
Definition: apc.c:85
_In_ CCHAR PriorityBoost
Definition: iofuncs.h:763
FORCEINLINE VOID KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:635
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:660
unsigned char BOOLEAN
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:660
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
enum State_ State
Definition: pofuncs.h:54
#define FALSE
Definition: numbers.c:16
ULONG ApcQueueable
Definition: ketypes.h:1084
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 */
896  KiAcquireApcLock(Thread, &ApcLock);
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 }
#define ASSERT_IRQL_LESS_OR_EQUAL(x)
Definition: debug.h:250
#define ASSERT_APC(Object)
FORCEINLINE VOID KiAcquireApcLock(IN PKTHREAD Thread, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:600
FORCEINLINE VOID KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:627
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
unsigned char BOOLEAN
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
unsigned char UCHAR
Definition: xmlstorage.h:181
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1415
FORCEINLINE VOID KiReleaseDispatcherLockFromDpcLevel(VOID)
Definition: ke_x.h:168
#define FALSE
Definition: numbers.c:16
PKAPC_STATE ApcStatePointer[2]
Definition: ketypes.h:1241
* PKAPC_STATE
Definition: ketypes.h:1258
FORCEINLINE VOID KiAcquireDispatcherLockAtDpcLevel(VOID)
Definition: ke_x.h:160
VOID NTAPI KiCheckForKernelApcDelivery ( VOID  )

Definition at line 36 of file apc.c.

37 {
38  KIRQL OldIrql;
39 
40  /* We should only deliver at passive */
42  {
43  /* Raise to APC and Deliver APCs, then lower back to Passive */
44  KeRaiseIrql(APC_LEVEL, &OldIrql);
45  KiDeliverApc(KernelMode, 0, 0);
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 KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define TRUE
Definition: numbers.c:17
UCHAR KIRQL
Definition: env_spec_w32.h:591
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
#define KeGetCurrentThread
Definition: hal.h:44
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
#define APC_LEVEL
Definition: env_spec_w32.h:695
VOID NTAPI KiDeliverApc ( IN KPROCESSOR_MODE  DeliveryMode,
IN PKEXCEPTION_FRAME  ExceptionFrame,
IN PKTRAP_FRAME  TrapFrame 
)

Definition at line 302 of file apc.c.

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

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 */
333  KiAcquireApcLockAtApcLevel(Thread, &ApcLock);
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;
354  SystemArgument1 = Apc->SystemArgument1;
355  SystemArgument2 = Apc->SystemArgument2;
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,
371  &SystemArgument1,
372  &SystemArgument2);
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,
407  &SystemArgument1,
408  &SystemArgument2);
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 */
444  KiAcquireApcLockAtApcLevel(Thread, &ApcLock);
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;
465  SystemArgument1 = Apc->SystemArgument1;
466  SystemArgument2 = Apc->SystemArgument2;
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,
477  &SystemArgument1,
478  &SystemArgument2);
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,
493  SystemArgument1,
494  SystemArgument2);
495  }
496  }
497 
498 Quickie:
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,
504  (ULONG_PTR)Process,
505  (ULONG_PTR)Thread->ApcState.Process,
506  Thread->ApcStateIndex,
507  KeGetCurrentPrcb()->DpcRoutineActive);
508  }
509 
510  /* Restore the trap frame */
511  Thread->TrapFrame = OldTrapFrame;
512 }
DWORD *typedef PVOID
Definition: winlogon.h:52
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
SHORT SpecialApcDisable
Definition: ketypes.h:1052
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1054
#define TRUE
Definition: numbers.c:17
PKTRAP_FRAME TrapFrame
Definition: ketypes.h:1181
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: stubs.c:203
FORCEINLINE VOID KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:627
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
uint32_t ULONG_PTR
Definition: typedefs.h:64
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
SHORT KernelApcDisable
Definition: ketypes.h:1051
#define ASSERT_IRQL_EQUAL(x)
Definition: debug.h:56
KAPC_STATE ApcState
Definition: ketypes.h:969
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:660
PVOID SystemArgument1
Definition: ketypes.h:536
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:632
PVOID NormalContext
Definition: ketypes.h:535
Definition: ketypes.h:520
Definition: typedefs.h:118
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:660
BOOLEAN NTAPI KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
Definition: thrdobj.c:731
FORCEINLINE VOID KiAcquireApcLockAtApcLevel(IN PKTHREAD Thread, IN PKLOCK_QUEUE_HANDLE Handle)
Definition: ke_x.h:618
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
#define FALSE
Definition: numbers.c:16
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
BOOLEAN Inserted
Definition: ketypes.h:540
UCHAR ApcStateIndex
Definition: ketypes.h:1198
#define KeGetCurrentThread
Definition: hal.h:44
#define APC_LEVEL
Definition: env_spec_w32.h:695
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:90
PVOID SystemArgument2
Definition: ketypes.h:537
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:642
VOID FASTCALL KiInsertQueueApc ( IN PKAPC  Apc,
IN KPRIORITY  PriorityBoost 
)

Definition at line 85 of file apc.c.

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

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 */
208  Status = STATUS_KERNEL_APC;
209 
210  /* Wake up the thread */
211  KiUnwaitThread(Thread, Status, PriorityBoost);
212  }
213  else if (Thread->State == GateWait)
214  {
215  /* Lock the thread */
216  KiAcquireThreadLock(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 */
250  KiReleaseThreadLock(Thread);
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;
260  Status = STATUS_USER_APC;
261 
262  /* Wake up the thread */
263  KiUnwaitThread(Thread, Status, PriorityBoost);
264  }
265 
266  /* Release dispatcher lock */
268 
269  /* Check if an interrupt was requested */
270  KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor);
271  }
272  }
273 }
FORCEINLINE VOID KiReleaseThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:244
VOID FASTCALL KiUnwaitThread(IN PKTHREAD Thread, IN LONG_PTR WaitStatus, IN KPRIORITY Increment)
Definition: wait.c:89
DISPATCHER_HEADER Header
Definition: ketypes.h:796
SHORT SpecialApcDisable
Definition: ketypes.h:1052
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
struct _LIST_ENTRY * Blink
Definition: typedefs.h:121
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
FORCEINLINE VOID KiInsertDeferredReadyList(IN PKTHREAD Thread)
Definition: ke_x.h:179
#define TRUE
Definition: numbers.c:17
#define InsertTailList(ListHead, Entry)
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
SHORT KernelApcDisable
Definition: ketypes.h:1051
KAPC_STATE ApcState
Definition: ketypes.h:969
_In_ CCHAR PriorityBoost
Definition: iofuncs.h:763
#define STATUS_KERNEL_APC
Definition: ntstatus.h:79
ULONG Alertable
Definition: ketypes.h:954
FORCEINLINE VOID KiAcquireThreadLock(IN PKTHREAD Thread)
Definition: ke_x.h:234
unsigned char BOOLEAN
FORCEINLINE VOID KiAcquireDispatcherObject(IN DISPATCHER_HEADER *Object)
Definition: ke_x.h:127
FORCEINLINE VOID KiRequestApcInterrupt(IN BOOLEAN NeedApc, IN UCHAR Processor)
Definition: ke_x.h:270
FORCEINLINE VOID KiReleaseDispatcherObject(IN DISPATCHER_HEADER *Object)
Definition: ke_x.h:137
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
PKQUEUE Queue
Definition: ketypes.h:1044
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
LIST_ENTRY WaitListEntry
Definition: ketypes.h:1041
unsigned char UCHAR
Definition: xmlstorage.h:181
Definition: ketypes.h:520
Definition: typedefs.h:118
volatile ULONG NextProcessor
Definition: ketypes.h:977
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
Status
Definition: gdiplustypes.h:24
LONG_PTR WaitStatus
Definition: ketypes.h:1002
#define STATUS_USER_APC
Definition: ntstatus.h:78
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
LONG NTSTATUS
Definition: DriverTester.h:11
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:144
volatile ULONG CurrentCount
Definition: ketypes.h:1267
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1415
#define DPRINT1
Definition: precomp.h:8
FORCEINLINE VOID KiReleaseDispatcherLockFromDpcLevel(VOID)
Definition: ke_x.h:168
#define FALSE
Definition: numbers.c:16
volatile UCHAR State
Definition: ketypes.h:997
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
UCHAR ApcStateIndex
Definition: ketypes.h:1198
KPROCESSOR_MODE WaitMode
Definition: ketypes.h:1000
VOID NTAPI PsExitSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE *NormalRoutine, PVOID *NormalContext, PVOID *SystemArgument1, PVOID *SystemArgument2)
#define KeGetCurrentThread
Definition: hal.h:44
PKAPC_STATE ApcStatePointer[2]
Definition: ketypes.h:1241
#define APC_LEVEL
Definition: env_spec_w32.h:695
* PKAPC_STATE
Definition: ketypes.h:1258
KIRQL WaitIrql
Definition: ketypes.h:999
VOID NTAPI KiMoveApcState ( PKAPC_STATE  OldState,
PKAPC_STATE  NewState 
)

Definition at line 538 of file apc.c.

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

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 }
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define KAPC_STATE_ACTUAL_LENGTH
Definition: ketypes.h:1260
FORCEINLINE VOID RepairList(IN PLIST_ENTRY Original, IN PLIST_ENTRY Copy, IN KPROCESSOR_MODE Mode)
Definition: apc.c:516
FORCEINLINE VOID RepairList ( IN PLIST_ENTRY  Original,
IN PLIST_ENTRY  Copy,
IN KPROCESSOR_MODE  Mode 
)

Definition at line 516 of file apc.c.

Referenced by KiMoveApcState().

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 */
524  InitializeListHead(&Copy[Mode]);
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 }
_In_ ULONG Mode
Definition: hubbusif.h:303
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
VOID Copy(PVOID Src, PVOID Dst, ULONG NumBytes)
Definition: mmixer.c:131
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944