- Fix several flaws in APC logic.
- Properly support Special APC Disabling.
- Allow Guarded Mutex and Guarded Regions to function properly.
- Optimize some code and add some additional checks.
- Fix several bugs in KeFreezeAllThreads
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
Modified: trunk/reactos/ntoskrnl/ke/apc.c
Modified: trunk/reactos/ntoskrnl/ke/kthread.c

Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
--- trunk/reactos/ntoskrnl/include/internal/ke.h	2005-09-27 01:48:49 UTC (rev 18116)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h	2005-09-27 01:57:27 UTC (rev 18117)
@@ -55,7 +55,8 @@
     PKTHREAD _Thread = KeGetCurrentThread(); \
     if((_Thread) && (++_Thread->KernelApcDisable == 0)) \
     { \
-        if (!IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode])) \
+        if (!IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode]) && \
+            (_Thread->SpecialApcDisable == 0)) \
         { \
             KiKernelApcDeliveryCheck(); \
         } \

Modified: trunk/reactos/ntoskrnl/ke/apc.c
--- trunk/reactos/ntoskrnl/ke/apc.c	2005-09-27 01:48:49 UTC (rev 18116)
+++ trunk/reactos/ntoskrnl/ke/apc.c	2005-09-27 01:57:27 UTC (rev 18117)
@@ -123,7 +123,8 @@
     if((Thread) && (++Thread->KernelApcDisable == 0))
     {
         /* Check if we need to request an APC Delivery */
-        if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
+        if ((!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) &&
+            (Thread->SpecialApcDisable == 0))
         {
             /* Check for the right environment */
             KiKernelApcDeliveryCheck();
@@ -225,6 +226,32 @@
     }
 }
 
+static
+__inline
+VOID
+KiRequestApcInterrupt(IN PKTHREAD Thread)
+{
+#ifdef CONFIG_SMP
+    PKPRCB Prcb, CurrentPrcb;
+    LONG i;
+
+    CurrentPrcb = KeGetCurrentPrcb();
+    for (i = 0; i < KeNumberProcessors; i++)
+    {
+        Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
+        if (Prcb->CurrentThread == Thread)
+        {
+            ASSERT (CurrentPrcb != Prcb);
+            KiIpiSendRequest(Prcb->SetMember, IPI_APC);
+            break;
+        }
+    }
+    ASSERT (i < KeNumberProcessors);
+#else
+    HalRequestSoftwareInterrupt(APC_LEVEL);
+#endif
+}
+
 /*++
  * KiInsertQueueApc
  *
@@ -238,8 +265,7 @@
  *     PriorityBoost - Priority Boost to apply to the Thread.
  *
  * Returns:
- *     If the APC is already inserted or APC queueing is disabled, FALSE.
- *     Otherwise, TRUE.
+ *     None
  *
  * Remarks:
  *     The APC will execute at APC_LEVEL for the KernelRoutine registered, and
@@ -248,122 +274,175 @@
  *     Callers of this routine must have locked the dipatcher database.
  *
  *--*/
-BOOLEAN
-STDCALL
+VOID
+FASTCALL
 KiInsertQueueApc(PKAPC Apc,
                  KPRIORITY PriorityBoost)
 {
     PKTHREAD Thread = Apc->Thread;
+    PKAPC_STATE ApcState;
+    KPROCESSOR_MODE ApcMode;
+    PLIST_ENTRY ListHead, NextEntry;
+    PKAPC QueuedApc;
+    NTSTATUS Status;
 
+    /* Acquire the lock (only needed on MP) */
     KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
 
-    /* Don't do anything if the APC is already inserted */
-    if (Apc->Inserted) {
-    
-        KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
-        return FALSE;
+    /* Little undocumented feature: Special Apc State Index */
+    if (Apc->ApcStateIndex == 3)
+    {
+        /* This tells us to use the thread's */
+        Apc->ApcStateIndex = Thread->ApcStateIndex;
     }
 
+    /* Get the APC State for this Index, and the mode too */
+    ApcState = Thread->ApcStatePointer[(int)Apc->ApcStateIndex];
+    ApcMode = Apc->ApcMode;
+
     /* 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)) {
+     * 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->NormalRoutine)
+    {
+        /* Normal APC; is it the Thread Termination APC? */
+        if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc))
+        {
+            /* Set User APC pending to true */
+            Thread->ApcState.UserApcPending = TRUE;
 
-        DPRINT("Inserting the Thread Exit APC for '%.16s' into the Queue\n", ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
-        Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
-        InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
-                       &Apc->ApcListEntry);
+            /* Insert it at the top of the list */
+            InsertHeadList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry);
 
