[ntoskrnl]
[reactos.git] / reactos / ntoskrnl / ps / kill.c
index b443960..b1ea95f 100644 (file)
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* GLOBALS *******************************************************************/
 
-LIST_ENTRY PspReaperListHead = {0};
+LIST_ENTRY PspReaperListHead = { NULL, NULL };
 WORK_QUEUE_ITEM PspReaperWorkItem;
+LARGE_INTEGER ShortTime = {{-10 * 100 * 1000, -1}};
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
@@ -81,7 +82,8 @@ NTAPI
 PspTerminateProcess(IN PEPROCESS Process,
                     IN NTSTATUS ExitStatus)
 {
-    PETHREAD Thread = NULL;
+    PETHREAD Thread;
+    NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE;
     PAGED_CODE();
     PSTRACE(PS_KILL_DEBUG,
             "Process: %p ExitStatus: %p\n", Process, ExitStatus);
@@ -100,22 +102,35 @@ PspTerminateProcess(IN PEPROCESS Process,
     InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT);
 
     /* Get the first thread */
-    Thread = PsGetNextProcessThread(Process, Thread);
+    Thread = PsGetNextProcessThread(Process, NULL);
     while (Thread)
     {
         /* Kill it */
-        PSREFTRACE(Thread);
         PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
-        PSREFTRACE(Thread);
         Thread = PsGetNextProcessThread(Process, Thread);
+
+        /* We had at least one thread, so termination is OK */
+        Status = STATUS_SUCCESS;
     }
 
-    /* Clear the handle table */
-    if (Process->ObjectTable) ObClearProcessHandleTable(Process);
+    /* Check if there was nothing to terminate or if we have a debug port */
+    if ((Status == STATUS_NOTHING_TO_TERMINATE) || (Process->DebugPort))
+    {
+        /* Clear the handle table anyway */
+        ObClearProcessHandleTable(Process);
+    }
 
-    /* Return success*/
-    PSREFTRACE(Process);
-    return STATUS_SUCCESS;
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+PsTerminateProcess(IN PEPROCESS Process,
+                   IN NTSTATUS ExitStatus)
+{
+    /* Call the internal API */
+    return PspTerminateProcess(Process, ExitStatus);
 }
 
 VOID
@@ -154,19 +169,16 @@ VOID
 NTAPI
 PspReapRoutine(IN PVOID Context)
 {
-    PLIST_ENTRY *ListAddr;
-    PLIST_ENTRY NextEntry;
+    PSINGLE_LIST_ENTRY NextEntry;
     PETHREAD Thread;
     PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context);
 
-    /* Get the Reaper Address Pointer */
-    ListAddr = &PspReaperListHead.Flink;
-
     /* Start main loop */
     do
     {
         /* Write magic value and return the next entry to process */
-        NextEntry = InterlockedExchangePointer(ListAddr, (PVOID)1);
+        NextEntry = InterlockedExchangePointer(&PspReaperListHead.Flink,
+                                               (PVOID)1);
         ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1));
 
         /* Start inner loop */
@@ -176,20 +188,21 @@ PspReapRoutine(IN PVOID Context)
             Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink);
 
             /* Delete this entry's kernel stack */
-            MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit,
+            MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase,
                                 Thread->Tcb.LargeStack);
             Thread->Tcb.InitialStack = NULL;
 
             /* Move to the next entry */
-            NextEntry = NextEntry->Flink;
+            NextEntry = NextEntry->Next;
 
             /* Dereference this thread */
             ObDereferenceObject(Thread);
-            PSREFTRACE(Thread);
         } while ((NextEntry != NULL) && (NextEntry != (PVOID)1));
 
         /* Remove magic value, keep looping if it got changed */
-    } while (InterlockedCompareExchangePointer(ListAddr, 0, 1) != (PVOID)1);
+    } while (InterlockedCompareExchangePointer(&PspReaperListHead.Flink,
+                                               0,
+                                               1) != (PVOID)1);
 }
 
 VOID
@@ -236,7 +249,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
     /* Check if we have a debug port */
     if (Process->DebugPort)
     {
-        /* Dererence the Debug Port */
+        /* Deference the Debug Port */
         ObDereferenceObject(Process->DebugPort);
         Process->DebugPort = NULL;
     }
