Thread/Process Termination/Repeaing Rewrite + Fixes
[reactos.git] / reactos / ntoskrnl / ke / apc.c
index daefbad..b2f0626 100644 (file)
 #define NDEBUG
 #include <internal/debug.h>
 
-/* GLOBALS *******************************************************************/
-
-VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
-
 /* FUNCTIONS *****************************************************************/
 
 /*++
@@ -145,19 +141,15 @@ KeInitializeApc(IN PKAPC Apc,
 }
 
 /*++
- * KeInsertQueueApc 
- * @implemented NT4
+ * KiInsertQueueApc 
  *
- *     The KeInsertQueueApc routine queues a APC for execution when the right
+ *     The KiInsertQueueApc 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:
@@ -173,45 +165,16 @@ KeInitializeApc(IN PKAPC Apc,
  *--*/
 BOOLEAN
 STDCALL
-KeInsertQueueApc(PKAPC Apc,
-                 PVOID SystemArgument1,
-                 PVOID SystemArgument2,
+KiInsertQueueApc(PKAPC Apc,
                  KPRIORITY PriorityBoost)
-
 {
-    KIRQL OldIrql;
-    PKTHREAD Thread;
+    PKTHREAD Thread = Apc->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);
-
-    /* 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;
-
     /* Don't do anything if the APC is already inserted */
     if (Apc->Inserted) {
         
-        KeReleaseDispatcherDatabaseLock(OldIrql);
         return FALSE;
     }
     
@@ -247,7 +210,7 @@ KeInsertQueueApc(PKAPC Apc,
         
         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);
+                       &Apc->ApcListEntry);
     }
     
     /* Confirm Insertion */    
@@ -271,9 +234,9 @@ KeInsertQueueApc(PKAPC Apc,
             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)) {
+        } else if ((Thread->State == THREAD_STATE_BLOCKED) && (Thread->WaitIrql == PASSIVE_LEVEL) &&
+                   ((Apc->NormalRoutine == NULL) || 
+                   ((!Thread->KernelApcDisable) && (!Thread->ApcState.KernelApcInProgress)))) {
           
             DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n");
             KiAbortWaitThread(Thread, STATUS_KERNEL_APC, PriorityBoost);
@@ -287,10 +250,79 @@ KeInsertQueueApc(PKAPC Apc,
         Thread->ApcState.UserApcPending = TRUE;
         KiAbortWaitThread(Thread, STATUS_USER_APC, PriorityBoost);
     }
+    
+    return TRUE;
+}
+    
+/*++
+ * 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)
+
+{
+    KIRQL OldIrql;
+    PKTHREAD Thread;
+    BOOLEAN Inserted;
+   
+    ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
+    DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
+           "SystemArgument2 %x)\n",Apc,SystemArgument1,
+            SystemArgument2);
+
+    /* 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;
+
+    /* Call the Internal Function */
+    Inserted = KiInsertQueueApc(Apc, PriorityBoost);
 
     /* Return Sucess if we are here */
     KeReleaseDispatcherDatabaseLock(OldIrql);
-    return TRUE;
+    return Inserted;
 }
 
 /*++