-    } else if (Apc->NormalRoutine == NULL) {
+            /* Display debug message */
+            DPRINT1("Inserted the Thread Exit APC for '%.16s' into the Queue\n",
+                   ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
+        }
+        else
+        {
+            /* Regular user or kernel Normal APC */
+            InsertTailList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry);
 
-        DPRINT("Inserting Special APC %x for '%.16s' into the Queue\n", Apc, ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
-
-        /* insert special apc before normal apcs (if any) but after the last special apc (fifo) */
-        InsertAscendingListFIFO(
-           &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], 
-           Apc,
-           KAPC, 
-           ApcListEntry, 
-           NormalRoutine /* sort field */
-           );
-
-    } else {
-
-        DPRINT("Inserting Normal APC %x for '%.16s' into the %x Queue\n", Apc, ((PETHREAD)Thread)->ThreadsProcess->ImageFileName, Apc->ApcMode);
-        InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
-                       &Apc->ApcListEntry);
+            /* Display debug message */
+            DPRINT("Inserted Normal APC for '%.16s' into the Queue\n",
+                   ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
+        }
     }
+    else
+    {
+        /* Special APC, find the first Normal APC in the list */
+        ListHead = &ApcState->ApcListHead[ApcMode];
+        NextEntry = ListHead->Flink;
+        while(NextEntry != ListHead)
+        {
+            /* Get the APC */
+            QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
 
-    /* Confirm Insertion */
-    Apc->Inserted = TRUE;
+            /* Is this a Normal APC? If so, break */
+            if (QueuedApc->NormalRoutine) break;
 
-    KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
+            /* Move to the next APC in the Queue */
+            NextEntry = NextEntry->Flink;
+        }
 
-    /*
-     * 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) {
+        /* Move to the APC before this one (ie: the last Special APC) */
+        NextEntry = NextEntry->Blink;
 
-        /* Set Kernel APC pending */
-        Thread->ApcState.KernelApcPending = TRUE;
+        /* Insert us here */
+        InsertHeadList(NextEntry, &Apc->ApcListEntry);
+        DPRINT("Inserted Special APC for '%.16s' into the Queue\n",
+               ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
+    }
 
-        /* Check the Thread State */
-        if (Thread->State == Running) {
+    /* Now check if the Apc State Indexes match */
+    if (Thread->ApcStateIndex == Apc->ApcStateIndex)
+    {
+        /* Check that if the thread matches */
+        if (Thread == KeGetCurrentThread())
+        {
+            /* Check if this is kernel mode */
+            if (ApcMode == KernelMode)
+            {
+                /* All valid, a Kernel APC is pending now */
+                Thread->ApcState.KernelApcPending = TRUE;
 
-#ifdef CONFIG_SMP
-            PKPRCB Prcb, CurrentPrcb;
-            LONG i;
-#endif
-
-            DPRINT ("Requesting APC Interrupt for Running Thread \n");
-
-#ifdef CONFIG_SMP
-            CurrentPrcb = KeGetCurrentPrcb();
-            if (CurrentPrcb->CurrentThread == Thread)
+                /* Check if Special APCs are disabled */
+                if (Thread->SpecialApcDisable == 0)
+                {
+                    /* They're not, so request the interrupt */
+                    HalRequestSoftwareInterrupt(APC_LEVEL);
+                }
+            }
+        }
+        else
+        {
+            /* Check if this is a non-kernel mode APC */
+            if (ApcMode != KernelMode)
             {
-               HalRequestSoftwareInterrupt(APC_LEVEL);
+                /* Not a Kernel-Mode APC. Are we waiting in user-mode? */
+                if ((Thread->State == Waiting) && (Thread->WaitMode == UserMode))
+                {
+                    /* The thread is waiting. Are we alertable, or is an APC pending */
+                    if ((Thread->Alertable) || (Thread->ApcState.UserApcPending))
+                    {
+                        /* Set user-mode APC pending */
+                        Thread->ApcState.UserApcPending = TRUE;
+                        Status = STATUS_USER_APC;
+                        goto Unwait;
+                    }
+                }
             }
             else
             {
-               for (i = 0; i < KeNumberProcessors; i++)
-               {
-                  Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
-                  if (Prcb->CurrentThread == Thread)
-                  {
-                     ASSERT (CurrentPrcb != Prcb);
-                     KiIpiSendRequest(Prcb->SetMember, IPI_APC);
-                     break;
-                  }
-               }
-               ASSERT (i < KeNumberProcessors);
-            }
-#else
-            HalRequestSoftwareInterrupt(APC_LEVEL);
-#endif
+                /* Kernel-mode APC, set us pending */
+                Thread->ApcState.KernelApcPending = TRUE;
 
-        } else if ((Thread->State == Waiting) && (Thread->WaitIrql == PASSIVE_LEVEL) &&
-                   ((Apc->NormalRoutine == NULL) ||
-                   ((!Thread->KernelApcDisable) && (!Thread->ApcState.KernelApcInProgress)))) {
+                /* Are we currently running? */
+                if (Thread->State == Running)
+                {
+                    /* The thread is running, so send an APC request */
+                    KiRequestApcInterrupt(Thread);
+                }
+                else
+                {
+                    /*
+                     * If the thread is Waiting at PASSIVE_LEVEL AND
+                     *      Special APCs are not disabled AND
+                     *          He is a Normal APC AND
+                     *              Kernel APCs are not disabled AND
+                     *                  Kernel APC is not pending OR
+                     *          He is a Special APC THEN
+                     *              Unwait thread with STATUS_KERNEL_APC
+                     */
+                    if ((Thread->State == Waiting) &&
+                        (Thread->WaitIrql == PASSIVE_LEVEL) &&
+                        (!Thread->SpecialApcDisable) && 
+                        ((!Apc->NormalRoutine) ||
+                         ((!Thread->KernelApcDisable) &&
+                         (!Thread->ApcState.KernelApcInProgress))))
+                    {
+                        /* We'll unwait with this status */
+                        Status = STATUS_KERNEL_APC;
 
-            DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n");
-            KiAbortWaitThread(Thread, STATUS_KERNEL_APC, PriorityBoost);
+                        /* Wake up the thread */
+Unwait:
+                        DPRINT("Waking up Thread for %lx Delivery \n", Status);
+                        KiAbortWaitThread(Thread, Status, PriorityBoost);
+                    }
+                    else
+                    {
+                        /* FIXME: Handle deferred ready sometime far far in the future */
+                    }
+                }
+            }
         }
-
-   } else if ((Thread->State == Waiting) &&
-              (Thread->WaitMode != KernelMode) &&
-              (Thread->Alertable)) {
-
-        DPRINT("Waking up Thread for User-Mode APC Delivery \n");
-        Thread->ApcState.UserApcPending = TRUE;
-        KiAbortWaitThread(Thread, STATUS_USER_APC, PriorityBoost);
     }
 
-    return TRUE;
+    /* Return to caller */
+    KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
+    return;
 }
 
 /*++
@@ -399,11 +478,9 @@
                  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, "
@@ -416,25 +493,25 @@
     /* 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");
+    /* Make sure we can Queue APCs and that this one isn't already inserted */
+    if ((Thread->ApcQueueable == FALSE) && (Apc->Inserted == TRUE))
+    {
+        DPRINT("Can't queue the APC\n");
         KeReleaseDispatcherDatabaseLock(OldIrql);
         return FALSE;
     }
 