@@ -244,7 +257,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
     /* Check if we have an exception port */
     if (Process->ExceptionPort)
     {
-        /* Dererence the Exception Port */
+        /* Deference the Exception Port */
         ObDereferenceObject(Process->ExceptionPort);
         Process->ExceptionPort = NULL;
     }
@@ -252,14 +265,16 @@ PspDeleteProcess(IN PVOID ObjectBody)
     /* Check if we have a section object */
     if (Process->SectionObject)
     {
-        /* Dererence the Section Object */
+        /* Deference the Section Object */
         ObDereferenceObject(Process->SectionObject);
         Process->SectionObject = NULL;
     }
 
-    /* Clean LDT and VDM_OBJECTS */
+#if defined(_X86_)
+    /* Clean Ldt and Vdm objects */
     PspDeleteLdt(Process);
     PspDeleteVdmObjects(Process);
+#endif
 
     /* Delete the Object Table */
     if (Process->ObjectTable)
@@ -270,13 +285,10 @@ PspDeleteProcess(IN PVOID ObjectBody)
         /* Kill the Object Info */
         ObKillProcess(Process);
 
-        /* Dettach */
+        /* Detach */
         KeUnstackDetachProcess(&ApcState);
     }
 
-    /* KDB hook */
-    KDB_DELETEPROCESS_HOOK(Process);
-
     /* Check if we have an address space, and clean it */
     if (Process->HasAddressSpace)
     {
@@ -286,7 +298,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
         /* Clean the Address Space */
         PspExitProcess(FALSE, Process);
 
-        /* Dettach */
+        /* Detach */
         KeUnstackDetachProcess(&ApcState);
 
         /* Completely delete the Address Space */
@@ -294,13 +306,13 @@ PspDeleteProcess(IN PVOID ObjectBody)
     }
 
     /* See if we have a PID */
-    if(Process->UniqueProcessId)
+    if (Process->UniqueProcessId)
     {
         /* Delete the PID */
-        if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId)))
+        if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId, NULL)))
         {
             /* Something wrong happened, bugcheck */
-            KEBUGCHECK(CID_HANDLE_DELETION);
+            KeBugCheck(CID_HANDLE_DELETION);
         }
     }
 
@@ -322,7 +334,6 @@ PspDeleteProcess(IN PVOID ObjectBody)
 
     /* Destroy the Quota Block */
     PspDestroyQuotaBlock(Process);
-    PSREFTRACE(Process);
 }
 
 VOID
@@ -340,7 +351,7 @@ PspDeleteThread(IN PVOID ObjectBody)
     if (Thread->Tcb.InitialStack)
     {
         /* Release it */
-        MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit,
+        MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase,
                             Thread->Tcb.LargeStack);
     }
 
@@ -348,10 +359,10 @@ PspDeleteThread(IN PVOID ObjectBody)
     if (Thread->Cid.UniqueThread)
     {
         /* Delete the CID Handle */
-        if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread)))
+        if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread, NULL)))
         {
             /* Something wrong happened, bugcheck */
-            KEBUGCHECK(CID_HANDLE_DELETION);
+            KeBugCheck(CID_HANDLE_DELETION);
         }
     }
 
@@ -359,7 +370,6 @@ PspDeleteThread(IN PVOID ObjectBody)
     PspDeleteThreadSecurity(Thread);
 
     /* Make sure the thread was inserted, before continuing */
-    PSREFTRACE(Thread);
     if (!Process) return;
 
     /* Check if the thread list is valid */
@@ -379,8 +389,6 @@ PspDeleteThread(IN PVOID ObjectBody)
 
     /* Dereference the Process */
     ObDereferenceObject(Process);
-    PSREFTRACE(Thread);
-    PSREFTRACE(Process);
 }
 
 /*
@@ -395,7 +403,7 @@ PspExitThread(IN NTSTATUS ExitStatus)
     NTSTATUS Status;
     PTEB Teb;
     PEPROCESS CurrentProcess;
-    PETHREAD Thread;
+    PETHREAD Thread, OtherThread, PreviousThread = NULL;
     PVOID DeallocationStack;
     ULONG Dummy;
     BOOLEAN Last = FALSE;
@@ -412,12 +420,10 @@ PspExitThread(IN NTSTATUS ExitStatus)
     ASSERT((Thread) == PsGetCurrentThread());
 
     /* Can't terminate a thread if it attached another process */
