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]->ApcListHead[(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]->ApcListHead[(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]->ApcListHead[(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]->ApcListHead[(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]->ApcListHead[(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]->ApcListHead[(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]