-    /* Set the System Arguments */
+    /* Set the System Arguments and set it as inserted */
     Apc->SystemArgument1 = SystemArgument1;
     Apc->SystemArgument2 = SystemArgument2;
+    Apc->Inserted = TRUE;
 
     /* Call the Internal Function */
-    Inserted = KiInsertQueueApc(Apc, PriorityBoost);
+    KiInsertQueueApc(Apc, PriorityBoost);
 
     /* Return Sucess if we are here */
     KeReleaseDispatcherDatabaseLock(OldIrql);
-    return Inserted;
+    return TRUE;
 }
 
 /*++
@@ -464,23 +541,25 @@
 {
     KIRQL OldIrql;
     PKAPC Apc;
-    PLIST_ENTRY FirstEntry = NULL;
+    PLIST_ENTRY FirstEntry, CurrentEntry;
 
     /* Lock the Dispatcher Database and APC Queue */
     OldIrql = KeAcquireDispatcherDatabaseLock();
     KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
 
-    /* mark all apcs as not-inserted */
-    LIST_FOR_EACH(Apc, &Thread->ApcState.ApcListHead[PreviousMode], KAPC, ApcListEntry) {
-       Apc->Inserted = FALSE;
-    }
-    
-    if (!IsListEmpty(&Thread->ApcState.ApcListHead[PreviousMode])) {
+    if (IsListEmpty(&Thread->ApcState.ApcListHead[PreviousMode])) {
+        FirstEntry = NULL;
+    } else {
         FirstEntry = Thread->ApcState.ApcListHead[PreviousMode].Flink;
-        /* unlink list head from the rest of the list */
         RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]);