-    PSREFTRACE(Thread);
-    PSREFTRACE(CurrentProcess);
     if (KeIsAttachedProcess())
     {
         /* Bugcheck */
-        KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
+        KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                      (ULONG_PTR)CurrentProcess,
                      (ULONG_PTR)Thread->Tcb.ApcState.Process,
                      (ULONG_PTR)Thread->Tcb.ApcStateIndex,
@@ -425,13 +431,13 @@ PspExitThread(IN NTSTATUS ExitStatus)
     }
 
     /* Lower to Passive Level */
-    KfLowerIrql(PASSIVE_LEVEL);
+    KeLowerIrql(PASSIVE_LEVEL);
 
     /* Can't be a worker thread */
     if (Thread->ActiveExWorker)
     {
         /* Bugcheck */
-        KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION,
+        KeBugCheckEx(ACTIVE_EX_WORKER_THREAD_TERMINATION,
                      (ULONG_PTR)Thread,
                      0,
                      0,
@@ -442,11 +448,11 @@ PspExitThread(IN NTSTATUS ExitStatus)
     if (Thread->Tcb.CombinedApcDisable != 0)
     {
         /* Bugcheck */
-        KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
+        KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT,
                      0,
-                     Thread->Tcb.KernelApcDisable,
-                     APC_LEVEL,
-                     0);
+                     Thread->Tcb.CombinedApcDisable,
+                     0,
+                     1);
     }
 
     /* Lock the thread */
@@ -491,7 +497,44 @@ PspExitThread(IN NTSTATUS ExitStatus)
             CurrentProcess->ExitStatus = ExitStatus;
         }
 
