#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 *********************************************************/
+VOID
+NTAPI
+PspCatchCriticalBreak(IN PCHAR Message,
+ IN PVOID ProcessOrThread,
+ IN PCHAR ImageName)
+{
+ CHAR Action[2];
+ BOOLEAN Handled = FALSE;
+ PAGED_CODE();
+
+ /* Check if a debugger is enabled */
+ if (KdDebuggerEnabled)
+ {
+ /* Print out the message */
+ DbgPrint(Message, ProcessOrThread, ImageName);
+ do
+ {
+ /* If a debugger isn't present, don't prompt */
+ if (KdDebuggerNotPresent) break;
+
+ /* A debuger is active, prompt for action */
+ DbgPrompt("Break, or Ignore (bi)?", Action, sizeof(Action));
+ switch (Action[0])
+ {
+ /* Break */
+ case 'B': case 'b':
+
+ /* Do a breakpoint */
+ DbgBreakPoint();
+
+ /* Ignore */
+ case 'I': case 'i':
+
+ /* Handle it */
+ Handled = TRUE;
+
+ /* Unrecognized */
+ default:
+ break;
+ }
+ } while (!Handled);
+ }
+
+ /* Did we ultimately handle this? */
+ if (!Handled)
+ {
+ /* We didn't, bugcheck */
+ KeBugCheckEx(CRITICAL_OBJECT_TERMINATION,
+ ((PKPROCESS)ProcessOrThread)->Header.Type,
+ (ULONG_PTR)ProcessOrThread,
+ (ULONG_PTR)ImageName,
+ (ULONG_PTR)Message);
+ }
+}
+
NTSTATUS
NTAPI
PspTerminateProcess(IN PEPROCESS Process,
IN NTSTATUS ExitStatus)
{
+ PETHREAD Thread;
+ NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE;
PAGED_CODE();
- PETHREAD Thread = NULL;
+ PSTRACE(PS_KILL_DEBUG,
+ "Process: %p ExitStatus: %p\n", Process, ExitStatus);
+ PSREFTRACE(Process);
- /* Check if this is a Critical Process, and Bugcheck */
+ /* Check if this is a Critical Process */
if (Process->BreakOnTermination)
{
- /* FIXME: Add critical Process support */
- DPRINT1("A critical Process is being terminated\n");
- KEBUGCHECK(0);
+ /* Break to debugger */
+ PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
+ Process,
+ Process->ImageFileName);
}
/* Set the delete flag */
InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT);
/* Get the first thread */
- Thread = PsGetNextProcessThread(Process, Thread);
+ Thread = PsGetNextProcessThread(Process, NULL);
while (Thread)
{
/* Kill it */
PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
Thread = PsGetNextProcessThread(Process, Thread);
+
+ /* We had at least one thread, so termination is OK */
+ Status = STATUS_SUCCESS;
+ }
+
+ /* 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);
}
- /* Clear the handle table */
- if (Process->ObjectTable) ObClearProcessHandleTable(Process);
+ /* Return status */
+ return Status;
+}
- /* Return success*/
- return STATUS_SUCCESS;
+NTSTATUS
+NTAPI
+PsTerminateProcess(IN PEPROCESS Process,
+ IN NTSTATUS ExitStatus)
+{
+ /* Call the internal API */
+ return PspTerminateProcess(Process, ExitStatus);
}
VOID
PEPROCESS Process = NULL;
/* Loop every process */
- Process == PsGetNextProcess(Process);
+ Process = PsGetNextProcess(Process);
while (Process)
{
/* Make sure this isn't the idle or initial process */
}
/* Get the next process */
- Process == PsGetNextProcess(Process);
+ Process = PsGetNextProcess(Process);
}
}
NTAPI
PspReapRoutine(IN PVOID Context)
{
- PLIST_ENTRY *ListAddr;
- PLIST_ENTRY NextEntry;
+ PSINGLE_LIST_ENTRY NextEntry;
PETHREAD Thread;
-
- /* Get the Reaper Address Pointer */
- ListAddr = &PspReaperListHead.Flink;
+ PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context);
/* 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 */
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);
} 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
PEPROCESS Process = (PEPROCESS)ObjectBody;
KAPC_STATE ApcState;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody);
+ PSREFTRACE(Process);
/* Check if it has an Active Process Link */
if (Process->ActiveProcessLinks.Flink)
/* Check if we have a debug port */
if (Process->DebugPort)
{
- /* Dererence the Debug Port */
+ /* Deference the Debug Port */
ObDereferenceObject(Process->DebugPort);
Process->DebugPort = NULL;
}
/* Check if we have an exception port */
if (Process->ExceptionPort)
{
- /* Dererence the Exception Port */
+ /* Deference the Exception Port */
ObDereferenceObject(Process->ExceptionPort);
Process->ExceptionPort = NULL;
}
/* 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)
/* 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)
{
/* Clean the Address Space */
PspExitProcess(FALSE, Process);
- /* Dettach */
+ /* Detach */
KeUnstackDetachProcess(&ApcState);
/* Completely delete the Address Space */
}
/* 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);
}
}
PETHREAD Thread = (PETHREAD)ObjectBody;
PEPROCESS Process = Thread->ThreadsProcess;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody);
+ PSREFTRACE(Thread);
ASSERT(Thread->Tcb.Win32Thread == NULL);
/* Check if we have a stack */
if (Thread->Tcb.InitialStack)
{
/* Release it */
- MmDeleteKernelStack((PVOID)Thread->Tcb.StackLimit,
+ MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase,
Thread->Tcb.LargeStack);
}
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);
}
}
NTSTATUS Status;
PTEB Teb;
PEPROCESS CurrentProcess;
- PETHREAD Thread;
+ PETHREAD Thread, OtherThread, PreviousThread = NULL;
PVOID DeallocationStack;
ULONG Dummy;
BOOLEAN Last = FALSE;
PKAPC Apc;
PTOKEN PrimaryToken;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG, "ExitStatus: %p\n", ExitStatus);
/* Get the Current Thread and Process */
Thread = PsGetCurrentThread();
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,
}
/* 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,
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 */
KeEnterCriticalRegion();
ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);
- /* Wake up the thread so we don't deadlock on lock */
- //KeForceResumeThread(&Thread->Tcb);
-
/* Decrease the active thread count, and check if it's 0 */
if (!(--CurrentProcess->ActiveThreads))
{
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)
{
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))
{
/* Check if this is a Critical Thread */
if ((KdDebuggerEnabled) && (Thread->BreakOnTermination))
{
- /* FIXME: Add critical thread support */
- KEBUGCHECK(0);
+ /* Break to debugger */
+ PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
+ Thread,
+ CurrentProcess->ImageFileName);
}
/* Check if it's the last thread and this is a Critical Process */
/* Check if a debugger is here to handle this */
if (KdDebuggerEnabled)
{
- /* FIXME: Add critical process support */
- DbgBreakPoint();
+ /* Break to debugger */
+ PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n",
+ CurrentProcess,
+ CurrentProcess->ImageFileName);
}
else
{
/* Bugcheck, we can't allow this */
- KEBUGCHECKEX(CRITICAL_PROCESS_DIED,
+ KeBugCheckEx(CRITICAL_PROCESS_DIED,
(ULONG_PTR)CurrentProcess,
0,
0,
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) -
/* 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 */
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)) ||
/* 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;
}
}
}
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. */
/* 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);
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);
FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode);
if (FirstEntry)
{
+ /* Start with the first entry */
CurrentEntry = FirstEntry;
do
{
if (Apc->RundownRoutine)
{
/* Call its own routine */
- (Apc->RundownRoutine)(Apc);
+ Apc->RundownRoutine(Apc);
}
else
{
/* 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);
}
IN OUT PKNORMAL_ROUTINE* NormalRoutine,
IN OUT PVOID* NormalContext,
IN OUT PVOID* SystemArgument1,
- IN OUT PVOID* SystemArguemnt2)
+ IN OUT PVOID* SystemArgument2)
{
NTSTATUS Status;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG,
+ "Apc: %p SystemArgument2: %p \n", Apc, SystemArgument2);
/* Don't do anything unless we are in User-Mode */
if (Apc->SystemArgument2)
PKAPC Apc = (PKAPC)SystemArgument1;
PETHREAD Thread = PsGetCurrentThread();
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG, "SystemArgument2: %p \n", SystemArgument2);
/* This should never happen */
ASSERT(!(((ULONG_PTR)SystemArgument2) & 1));
NTSTATUS Status = STATUS_SUCCESS;
ULONG Flags;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG, "Thread: %p ExitStatus: %p\n", Thread, ExitStatus);
+ PSREFTRACE(Thread);
/* Check if this is a Critical Thread, and Bugcheck */
if (Thread->BreakOnTermination)
{
- /* FIXME: Add critical thread support */
- DPRINT1("A critical thread is being terminated\n");
- KEBUGCHECK(0);
+ /* Break to debugger */
+ PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
+ Thread,
+ Thread->ThreadsProcess->ImageFileName);
}
/* Check if we are already inside the thread */
if ((bSelf) || (PsGetCurrentThread() == Thread))
{
/* This should only happen at passive */
- ASSERT_IRQL(PASSIVE_LEVEL);
+ ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
/* Mark it as terminated */
- InterlockedOr((PLONG)&Thread->CrossThreadFlags, CT_TERMINATED_BIT);
+ PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT);
/* Directly terminate the thread */
PspExitThread(ExitStatus);
/* 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,
if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
{
/* The APC was already in the queue, fail */
- ExFreePool(Apc);
Status = STATUS_UNSUCCESSFUL;
}
else
{
ULONG Actual;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG,
+ "LastThread: %p Process: %p\n", LastThread, Process);
+ PSREFTRACE(Process);
/* Set Process Exit flag */
InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_EXITING_BIT);
PETHREAD Thread = PsGetCurrentThread();
/* Make sure this is a system thread */
- if (Thread->SystemThread)
- {
- DPRINT1("Trying to Terminate a non-system thread!\n");
- return STATUS_INVALID_PARAMETER;
- }
+ if (!Thread->SystemThread) return STATUS_INVALID_PARAMETER;
/* Terminate it for real */
return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE);
PETHREAD Thread, CurrentThread = PsGetCurrentThread();
BOOLEAN KillByHandle;
PAGED_CODE();
+ 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(),
/* Check if this is a Critical Process, and Bugcheck */
if (Process->BreakOnTermination)
{
- /* FIXME: Add critical Process support */
- DPRINT1("A critical Process is being terminated\n");
- KEBUGCHECK(0);
+ /* Break to debugger */
+ PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
+ Process,
+ Process->ImageFileName);
}
/* 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;
}
/* 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 */
PETHREAD CurrentThread = PsGetCurrentThread();
NTSTATUS Status;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG,
+ "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle, ExitStatus);
/* Handle the special NULL case */
if (!ThreadHandle)
PVOID TerminationLpcPort;
PETHREAD Thread;
PAGED_CODE();
+ PSTRACE(PS_KILL_DEBUG, "PortHandle: %p\n", PortHandle);
/* Get the Port */
Status = ObReferenceObjectByHandle(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 */