Alex Ionescu ionucu@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]