-        /* FIXME: Wait on the other threads to finish */
+        /* Loop all the current threads */
+        FirstEntry = &CurrentProcess->ThreadListHead;
+        CurrentEntry = FirstEntry->Flink;
+        while (FirstEntry != CurrentEntry)
+        {
+            /* Get the thread on the list */
+            OtherThread = CONTAINING_RECORD(CurrentEntry,
+                                            ETHREAD,
+                                            ThreadListEntry);
+
+            /* Check if it's a thread that's still alive */
+            if ((OtherThread != Thread) &&
+                !(KeReadStateThread(&OtherThread->Tcb)) &&
+                (ObReferenceObjectSafe(OtherThread)))
+            {
+                /* It's a live thread and we referenced it, unlock process */
+                ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
+                KeLeaveCriticalRegion();
+
+                /* Wait on the thread */
+                KeWaitForSingleObject(OtherThread,
+                                      Executive,
+                                      KernelMode,
+                                      FALSE,
+                                      NULL);
+
+                /* Check if we had a previous thread to dereference */
+                if (PreviousThread) ObDereferenceObject(PreviousThread);
+
+                /* Remember the thread and re-lock the process */
+                PreviousThread = OtherThread;
+                KeEnterCriticalRegion();
+                ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);
+            }
+
+            /* Go to the next thread */
+            CurrentEntry = CurrentEntry->Flink;
+        }
     }
     else if (ExitStatus != STATUS_THREAD_IS_TERMINATING)
     {
@@ -503,6 +546,9 @@ PspExitThread(IN NTSTATUS ExitStatus)
     ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
     KeLeaveCriticalRegion();
 
+    /* Check if we had a previous thread to dereference */
+    if (PreviousThread) ObDereferenceObject(PreviousThread);
+
     /* Check if the process has a debug port and if this is a user thread */
     if ((CurrentProcess->DebugPort) && !(Thread->SystemThread))
     {
@@ -534,7 +580,7 @@ PspExitThread(IN NTSTATUS ExitStatus)
         else
         {
             /* Bugcheck, we can't allow this */
-            KEBUGCHECKEX(CRITICAL_PROCESS_DIED,
+            KeBugCheckEx(CRITICAL_PROCESS_DIED,
                          (ULONG_PTR)CurrentProcess,
                          0,
                          0,
@@ -550,6 +596,7 @@ PspExitThread(IN NTSTATUS ExitStatus)
     if (TerminationPort)
     {
         /* Setup the message header */
+        TerminationMsg.h.u2.ZeroInit = 0;
         TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
         TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
         TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
@@ -561,15 +608,20 @@ PspExitThread(IN NTSTATUS ExitStatus)
             /* Save the Create Time */
             TerminationMsg.CreateTime = Thread->CreateTime;
 
-TryAgain:
-            /* Send the LPC Message */
-            Status = LpcRequestPort(TerminationPort->Port, &TerminationMsg.h);
-            if ((Status == STATUS_NO_MEMORY) ||
-                (Status == STATUS_INSUFFICIENT_RESOURCES))
+            /* Loop trying to send message */
+            while (TRUE)
             {
-                /* Wait a bit and try again */
-                KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
-                goto TryAgain;
+                /* Send the LPC Message */
+                Status = LpcRequestPort(TerminationPort->Port,
+                                        &TerminationMsg.h);
+                if ((Status == STATUS_NO_MEMORY) ||
+                    (Status == STATUS_INSUFFICIENT_RESOURCES))
+                {
+                    /* Wait a bit and try again */
+                    KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
+                    continue;
+                }
+                break;
             }
 
             /* Dereference this LPC Port */
@@ -582,7 +634,8 @@ TryAgain:
             ExFreePool(TerminationPort);
 
             /* Keep looping as long as there is a port */
-        } while ((TerminationPort = NextPort));
+            TerminationPort = NextPort;
+        } while (TerminationPort);
     }
     else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) &&
               (Thread->DeadThread)) ||
@@ -618,16 +671,20 @@ TryAgain:
             /* Save the Create Time */
             TerminationMsg.CreateTime = Thread->CreateTime;
 
-TryAgain2:
-            /* Send the LPC Message */
-            Status = LpcRequestPort(CurrentProcess->ExceptionPort,
-                                    &TerminationMsg.h);
-            if ((Status == STATUS_NO_MEMORY) ||
-                (Status == STATUS_INSUFFICIENT_RESOURCES))
+            /* Loop trying to send message */
+            while (TRUE)
             {
-                /* Wait a bit and try again */
-                KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
-                goto TryAgain2;
+                /* Send the LPC Message */
+                Status = LpcRequestPort(CurrentProcess->ExceptionPort,
+                                        &TerminationMsg.h);
+                if ((Status == STATUS_NO_MEMORY) ||
+                    (Status == STATUS_INSUFFICIENT_RESOURCES))
+                {
+                    /* Wait a bit and try again */
+                    KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
+                    continue;
+                }
+                break;
             }
         }
     }
@@ -637,18 +694,17 @@ TryAgain2:
                                                      PsW32ThreadCalloutExit);
 
     /* If we are the last thread and have a W32 Process */
-    PSREFTRACE(Thread);
     if ((Last) && (CurrentProcess->Win32Process))
     {
         /* Run it down too */
         PspW32ProcessCallout(CurrentProcess, FALSE);
     }
 
-    /* Make sure Stack Swap isn't enabled */
-    if (Thread->Tcb.EnableStackSwap)
+    /* Make sure Stack Swap is enabled */
+    if (!Thread->Tcb.EnableStackSwap)
     {
-        /* Stack swap really shouldn't be on during exit !*/
-        KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0);
+        /* Stack swap really shouldn't be disabled during exit! */
+        KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0);
     }
 
     /* Cancel I/O for the thread. */
@@ -665,25 +721,29 @@ TryAgain2:
 
     /* Check if we have a TEB */
     Teb = Thread->Tcb.Teb;
