Alex Ionescu <ionucu(a)videotron.ca>
- Remove ke/critical.c and move its functions into ke/apc.c
- Reformat ke/apc.c code which I had written messed up (due to MSVC)
- Add a bit more commenting.
Modified: trunk/reactos/ntoskrnl/Makefile
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
Modified: trunk/reactos/ntoskrnl/ke/apc.c
Deleted: trunk/reactos/ntoskrnl/ke/critical.c
_____
Modified: trunk/reactos/ntoskrnl/Makefile
--- trunk/reactos/ntoskrnl/Makefile 2005-03-12 22:16:02 UTC (rev
13984)
+++ trunk/reactos/ntoskrnl/Makefile 2005-03-12 22:31:22 UTC (rev
13985)
@@ -97,7 +97,6 @@
ke/bug.o \
ke/catch.o \
ke/clock.o \
- ke/critical.o \
ke/dpc.o \
ke/device.o \
ke/event.o \
_____
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
--- trunk/reactos/ntoskrnl/include/internal/ke.h 2005-03-12
22:16:02 UTC (rev 13984)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h 2005-03-12
22:31:22 UTC (rev 13985)
@@ -179,7 +179,7 @@
PVOID Reserved,
PKTRAP_FRAME TrapFrame);
-VOID KiInitializeUserApc(IN PVOID Reserved,
+VOID STDCALL KiInitializeUserApc(IN PVOID Reserved,
IN PKTRAP_FRAME TrapFrame,
IN PKNORMAL_ROUTINE NormalRoutine,
IN PVOID NormalContext,
_____
Modified: trunk/reactos/ntoskrnl/ke/apc.c
--- trunk/reactos/ntoskrnl/ke/apc.c 2005-03-12 22:16:02 UTC (rev
13984)
+++ trunk/reactos/ntoskrnl/ke/apc.c 2005-03-12 22:31:22 UTC (rev
13985)
@@ -1,5 +1,4 @@
-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/apc.c
@@ -19,581 +18,820 @@
VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
-#define TAG_KAPC TAG('K', 'A', 'P', 'C')
-
/* FUNCTIONS
*****************************************************************/
-/*
- * @implemented
- */
+/*++
+ * KeEnterCriticalRegion
+ * @implemented NT4
+ *
+ * The KeEnterCriticalRegion routine temporarily disables the
delivery of
+ * normal kernel APCs; special kernel-mode APCs are still
delivered.
+ *
+ * Params:
+ * None.
+ *
+ * Returns:
+ * None.
+ *
+ * Remarks:
+ * Highest-level drivers can call this routine while running in the
context
+ * of the thread that requested the current I/O operation. Any
caller of
+ * this routine should call KeLeaveCriticalRegion as quickly as
possible.
+ *
+ * Callers of KeEnterCriticalRegion must be running at IRQL <=
APC_LEVEL.
+ *
+ *--*/
+VOID
+STDCALL
+KeEnterCriticalRegion(VOID)
+{
+ /* Disable Kernel APCs */
+ PKTHREAD Thread = KeGetCurrentThread();
+ if (Thread) Thread->KernelApcDisable--;
+}
+
+/*++
+ * KeInitializeApc
+ * @implemented NT4
+ *
+ * The The KeInitializeApc routine initializes an APC object, and
registers
+ * the Kernel, Rundown and Normal routines for that object.
+ *
+ * Params:
+ * Apc - Pointer to a KAPC structure that represents the APC object
to
+ * initialize. The caller must allocate storage for the
structure
+ * from resident memory.
+ *
+ * Thread - Thread to which to deliver the APC.
+ *
+ * TargetEnvironment - APC Environment to be used.
+ *
+ * KernelRoutine - Points to the KernelRoutine to associate with
the APC.
+ * This routine is executed for all APCs.
+ *
+ * RundownRoutine - Points to the RundownRoutine to associate with
the APC.
+ * This routine is executed when the Thread exists
with
+ * the APC executing.
+ *
+ * NormalRoutine - Points to the NormalRoutine to associate with
the APC.
+ * This routine is executed at PASSIVE_LEVEL. If
this is
+ * not specifed, the APC becomes a Special APC and
the
+ * Mode and Context parameters are ignored.
+ *
+ * Mode - Specifies the processor mode at which to run the Normal
Routine.
+ *
+ * Context - Specifices the value to pass as Context parameter to
the
+ * registered routines.
+ *
+ * Returns:
+ * None.
+ *
+ * Remarks:
+ * The caller can queue an initialized APC with KeInsertQueueApc.
+ *
+ * Storage for the APC object must be resident, such as nonpaged
pool
+ * allocated by the caller.
+ *
+ * Callers of this routine must be running at IRQL = PASSIVE_LEVEL.
+ *
+ *--*/
VOID
STDCALL
-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)
-/*
- * FUNCTION: Initialize an APC object
- * ARGUMENTS:
- * Apc = Pointer to the APC object to initialized
- * Thread = Thread the APC is to be delivered to
- * TargetEnvironment = APC environment to use
- * KernelRoutine = Routine to be called for a kernel-mode APC
- * RundownRoutine = Routine to be called if the thread has exited
with
- * the APC being executed
- * NormalRoutine = Routine to be called for a user-mode APC
- * Mode = APC mode
- * Context = Parameter to be passed to the APC routine
- */
+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)
{
- DPRINT ("KeInitializeApc(Apc %x, Thread %x, Environment %d, "
- "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x,
Mode %d, "
- "Context
%x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine,
- NormalRoutine,Mode,Context);
+ DPRINT("KeInitializeApc(Apc %x, Thread %x, Environment %d, "
+ "KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode
%d, "
+ "Context
%x)\n",Apc,Thread,TargetEnvironment,KernelRoutine,RundownRoutine,
+ NormalRoutine,Mode,Context);
- /* Set up the basic APC Structure Data */
- RtlZeroMemory(Apc, sizeof(KAPC));
- Apc->Type = ApcObject;
- Apc->Size = sizeof(KAPC);
-
- /* Set the Environment */
- if (TargetEnvironment == CurrentApcEnvironment) {
- Apc->ApcStateIndex = Thread->ApcStateIndex;
- } else {
- Apc->ApcStateIndex = TargetEnvironment;
- }
-
- /* Set the Thread and Routines */
- Apc->Thread = Thread;
- Apc->KernelRoutine = KernelRoutine;
- Apc->RundownRoutine = RundownRoutine;
- Apc->NormalRoutine = NormalRoutine;
+ /* Set up the basic APC Structure Data */
+ RtlZeroMemory(Apc, sizeof(KAPC));
+ Apc->Type = ApcObject;
+ Apc->Size = sizeof(KAPC);
+
+ /* Set the Environment */
+ if (TargetEnvironment == CurrentApcEnvironment) {
+
+ Apc->ApcStateIndex = Thread->ApcStateIndex;
+
+ } else {
+
+ Apc->ApcStateIndex = TargetEnvironment;
+ }
+
+ /* Set the Thread and Routines */
+ Apc->Thread = Thread;
+ Apc->KernelRoutine = KernelRoutine;
+ Apc->RundownRoutine = RundownRoutine;
+ Apc->NormalRoutine = NormalRoutine;
- /* Check if this is a Special APC, in which case we use
KernelMode and no Context */
- if (ARGUMENT_PRESENT(NormalRoutine)) {
- Apc->ApcMode = Mode;
- Apc->NormalContext = Context;
- } else {
- Apc->ApcMode = KernelMode;
- }
+ /* Check if this is a Special APC, in which case we use KernelMode
and no Context */
+ if (ARGUMENT_PRESENT(NormalRoutine)) {
+
+ Apc->ApcMode = Mode;
+ Apc->NormalContext = Context;
+
+ } else {
+
+ Apc->ApcMode = KernelMode;
+ }
}
-/*
- * @implemented
- */
+/*++
+ * KeInsertQueueApc
+ * @implemented NT4
+ *
+ * The KeInsertQueueApc routine queues a APC for execution when the
right
+ * scheduler environment exists.
+ *
+ * Params:
+ * Apc - Pointer to an initialized control object of type DPC for
which the
+ * caller provides the storage.
+ *
+ * SystemArgument[1,2] - Pointer to a set of two parameters that
contain
+ * untyped data.
+ *
+ * PriorityBoost - Priority Boost to apply to the Thread.
+ *
+ * Returns:
+ * If the APC is already inserted or APC queueing is disabled,
FALSE.
+ * Otherwise, TRUE.
+ *
+ * Remarks:
+ * The APC will execute at APC_LEVEL for the KernelRoutine
registered, and
+ * at PASSIVE_LEVEL for the NormalRoutine registered.
+ *
+ * Callers of this routine must be running at IRQL = PASSIVE_LEVEL.
+ *
+ *--*/
BOOLEAN
STDCALL
-KeInsertQueueApc (PKAPC Apc,
- PVOID SystemArgument1,
- PVOID SystemArgument2,
- KPRIORITY PriorityBoost)
-/*
- * FUNCTION: Queues an APC for execution
- * ARGUMENTS:
- * Apc = APC to be queued
- * SystemArgument[1-2] = Arguments we ignore and simply pass
on.
- * PriorityBoost = Priority Boost to give to the Thread
- */
+KeInsertQueueApc(PKAPC Apc,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2,
+ KPRIORITY PriorityBoost)
+
{
- KIRQL OldIrql;
- PKTHREAD Thread;
- PLIST_ENTRY ApcListEntry;
- PKAPC QueuedApc;
+ KIRQL OldIrql;
+ PKTHREAD Thread;
+ PLIST_ENTRY ApcListEntry;
+ PKAPC QueuedApc;
- ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
- DPRINT ("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
- "SystemArgument2 %x)\n",Apc,SystemArgument1,
- SystemArgument2);
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
+ DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
+ "SystemArgument2 %x)\n",Apc,SystemArgument1,
+ SystemArgument2);
- OldIrql = KeAcquireDispatcherDatabaseLock();
-
- /* Get the Thread specified in the APC */
- Thread = Apc->Thread;
-
- /* Make sure the thread allows APC Queues.
+ /* Lock the Dispatcher Database */
+ OldIrql = KeAcquireDispatcherDatabaseLock();
+
+ /* Get the Thread specified in the APC */
+ Thread = Apc->Thread;
+
+ /* Make sure the thread allows APC Queues.
* The thread is not apc queueable, for instance, when it's (about
to be) terminated.
*/
- if (Thread->ApcQueueable == FALSE) {
- DPRINT("Thread doesn't allow APC Queues\n");
- KeReleaseDispatcherDatabaseLock(OldIrql);
- return FALSE;
- }
-
- /* Set the System Arguments */
- Apc->SystemArgument1 = SystemArgument1;
- Apc->SystemArgument2 = SystemArgument2;
+ if (Thread->ApcQueueable == FALSE) {
+ DPRINT("Thread doesn't allow APC Queues\n");
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+ return FALSE;
+ }
+
+ /* Set the System Arguments */
+ Apc->SystemArgument1 = SystemArgument1;
+ Apc->SystemArgument2 = SystemArgument2;
- /* Don't do anything if the APC is already inserted */
- if (Apc->Inserted) {
- KeReleaseDispatcherDatabaseLock(OldIrql);
- return FALSE;
- }
-
- /* Three scenarios:
- 1) Kernel APC with Normal Routine or User APC = Put it at the
end of the List
- 2) User APC which is PsExitSpecialApc = Put it at the front
of the List
- 3) Kernel APC without Normal Routine = Put it at the end of
the No-Normal Routine Kernel APC list
- */
- if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine ==
(PKKERNEL_ROUTINE)PsExitSpecialApc)) {
- DPRINT ("Inserting the Process Exit APC into the
Queue\n");
-
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
-
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcLis
tHead[(int)Apc->ApcMode],
- &Apc->ApcListEntry);
- } else if (Apc->NormalRoutine == NULL) {
- DPRINT ("Inserting Special APC %x into the Queue\n",
Apc);
- for (ApcListEntry =
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->
ApcMode].Flink;
- ApcListEntry !=
&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc-
ApcMode];
- ApcListEntry =
ApcListEntry->Flink) {
+ /* Don't do anything if the APC is already inserted */
+ if (Apc->Inserted) {
+
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+ return FALSE;
+ }
+
+ /* Three scenarios:
+ 1) Kernel APC with Normal Routine or User APC = Put it at the
end of the List
+ 2) User APC which is PsExitSpecialApc = Put it at the front of
the List
+ 3) Kernel APC without Normal Routine = Put it at the end of the
No-Normal Routine Kernel APC list
+ */
+ if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine ==
(PKKERNEL_ROUTINE)PsExitSpecialApc)) {
+
+ DPRINT ("Inserting the Process Exit APC into the Queue\n");
+
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
+
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcLis
tHead[(int)Apc->ApcMode],
+ &Apc->ApcListEntry);
+
+ } else if (Apc->NormalRoutine == NULL) {
+
+ DPRINT ("Inserting Special APC %x into the Queue\n", Apc);
+
+ for (ApcListEntry =
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->
ApcMode].Flink;
+ ApcListEntry !=
&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc-
ApcMode];
+ ApcListEntry =
ApcListEntry->Flink) {
- QueuedApc = CONTAINING_RECORD(ApcListEntry,
KAPC, ApcListEntry);
- if (Apc->NormalRoutine != NULL) break;
- }
-
- /* We found the first "Normal" APC, so write right
before it */
- ApcListEntry = ApcListEntry->Blink;
- InsertHeadList(ApcListEntry, &Apc->ApcListEntry);
- } else {
- DPRINT ("Inserting Normal APC %x into the %x Queue\n",
Apc, Apc->ApcMode);
-
InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcLis
tHead[(int)Apc->ApcMode],
- &Apc->ApcListEntry);
- }
-
- /* Confirm Insertion */
- Apc->Inserted = TRUE;
+ QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC,
ApcListEntry);
+ if (Apc->NormalRoutine != NULL) break;
+ }
+
+ /* We found the first "Normal" APC, so write right before it */
+ ApcListEntry = ApcListEntry->Blink;
+ InsertHeadList(ApcListEntry, &Apc->ApcListEntry);
+
+ } else {
+
+ DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc,
Apc->ApcMode);
+
InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcLis
tHead[(int)Apc->ApcMode],
+ &Apc->ApcListEntry);
+ }
+
+ /* Confirm Insertion */
+ Apc->Inserted = TRUE;
- /* Three possibilites here again:
- 1) Kernel APC, The thread is Running: Request an Interrupt
- 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and
APCs are enabled and not in progress: Unwait the Thread
- 3) User APC, Unwait the Thread if it is alertable
- */
- if (Apc->ApcMode == KernelMode) {
- Thread->ApcState.KernelApcPending = TRUE;
- if (Thread->State == THREAD_STATE_RUNNING) {
- /* FIXME: Use IPI */
- DPRINT ("Requesting APC Interrupt for Running
Thread \n");
- HalRequestSoftwareInterrupt(APC_LEVEL);
- } else if ((Thread->State == THREAD_STATE_BLOCKED) &&
+ /*
+ * Three possibilites here again:
+ * 1) Kernel APC, The thread is Running: Request an Interrupt
+ * 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs
are enabled and not in progress: Unwait the Thread
+ * 3) User APC, Unwait the Thread if it is alertable
+ */
+ if (Apc->ApcMode == KernelMode) {
+
+ /* Set Kernel APC pending */
+ Thread->ApcState.KernelApcPending = TRUE;
+
+ /* Check the Thread State */
+ if (Thread->State == THREAD_STATE_RUNNING) {
+
+ /* FIXME: Use IPI */
+ DPRINT ("Requesting APC Interrupt for Running Thread \n");
+ HalRequestSoftwareInterrupt(APC_LEVEL);
+
+ } else if ((Thread->State == THREAD_STATE_BLOCKED) &&
(Thread->WaitIrql < APC_LEVEL) &&
- (Apc->NormalRoutine == NULL))
- {
- DPRINT ("Waking up Thread for Kernel-Mode APC
Delivery \n");
- KiAbortWaitThread(Thread, STATUS_KERNEL_APC);
- }
+ (Apc->NormalRoutine == NULL)) {
+
+ DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n");
+ KiAbortWaitThread(Thread, STATUS_KERNEL_APC);
+ }
+
} else if ((Thread->State == THREAD_STATE_BLOCKED) &&
(Thread->WaitMode == UserMode) &&
- (Thread->Alertable))
- {
- DPRINT ("Waking up Thread for User-Mode APC Delivery
\n");
- Thread->ApcState.UserApcPending = TRUE;
- KiAbortWaitThread(Thread, STATUS_USER_APC);
- }
+ (Thread->Alertable)) {
+
+ DPRINT("Waking up Thread for User-Mode APC Delivery \n");
+ Thread->ApcState.UserApcPending = TRUE;
+ KiAbortWaitThread(Thread, STATUS_USER_APC);
+ }
- /* Return Sucess if we are here */
- KeReleaseDispatcherDatabaseLock(OldIrql);
- return TRUE;
+ /* Return Sucess if we are here */
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+ return TRUE;
}
-BOOLEAN STDCALL
-KeRemoveQueueApc (PKAPC Apc)
-/*
- * FUNCTION: Removes APC object from the apc queue
- * ARGUMENTS:
- * Apc = APC to remove
- * RETURNS: TRUE if the APC was in the queue
- * FALSE otherwise
- * NOTE: This function is not exported.
- */
+/*++
+ * KeLeaveCriticalRegion
+ * @implemented NT4
+ *
+ * The KeLeaveCriticalRegion routine reenables the delivery of
normal
+ * kernel-mode APCs that were disabled by a call to
KeEnterCriticalRegion.
+ *
+ * Params:
+ * None.
+ *
+ * Returns:
+ * None.
+ *
+ * Remarks:
+ * Highest-level drivers can call this routine while running in the
context
+ * of the thread that requested the current I/O operation.
+ *
+ * Callers of KeLeaveCriticalRegion must be running at IRQL <=
DISPATCH_LEVEL.
+ *
+ *--*/
+VOID
+STDCALL
+KeLeaveCriticalRegion (VOID)
{
- KIRQL OldIrql;
- PKTHREAD Thread = Apc->Thread;
+ PKTHREAD Thread = KeGetCurrentThread();
- ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
- DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
-
- OldIrql = KeAcquireDispatcherDatabaseLock();
- KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
-
- /* Remove it from the Queue if it's inserted */
- if (!Apc->Inserted == FALSE) {
- RemoveEntryList(&Apc->ApcListEntry);
- Apc->Inserted = FALSE;
-
- /* If the Queue is completely empty, then no more APCs
are pending */
- if
(IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListH
ead[(int)Apc->ApcMode])) {
- if (Apc->ApcMode == KernelMode) {
-
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending =
FALSE;
- } else {
-
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending =
FALSE;
- }
- }
- } else {
- KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
- KeReleaseDispatcherDatabaseLock(OldIrql);
- return(FALSE);
- }
-
- /* Restore IRQL and Return */
- KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
- KeReleaseDispatcherDatabaseLock(OldIrql);
- return(TRUE);
+ /* Check if Kernel APCs are now enabled */
+ if((Thread) && (++Thread->KernelApcDisable == 0)) {
+
+ /* Check if we need to request an APC Delivery */
+ if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) {
+
+ /* Set APC Pending */
+ Thread->ApcState.KernelApcPending = TRUE;
+ HalRequestSoftwareInterrupt(APC_LEVEL);
+ }
+ }
}
+/*++
+ * KeRemoveQueueApc
+ *
+ * The KeRemoveQueueApc routine removes a given APC object from the
system
+ * APC queue.
+ *
+ * Params:
+ * APC - Pointer to an initialized APC object that was queued by
calling
+ * KeInsertQueueApc.
+ *
+ * Returns:
+ * TRUE if the APC Object is in the APC Queue. If it isn't, no
operation is
+ * performed and FALSE is returned.
+ *
+ * Remarks:
+ * If the given APC Object is currently queued, it is removed from
the queue
+ * and any calls to the registered routines are cancelled.
+ *
+ * Callers of KeLeaveCriticalRegion can be running at any IRQL.
+ *
+ *--*/
+BOOLEAN
+STDCALL
+KeRemoveQueueApc(PKAPC Apc)
+{
+ KIRQL OldIrql;
+ PKTHREAD Thread = Apc->Thread;
-/*
- * @implemented
- */
+ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
+ DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
+
+ OldIrql = KeAcquireDispatcherDatabaseLock();
+ KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
+
+ /* Check if it's inserted */
+ if (Apc->Inserted) {
+
+ /* Remove it from the Queue*/
+ RemoveEntryList(&Apc->ApcListEntry);
+ Apc->Inserted = FALSE;
+
+ /* If the Queue is completely empty, then no more APCs are
pending */
+ if
(IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListH
ead[(int)Apc->ApcMode])) {
+
+ /* Set the correct State based on the Apc Mode */
+ if (Apc->ApcMode == KernelMode) {
+
+
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending =
FALSE;
+
+ } else {
+
+
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending =
FALSE;
+ }
+ }
+
+ } else {
+
+ /* It's not inserted, fail */
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+ return(FALSE);
+ }
+
+ /* Restore IRQL and Return */
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+ return(TRUE);
+}
+
+/*++
+ * KiDeliverApc
+ * @implemented @NT4
+ *
+ * The KiDeliverApc routine is called from IRQL switching code if
the
+ * thread is returning from an IRQL >= APC_LEVEL and Kernel-Mode
APCs are
+ * pending.
+ *
+ * Params:
+ * DeliveryMode - Specifies the current processor mode.
+ *
+ * Reserved - Pointer to the Exception Frame on non-i386 builds.
+ *
+ * TrapFrame - Pointer to the Trap Frame.
+ *
+ * Returns:
+ * None.
+ *
+ * Remarks:
+ * First, Special APCs are delivered, followed by Kernel-Mode APCs
and
+ * User-Mode APCs. Note that the TrapFrame is only valid if the
previous
+ * mode is User.
+ *
+ * Upon entry, this routine executes at APC_LEVEL.
+ *
+ *--*/
VOID
STDCALL
KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
PVOID Reserved,
PKTRAP_FRAME TrapFrame)
-/*
- * FUNCTION: Deliver an APC to the current thread.
- * NOTES: This is called from the IRQL switching code if the current
thread
- * is returning from an IRQL greater than or equal to APC_LEVEL to
- * PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any
- * pending APCs will be delivered after a thread gets a new quantum and
- * after it wakes from a wait. Note that the TrapFrame is only valid if
- * the previous mode is User.
- */
{
- PKTHREAD Thread = KeGetCurrentThread();
- PLIST_ENTRY ApcListEntry;
- PKAPC Apc;
- KIRQL OldIrql;
- PKKERNEL_ROUTINE KernelRoutine;
- PVOID NormalContext;
- PKNORMAL_ROUTINE NormalRoutine;
- PVOID SystemArgument1;
- PVOID SystemArgument2;
+ PKTHREAD Thread = KeGetCurrentThread();
+ PLIST_ENTRY ApcListEntry;
+ PKAPC Apc;
+ KIRQL OldIrql;
+ PKKERNEL_ROUTINE KernelRoutine;
+ PVOID NormalContext;
+ PKNORMAL_ROUTINE NormalRoutine;
+ PVOID SystemArgument1;
+ PVOID SystemArgument2;
- ASSERT_IRQL_EQUAL(APC_LEVEL);
+ ASSERT_IRQL_EQUAL(APC_LEVEL);
- /* Lock the APC Queue and Raise IRQL to Synch */
- KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
+ /* Lock the APC Queue and Raise IRQL to Synch */
+ KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
- /* Clear APC Pending */
- Thread->ApcState.KernelApcPending = FALSE;
-
- /* Do the Kernel APCs first */
- while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
{
-
- /* Get the next Entry */
- ApcListEntry =
Thread->ApcState.ApcListHead[KernelMode].Flink;
- Apc = CONTAINING_RECORD(ApcListEntry, KAPC,
ApcListEntry);
-
- /* Save Parameters so that it's safe to free the Object
in Kernel Routine*/
- NormalRoutine = Apc->NormalRoutine;
- KernelRoutine = Apc->KernelRoutine;
- NormalContext = Apc->NormalContext;
- SystemArgument1 = Apc->SystemArgument1;
- SystemArgument2 = Apc->SystemArgument2;
+ /* Clear APC Pending */
+ Thread->ApcState.KernelApcPending = FALSE;
+
+ /* Do the Kernel APCs first */
+ while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) {
+
+ /* Get the next Entry */
+ ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
+ Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
+
+ /* Save Parameters so that it's safe to free the Object in
Kernel Routine*/
+ NormalRoutine = Apc->NormalRoutine;
+ KernelRoutine = Apc->KernelRoutine;
+ NormalContext = Apc->NormalContext;
+ SystemArgument1 = Apc->SystemArgument1;
+ SystemArgument2 = Apc->SystemArgument2;
- /* Special APC */
- if (NormalRoutine == NULL) {
- /* Remove the APC from the list */
- Apc->Inserted = FALSE;
- RemoveEntryList(ApcListEntry);
-
- /* Go back to APC_LEVEL */
- KeReleaseSpinLock(&Thread->ApcQueueLock,
OldIrql);
-
- /* Call the Special APC */
- DPRINT("Delivering a Special APC: %x\n", Apc);
- KernelRoutine(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
+ /* Special APC */
+ if (NormalRoutine == NULL) {
+
+ /* Remove the APC from the list */
+ Apc->Inserted = FALSE;
+ RemoveEntryList(ApcListEntry);
+
+ /* Go back to APC_LEVEL */
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+
+ /* Call the Special APC */
+ DPRINT("Delivering a Special APC: %x\n", Apc);
+ KernelRoutine(Apc,
+ &NormalRoutine,
+ &NormalContext,
+ &SystemArgument1,
+ &SystemArgument2);
- /* Raise IRQL and Lock again */
- KeAcquireSpinLock(&Thread->ApcQueueLock,
&OldIrql);
- } else {
- /* Normal Kernel APC */
- if (Thread->ApcState.KernelApcInProgress ||
Thread->KernelApcDisable) {
+ /* Raise IRQL and Lock again */
+ KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
- /*
- * DeliveryMode must be KernelMode in this case, since one
may not
- * return to umode while being inside a critical section or
while
- * a regular kmode apc is running (the latter should be
impossible btw).
- * -Gunnar
- */
- ASSERT(DeliveryMode == KernelMode);
+ } else {
+
+ /* Normal Kernel APC */
+ if (Thread->ApcState.KernelApcInProgress ||
Thread->KernelApcDisable) {
+
+ /*
+ * DeliveryMode must be KernelMode in this case, since
one may not
+ * return to umode while being inside a critical
section or while
+ * a regular kmode apc is running (the latter should be
impossible btw).
+ * -Gunnar
+ */
+ ASSERT(DeliveryMode == KernelMode);
- KeReleaseSpinLock(&Thread->ApcQueueLock,
OldIrql);
- return;
- }
-
- /* Dequeue the APC */
- RemoveEntryList(ApcListEntry);
- Apc->Inserted = FALSE;
-
- /* Go back to APC_LEVEL */
- KeReleaseSpinLock(&Thread->ApcQueueLock,
OldIrql);
-
- /* Call the Kernel APC */
- DPRINT("Delivering a Normal APC: %x\n", Apc);
- KernelRoutine(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
-
- /* If There still is a Normal Routine, then we
need to call this at PASSIVE_LEVEL */
- if (NormalRoutine != NULL) {
- /* At Passive Level, this APC can be
prempted by a Special APC */
- Thread->ApcState.KernelApcInProgress =
TRUE;
- KeLowerIrql(PASSIVE_LEVEL);
-
- /* Call and Raise IRQ back to APC_LEVEL
*/
- DPRINT("Calling the Normal Routine for a
Normal APC: %x\n", Apc);
- NormalRoutine(&NormalContext,
&SystemArgument1, &SystemArgument2);
- KeRaiseIrql(APC_LEVEL, &OldIrql);
- }
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+ return;
+ }
+
+ /* Dequeue the APC */
+ RemoveEntryList(ApcListEntry);
+ Apc->Inserted = FALSE;
+
+ /* Go back to APC_LEVEL */
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+
+ /* Call the Kernel APC */
+ DPRINT("Delivering a Normal APC: %x\n", Apc);
+ KernelRoutine(Apc,
+ &NormalRoutine,
+ &NormalContext,
+ &SystemArgument1,
+ &SystemArgument2);
+
+ /* If There still is a Normal Routine, then we need to call
this at PASSIVE_LEVEL */
+ if (NormalRoutine != NULL) {
+
+ /* At Passive Level, this APC can be prempted by a
Special APC */
+ Thread->ApcState.KernelApcInProgress = TRUE;
+ KeLowerIrql(PASSIVE_LEVEL);
+
+ /* Call and Raise IRQ back to APC_LEVEL */
+ DPRINT("Calling the Normal Routine for a Normal APC:
%x\n", Apc);
+ NormalRoutine(&NormalContext, &SystemArgument1,
&SystemArgument2);
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
+ }
- /* Raise IRQL and Lock again */
- KeAcquireSpinLock(&Thread->ApcQueueLock,
&OldIrql);
- Thread->ApcState.KernelApcInProgress = FALSE;
- }
- }
-
- /* Now we do the User APCs */
- if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
- (DeliveryMode == UserMode) &&
- (Thread->ApcState.UserApcPending == TRUE)) {
-
- /* It's not pending anymore */
- Thread->ApcState.UserApcPending = FALSE;
+ /* Raise IRQL and Lock again */
+ KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
+ Thread->ApcState.KernelApcInProgress = FALSE;
+ }
+ }
+
+ /* Now we do the User APCs */
+ if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
+ (DeliveryMode == UserMode) && (Thread->ApcState.UserApcPending
== TRUE)) {
+
+ /* It's not pending anymore */
+ Thread->ApcState.UserApcPending = FALSE;
- /* Get the APC Object */
- ApcListEntry =
Thread->ApcState.ApcListHead[UserMode].Flink;
- Apc = CONTAINING_RECORD(ApcListEntry, KAPC,
ApcListEntry);
-
- /* Save Parameters so that it's safe to free the Object
in Kernel Routine*/
- NormalRoutine = Apc->NormalRoutine;
- KernelRoutine = Apc->KernelRoutine;
- NormalContext = Apc->NormalContext;
- SystemArgument1 = Apc->SystemArgument1;
- SystemArgument2 = Apc->SystemArgument2;
-
- /* Remove the APC from Queue, restore IRQL and call the
APC */
- RemoveEntryList(ApcListEntry);
- Apc->Inserted = FALSE;
+ /* Get the APC Object */
+ ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
+ Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
+
+ /* Save Parameters so that it's safe to free the Object in
Kernel Routine*/
+ NormalRoutine = Apc->NormalRoutine;
+ KernelRoutine = Apc->KernelRoutine;
+ NormalContext = Apc->NormalContext;
+ SystemArgument1 = Apc->SystemArgument1;
+ SystemArgument2 = Apc->SystemArgument2;
+
+ /* Remove the APC from Queue, restore IRQL and call the APC */
+ RemoveEntryList(ApcListEntry);
+ Apc->Inserted = FALSE;
- KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
- DPRINT("Calling the Kernel Routine for for a User APC:
%x\n", Apc);
- KernelRoutine(Apc,
- &NormalRoutine,
- &NormalContext,
- &SystemArgument1,
- &SystemArgument2);
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+ DPRINT("Calling the Kernel Routine for for a User APC: %x\n",
Apc);
+ KernelRoutine(Apc,
+ &NormalRoutine,
+ &NormalContext,
+ &SystemArgument1,
+ &SystemArgument2);
- if (NormalRoutine == NULL) {
- /* Check if more User APCs are Pending */
- KeTestAlertThread(UserMode);
- } else {
- /* Set up the Trap Frame and prepare for
Execution in NTDLL.DLL */
- DPRINT("Delivering a User APC: %x\n", Apc);
- KiInitializeUserApc(Reserved,
- TrapFrame,
- NormalRoutine,
- NormalContext,
- SystemArgument1,
- SystemArgument2);
- }
- } else {
- /* Go back to APC_LEVEL */
- KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
- }
+ if (NormalRoutine == NULL) {
+
+ /* Check if more User APCs are Pending */
+ KeTestAlertThread(UserMode);
+
+ } else {
+
+ /* Set up the Trap Frame and prepare for Execution in
NTDLL.DLL */
+ DPRINT("Delivering a User APC: %x\n", Apc);
+ KiInitializeUserApc(Reserved,
+ TrapFrame,
+ NormalRoutine,
+ NormalContext,
+ SystemArgument1,
+ SystemArgument2);
+ }
+
+ } else {
+
+ /* Go back to APC_LEVEL */
+ KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+ }
}
VOID
STDCALL
KiFreeApcRoutine(PKAPC Apc,
- PKNORMAL_ROUTINE* NormalRoutine,
- PVOID* NormalContext,
- PVOID* SystemArgument1,
- PVOID* SystemArgument2)
+ PKNORMAL_ROUTINE* NormalRoutine,
+ PVOID* NormalContext,
+ PVOID* SystemArgument1,
+ PVOID* SystemArgument2)
{
- /* Free the APC and do nothing else */
- ExFreePool(Apc);
+ /* Free the APC and do nothing else */
+ ExFreePool(Apc);
}
-VOID
+/*++
+ * KiInitializeUserApc
+ *
+ * Prepares the Context for a User-Mode APC called through
NTDLL.DLL
+ *
+ * Params:
+ * Reserved - Pointer to the Exception Frame on non-i386 builds.
+ *
+ * TrapFrame - Pointer to the Trap Frame.
+ *
+ * NormalRoutine - Pointer to the NormalRoutine to call.
+ *
+ * NormalContext - Pointer to the context to send to the Normal
Routine.
+ *
+ * SystemArgument[1-2] - Pointer to a set of two parameters that
contain
+ * untyped data.
+ *
+ * Returns:
+ * None.
+ *
+ * Remarks:
+ * None.
+ *
+ *--*/
[truncated at 1000 lines; 411 more skipped]