+        CurrentEntry = FirstEntry;
+        do {
+            Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
+            Apc->Inserted = FALSE;
+            CurrentEntry = CurrentEntry->Flink;
+        } while (CurrentEntry != FirstEntry);
     }
-    
+
     /* Release the locks */
     KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
     KeReleaseDispatcherDatabaseLock(OldIrql);
@@ -516,46 +595,42 @@
 {
     KIRQL OldIrql;
     PKTHREAD Thread = Apc->Thread;
-
+    PKAPC_STATE ApcState;
+    BOOLEAN Inserted;
     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
     DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
 
+    /* Acquire locks */
     OldIrql = KeAcquireDispatcherDatabaseLock();
     KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
 
     /* Check if it's inserted */
-    if (Apc->Inserted) {
-
+    if ((Inserted = Apc->Inserted))
+    {
         /* Remove it from the Queue*/
+        Apc->Inserted = FALSE;
+        ApcState = Thread->ApcStatePointer[(int)Apc->ApcStateIndex];
         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 (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;
+            if (Apc->ApcMode == KernelMode)
+            {
+                ApcState->KernelApcPending = FALSE;
             }
+            else
+            {
+                ApcState->UserApcPending = FALSE;
+            }
         }
-
-    } else {
-
-        /* It's not inserted, fail */
-        KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
-        KeReleaseDispatcherDatabaseLock(OldIrql);
-        return(FALSE);
     }
 
     /* Restore IRQL and Return */
     KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
     KeReleaseDispatcherDatabaseLock(OldIrql);
-    return(TRUE);
+    return Inserted;
 }
 
 /*++
@@ -591,6 +666,8 @@
              PKTRAP_FRAME TrapFrame)
 {
     PKTHREAD Thread = KeGetCurrentThread();
+    PKPROCESS Process = KeGetCurrentProcess();
+    PKTRAP_FRAME OldTrapFrame;
     PLIST_ENTRY ApcListEntry;
     PKAPC Apc;
     KIRQL OldIrql;
@@ -599,17 +676,22 @@
     PKNORMAL_ROUTINE NormalRoutine;
     PVOID SystemArgument1;
     PVOID SystemArgument2;
-
     ASSERT_IRQL_EQUAL(APC_LEVEL);
 
-    /* Lock the APC Queue and Raise IRQL to Synch */
-    KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
+    /* Save the old trap frame */
+    OldTrapFrame = Thread->TrapFrame;
 
-    /* Clear APC Pending */
+    /* Clear Kernel APC Pending */
     Thread->ApcState.KernelApcPending = FALSE;
 
+    /* Check if Special APCs are disabled */
+    if (Thread->SpecialApcDisable != 0) goto Quickie;
+
     /* Do the Kernel APCs first */
-    while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) {
+    while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
+    {
+        /* Lock the APC Queue and Raise IRQL to Synch */
+        KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
 
         /* Get the next Entry */
         ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
@@ -623,8 +705,8 @@
         SystemArgument2 = Apc->SystemArgument2;
 
         /* Special APC */
-       if (NormalRoutine == NULL) {
-
+        if (!NormalRoutine)
+        {
             /* Remove the APC from the list */
             RemoveEntryList(ApcListEntry);
             Apc->Inserted = FALSE;
@@ -639,15 +721,13 @@
                           &NormalContext,
                           &SystemArgument1,
                           &SystemArgument2);
-
-            /* Raise IRQL and Lock again */
-            KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
-
-        } else {
-
-             /* Normal Kernel APC */
-            if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) {
-
+        }
+        else
+        {
+            /* Normal Kernel APC, make sur APCs aren't disabled or in progress*/
+            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
@@ -656,8 +736,9 @@
                  */
                 ASSERT(DeliveryMode == KernelMode);
 
+                /* Release lock and return */
                 KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
-                return;
+                goto Quickie;
             }
 
             /* Dequeue the APC */
@@ -676,8 +757,8 @@
                           &SystemArgument2);
 
             /* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */
-            if (NormalRoutine != NULL) {
-
+            if (NormalRoutine)
+            {
                 /* At Passive Level, this APC can be prempted by a Special APC */
                 Thread->ApcState.KernelApcInProgress = TRUE;
                 KeLowerIrql(PASSIVE_LEVEL);
@@ -688,21 +769,34 @@
                 KeRaiseIrql(APC_LEVEL, &OldIrql);
             }
 
-            /* Raise IRQL and Lock again */
-            KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
+            /* Set Kernel APC in progress to false and loop again */
             Thread->ApcState.KernelApcInProgress = FALSE;
         }
     }
 
     /* Now we do the User APCs */