-    if(Teb)
+    if (Teb)
     {
-        /* Check if the thread isn't terminated and if we should free stack */
-        if (!(Thread->Terminated) && (Teb->FreeStackOnTermination))
+        /* Check if the thread is still alive */
+        if (!Thread->DeadThread)
         {
-            /* Set the TEB's Deallocation Stack as the Base Address */
-            Dummy = 0;
-            DeallocationStack = Teb->DeallocationStack;
-
-            /* Free the Thread's Stack */
-            ZwFreeVirtualMemory(NtCurrentProcess(),
-                                &DeallocationStack,
-                                &Dummy,
-                                MEM_RELEASE);
-        }
+            /* Check if we need to free its stack */
+            if (Teb->FreeStackOnTermination)
+            {
+                /* Set the TEB's Deallocation Stack as the Base Address */
+                Dummy = 0;
+                DeallocationStack = Teb->DeallocationStack;
+
+                /* Free the Thread's Stack */
+                ZwFreeVirtualMemory(NtCurrentProcess(),
+                                    &DeallocationStack,
+                                    &Dummy,
+                                    MEM_RELEASE);
+            }
 
-        /* Free the debug handle */
-        if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1],
-                                                 UserMode);
+            /* Free the debug handle */
+            if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1],
+                                                     UserMode);
+        }
 
         /* Decommit the TEB */
         MmDeleteTeb(CurrentProcess, Teb);
@@ -701,8 +761,6 @@ TryAgain2:
     ASSERT(Thread->Tcb.CombinedApcDisable == 0);
 
     /* Check if this is the final thread or not */
-    PSREFTRACE(Thread);
-    PSREFTRACE(CurrentProcess);
     if (Last)
     {
         /* Set the process exit time */
@@ -723,11 +781,10 @@ TryAgain2:
         ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken);
 
         /* Check if this is a VDM Process and rundown the VDM DPCs if so */
-        if (CurrentProcess->VdmObjects);// VdmRundownDpcs(CurrentProcess);
+        if (CurrentProcess->VdmObjects) { /* VdmRundownDpcs(CurrentProcess); */ }
 
         /* Kill the process in the Object Manager */
         ObKillProcess(CurrentProcess);
-        PSREFTRACE(CurrentProcess);
 
         /* Check if we have a section object */
         if (CurrentProcess->SectionObject)
@@ -759,6 +816,7 @@ TryAgain2:
     FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode);
     if (FirstEntry)
     {
+        /* Start with the first entry */
         CurrentEntry = FirstEntry;
         do
         {
@@ -772,7 +830,7 @@ TryAgain2:
            if (Apc->RundownRoutine)
            {
               /* Call its own routine */
-              (Apc->RundownRoutine)(Apc);
+              Apc->RundownRoutine(Apc);
            }
            else
            {
@@ -791,12 +849,12 @@ TryAgain2:
 
     /* Flush the APC queue, which should be empty */
     FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode);
-    if (FirstEntry)
+    if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0))
     {
         /* Bugcheck time */
-        KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
+        KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT,
                      (ULONG_PTR)FirstEntry,
-                     Thread->Tcb.KernelApcDisable,
+                     Thread->Tcb.CombinedApcDisable,
                      KeGetCurrentIrql(),
                      0);
     }
@@ -805,8 +863,6 @@ TryAgain2:
     if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE);
 
     /* Terminate the Thread from the Scheduler */
-    PSREFTRACE(Thread);
-    PSREFTRACE(CurrentProcess);
     KeTerminateThread(0);
 }
 
@@ -902,7 +958,7 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
     if ((bSelf) || (PsGetCurrentThread() == Thread))
     {
         /* This should only happen at passive */
-        ASSERT_IRQL(PASSIVE_LEVEL);
+        ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
 
         /* Mark it as terminated */
         PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT);
@@ -916,12 +972,14 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
 
     /* Allocate the APC */
     Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
+    if (!Apc) return STATUS_INSUFFICIENT_RESOURCES;
 
     /* Set the Terminated Flag */
-    Flags = Thread->CrossThreadFlags | 1;
+    Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT;
 
     /* Set it, and check if it was already set while we were running */
-    if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) & 1))
+    if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) &
+          CT_TERMINATED_BIT))
     {
         /* Initialize a Kernel Mode APC to Kill the Thread */
         KeInitializeApc(Apc,
@@ -937,7 +995,6 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
         if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
         {
             /* The APC was already in the queue, fail */
-            ExFreePool(Apc);
             Status = STATUS_UNSUCCESSFUL;
         }
         else
@@ -952,7 +1009,6 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
     ExFreePool(Apc);
 
     /* Return Status */
-    PSREFTRACE(Thread);
     return Status;
 }
 
@@ -997,7 +1053,6 @@ PspExitProcess(IN BOOLEAN LastThread,
     }
 
     /* Check if we are the last thread */
-    PSREFTRACE(Process);
     if (LastThread)
     {
         /* Check if we have to set the Timer Resolution */
@@ -1034,7 +1089,7 @@ PsTerminateSystemThread(IN NTSTATUS ExitStatus)
     PETHREAD Thread = PsGetCurrentThread();
 
     /* Make sure this is a system thread */
-    if (Thread->SystemThread) return STATUS_INVALID_PARAMETER;
+    if (!Thread->SystemThread) return STATUS_INVALID_PARAMETER;
 
     /* Terminate it for real */
     return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE);
@@ -1056,12 +1111,21 @@ NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
     PSTRACE(PS_KILL_DEBUG,
             "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle, ExitStatus);
 
-    /* Remember how we will kill it */
-    KillByHandle = (ProcessHandle != NULL);
+    /* Were we passed a process handle? */
+    if (ProcessHandle)
+    {
+        /* Yes we were, use it */
+        KillByHandle = TRUE;
+    }
+    else
+    {
+        /* We weren't... we assume this is suicide */
+        KillByHandle = FALSE;
+        ProcessHandle = NtCurrentProcess();
+    }
 
     /* Get the Process Object */
-    Status = ObReferenceObjectByHandle((KillByHandle) ?
-                                       ProcessHandle : NtCurrentProcess(),
+    Status = ObReferenceObjectByHandle(ProcessHandle,
                                        PROCESS_TERMINATE,
                                        PsProcessType,
                                        KeGetPreviousMode(),
@@ -1079,11 +1143,15 @@ NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
     }
 
     /* Lock the Process */
-    ExAcquireRundownProtection(&Process->RundownProtect);
+    if (!ExAcquireRundownProtection(&Process->RundownProtect))
+    {
+        /* Failed to lock, fail */
+        ObDereferenceObject (Process);
+        return STATUS_PROCESS_IS_TERMINATING;
+    }
 
-    /* Set the delete flag */
-    if (!KillByHandle) InterlockedOr((PLONG)&Process->Flags,
-                                     PSF_PROCESS_DELETE_BIT);
+    /* Set the delete flag, unless the process is comitting suicide */
+    if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT);
 
     /* Get the first thread */
     Status = STATUS_NOTHING_TO_TERMINATE;
@@ -1104,29 +1172,30 @@ NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
             }
 
             /* Move to the next thread */
-        } while((Thread = PsGetNextProcessThread(Process, Thread)));
+            Thread = PsGetNextProcessThread(Process, Thread);
+        } while (Thread);
     }
 
     /* Unlock the process */
     ExReleaseRundownProtection(&Process->RundownProtect);
 
     /* Check if we are killing ourselves */
-    if (Process != CurrentProcess)
+    if (Process == CurrentProcess)
     {
-        /* Check for the DBG_TERMINATE_PROCESS exit code */
-        if (ExitStatus == DBG_TERMINATE_PROCESS)
+        /* Also make sure the caller gave us our handle */
+        if (KillByHandle)
         {
-            /* FIXME: Disable debugging on this process */
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+
+            /* Terminate ourselves */
+            PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE);
         }
     }
-    /* Make sure that we got a handle */
-    else if (KillByHandle)
+    else if (ExitStatus == DBG_TERMINATE_PROCESS)
     {
-        /* Dereference the project */
-        ObDereferenceObject(Process);
-
-        /* Terminate ourselves */
-        PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE);
+        /* Disable debugging on this process */
+        DbgkClearProcessDebugObject(Process, NULL);
     }
 
     /* Check if there was nothing to terminate, or if we have a Debug Port */
@@ -1233,7 +1302,7 @@ NtRegisterThreadTerminatePort(IN HANDLE PortHandle)
     /* Allocate the Port and make sure it suceeded */
     TerminationPort = ExAllocatePoolWithTag(NonPagedPool,
                                             sizeof(TERMINATION_PORT),
-                                            TAG('P', 's', 'T', '='));
+                                            '=TsP');
     if(TerminationPort)
     {
         /* Associate the Port */