-    if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
-        (DeliveryMode != KernelMode) && (Thread->ApcState.UserApcPending == TRUE)) {
+    if ((DeliveryMode == UserMode) &&
+        (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
+         (Thread->ApcState.UserApcPending == TRUE))
+    {
+        /* Lock the APC Queue and Raise IRQL to Synch */
+        KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
 
         /* It's not pending anymore */
         Thread->ApcState.UserApcPending = FALSE;
 
-        /* Get the APC Object */
+        /* Get the APC Entry */
         ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
+
+        /* Is it empty now? */
+        if (!ApcListEntry)
+        {
+            /* Release the lock and return */
+            KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
+            goto Quickie;
+        }
+
+        /* Get the actual APC object */
         Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
 
         /* Save Parameters so that it's safe to free the Object in Kernel Routine*/
@@ -724,13 +818,13 @@
                       &SystemArgument1,
                       &SystemArgument2);
 
-        if (NormalRoutine == NULL) {
-
+        if (!NormalRoutine)
+        {
             /* Check if more User APCs are Pending */
             KeTestAlertThread(UserMode);
-
-        } else {
-
+        }
+        else
+        {
             /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
             DPRINT("Delivering a User APC: %x\n", Apc);
             KiInitializeUserApc(Reserved,
@@ -740,12 +834,23 @@
                                 SystemArgument1,
                                 SystemArgument2);
         }
+    }
 
-    } else {
+Quickie:
+    /* Make sure we're still in the same process */
+    if (Process != Thread->ApcState.Process)
+    {
+        /* Erm, we got attached or something! BAD! */
+        KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
+                     (ULONG_PTR)Process,
+                     (ULONG_PTR)Thread->ApcState.Process,
+                     Thread->ApcStateIndex,
+                     KeGetCurrentPrcb()->DpcRoutineActive);
+    }
 
-        /* Go back to APC_LEVEL */
-        KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
-    }
+    /* Restore the trap frame */
+    Thread->TrapFrame = OldTrapFrame;
+    return;
 }
 
 VOID
@@ -865,7 +970,7 @@
 KeAreApcsDisabled(VOID)
 {
     /* Return the Kernel APC State */
-    return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE;
+    return KeGetCurrentThread()->CombinedApcDisable ? TRUE : FALSE;
 }
 
 /*++

Modified: trunk/reactos/ntoskrnl/ke/kthread.c
--- trunk/reactos/ntoskrnl/ke/kthread.c	2005-09-27 01:48:49 UTC (rev 18116)
+++ trunk/reactos/ntoskrnl/ke/kthread.c	2005-09-27 01:57:27 UTC (rev 18117)
@@ -527,8 +527,8 @@
     return PreviousCount;
 }
 
-BOOLEAN
-STDCALL
+VOID
+FASTCALL
 KiInsertQueueApc(PKAPC Apc,
                  KPRIORITY PriorityBoost);
 
@@ -547,20 +547,42 @@
     /* Acquire Lock */
     OldIrql = KeAcquireDispatcherDatabaseLock();
 
+    /* If someone is already trying to free us, try again */
+    while (CurrentThread->FreezeCount)
+    {
+        /* Release and re-acquire the lock so the APC will go through */
+        KeReleaseDispatcherDatabaseLock(OldIrql);
+        OldIrql = KeAcquireDispatcherDatabaseLock();
+    }
+
+    /* Enter a critical region */
+    KeEnterCriticalRegion();
+
     /* Loop the Process's Threads */
     LIST_FOR_EACH(Current, &Process->ThreadListHead, KTHREAD, ThreadListEntry)
     {
         /* Make sure it's not ours */
-        if (Current == CurrentThread) continue;
-
-        /* Make sure it wasn't already frozen, and that it's not suspended */
-        if (!(++Current->FreezeCount) && !(Current->SuspendCount))
+        if (Current != CurrentThread)
         {
-            /* Insert the APC */
-            if (!KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT))
+            /* Should be bother inserting the APC? */
+            if (Current->ApcQueueable)
             {
-                /* Unsignal the Semaphore, the APC already got inserted */
-                Current->SuspendSemaphore.Header.SignalState--;
+                /* Make sure it wasn't already frozen, and that it's not suspended */
+                if (!(++Current->FreezeCount) && !(Current->SuspendCount))
+                {
+                    /* Did we already insert it? */
+                    if (!Current->SuspendApc.Inserted)
+                    {
+                        /* Insert the APC */
+                        Current->SuspendApc.Inserted = TRUE;
+                        KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
+                    }
+                    else
+                    {
+                        /* Unsignal the Semaphore, the APC already got inserted */
+                        Current->SuspendSemaphore.Header.SignalState--;
+                    }
+                }
             }
         }
     }
@@ -589,20 +611,30 @@
     {
         /* Raise an exception */
         KeReleaseDispatcherDatabaseLock(OldIrql);
-        ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
+        RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
     }
 
-    /* Increment it */
-    Thread->SuspendCount++;
+    /* Should we bother to queue at all? */
+    if (Thread->ApcQueueable)
+    {
+        /* Increment the suspend count */
+        Thread->SuspendCount++;
 
-    /* Check if we should suspend it */
-    if (!PreviousCount && !Thread->FreezeCount) {
-
-        /* Insert the APC */
-        if (!KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT)) {
-
-            /* Unsignal the Semaphore, the APC already got inserted */
-            Thread->SuspendSemaphore.Header.SignalState--;
+        /* Check if we should suspend it */
+        if (!PreviousCount && !Thread->FreezeCount)
+        {
+            /* Is the APC already inserted? */
+            if (!Thread->SuspendApc.Inserted)
+            {
+                /* Not inserted, insert it */
+                Thread->SuspendApc.Inserted = TRUE;
+                KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
+            }
+            else
+            {
+                /* Unsignal the Semaphore, the APC already got inserted */
+                Thread->SuspendSemaphore.Header.SignalState--;
+            }
         }
     }