1999-01-16 21:03:00 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/ps/kill.c
|
|
|
|
* PURPOSE: Terminating a thread
|
1999-03-25 00:37:06 +00:00
|
|
|
* PROGRAMMER: David Welch (welch@cwcom.net)
|
1999-01-16 21:03:00 +00:00
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 22/05/98
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include <ddk/ntddk.h>
|
|
|
|
#include <internal/ps.h>
|
1999-03-25 00:37:06 +00:00
|
|
|
#include <internal/ke.h>
|
1999-04-01 12:39:43 +00:00
|
|
|
#include <internal/mm.h>
|
|
|
|
#include <internal/ob.h>
|
2000-04-03 21:54:42 +00:00
|
|
|
#include <internal/port.h>
|
1999-01-16 21:03:00 +00:00
|
|
|
|
1999-12-13 22:04:41 +00:00
|
|
|
#define NDEBUG
|
1999-01-16 21:03:00 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
1999-04-10 12:08:24 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
1999-01-16 21:03:00 +00:00
|
|
|
|
|
|
|
extern ULONG PiNrThreads;
|
1999-11-02 08:55:45 +00:00
|
|
|
extern ULONG PiNrRunnableThreads;
|
|
|
|
extern KSPIN_LOCK PiThreadListLock;
|
1999-12-18 17:48:23 +00:00
|
|
|
extern LIST_ENTRY PiThreadListHead;
|
2000-07-07 00:49:02 +00:00
|
|
|
extern KSPIN_LOCK PiApcLock;
|
|
|
|
|
|
|
|
VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
|
1999-01-16 21:03:00 +00:00
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2000-12-23 02:37:41 +00:00
|
|
|
VOID
|
|
|
|
PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus)
|
1999-12-18 17:48:23 +00:00
|
|
|
{
|
|
|
|
KIRQL oldlvl;
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PETHREAD current;
|
2000-02-14 14:13:34 +00:00
|
|
|
|
|
|
|
DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
|
|
|
|
Process, ExitStatus);
|
|
|
|
|
1999-12-18 17:48:23 +00:00
|
|
|
KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
|
|
|
|
|
2000-07-07 00:49:02 +00:00
|
|
|
current_entry = Process->ThreadListHead.Flink;
|
|
|
|
while (current_entry != &Process->ThreadListHead)
|
1999-12-18 17:48:23 +00:00
|
|
|
{
|
2000-12-23 02:37:41 +00:00
|
|
|
current = CONTAINING_RECORD(current_entry, ETHREAD,
|
|
|
|
Tcb.ProcessThreadListEntry);
|
|
|
|
if (current != PsGetCurrentThread() &&
|
|
|
|
current->DeadThread == 0)
|
1999-12-18 17:48:23 +00:00
|
|
|
{
|
2000-12-23 02:37:41 +00:00
|
|
|
DPRINT("Terminating %x, current thread: %x, "
|
|
|
|
"thread's process: %x\n", current, PsGetCurrentThread(),
|
|
|
|
current->ThreadsProcess);
|
|
|
|
KeReleaseSpinLock(&PiThreadListLock, oldlvl);
|
1999-12-18 17:48:23 +00:00
|
|
|
PsTerminateOtherThread(current, ExitStatus);
|
2000-12-23 02:37:41 +00:00
|
|
|
KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
|
|
|
|
current_entry = Process->ThreadListHead.Flink;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
current_entry = current_entry->Flink;
|
1999-12-18 17:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&PiThreadListLock, oldlvl);
|
2000-02-14 14:13:34 +00:00
|
|
|
DPRINT("Finished PiTerminateProcessThreads()\n");
|
1999-12-18 17:48:23 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 02:37:41 +00:00
|
|
|
VOID
|
|
|
|
PsReapThreads(VOID)
|
1999-12-18 17:48:23 +00:00
|
|
|
{
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PETHREAD current;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
|
|
|
|
// DPRINT1("PsReapThreads()\n");
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
|
|
|
|
|
|
|
|
current_entry = PiThreadListHead.Flink;
|
|
|
|
|
|
|
|
while (current_entry != &PiThreadListHead)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, ETHREAD,
|
|
|
|
Tcb.ThreadListEntry);
|
|
|
|
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
|
|
|
|
if (current->Tcb.State == THREAD_STATE_TERMINATED_1)
|
|
|
|
{
|
|
|
|
PEPROCESS Process = current->ThreadsProcess;
|
|
|
|
NTSTATUS Status = current->ExitStatus;
|
|
|
|
|
1999-12-26 15:50:53 +00:00
|
|
|
DPRINT("PsProcessType %x\n", PsProcessType);
|
1999-12-18 17:48:23 +00:00
|
|
|
DPRINT("Reaping thread %x\n", current);
|
1999-12-26 15:50:53 +00:00
|
|
|
DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
|
1999-12-18 17:48:23 +00:00
|
|
|
current->Tcb.State = THREAD_STATE_TERMINATED_2;
|
|
|
|
RemoveEntryList(¤t->Tcb.ProcessThreadListEntry);
|
2000-07-04 08:52:47 +00:00
|
|
|
if (IsListEmpty(&Process->ThreadListHead))
|
1999-12-18 17:48:23 +00:00
|
|
|
{
|
|
|
|
DPRINT("Last thread terminated, terminating process\n");
|
2000-07-07 00:49:02 +00:00
|
|
|
KeReleaseSpinLock( &PiThreadListLock, oldIrql );
|
1999-12-18 17:48:23 +00:00
|
|
|
PiTerminateProcess(Process, Status);
|
2000-07-07 00:49:02 +00:00
|
|
|
KeAcquireSpinLock( &PiThreadListLock, &oldIrql );
|
1999-12-18 17:48:23 +00:00
|
|
|
}
|
1999-12-26 15:50:53 +00:00
|
|
|
DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
|
2000-07-07 00:49:02 +00:00
|
|
|
KeReleaseSpinLock(&PiThreadListLock, oldIrql);
|
|
|
|
ObDereferenceObject(current);
|
|
|
|
KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
|
1999-12-18 17:48:23 +00:00
|
|
|
current_entry = PiThreadListHead.Flink;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&PiThreadListLock, oldIrql);
|
|
|
|
}
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
VOID PsTerminateCurrentThread(NTSTATUS ExitStatus)
|
1999-02-06 18:34:14 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Terminates the current thread
|
|
|
|
*/
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
1999-12-13 22:04:41 +00:00
|
|
|
KIRQL oldIrql;
|
1999-01-16 21:03:00 +00:00
|
|
|
PETHREAD CurrentThread;
|
|
|
|
|
|
|
|
CurrentThread = PsGetCurrentThread();
|
|
|
|
|
|
|
|
DPRINT("terminating %x\n",CurrentThread);
|
1999-12-13 22:04:41 +00:00
|
|
|
KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
|
|
|
|
|
|
|
|
CurrentThread->ExitStatus = ExitStatus;
|
2000-02-14 14:13:34 +00:00
|
|
|
KeAcquireDispatcherDatabaseLock(FALSE);
|
1999-10-07 23:46:27 +00:00
|
|
|
CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
|
1999-09-06 21:32:57 +00:00
|
|
|
KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
|
2000-02-14 14:13:34 +00:00
|
|
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
1999-12-26 15:50:53 +00:00
|
|
|
|
1999-12-13 22:04:41 +00:00
|
|
|
PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
|
1999-11-12 12:01:17 +00:00
|
|
|
KeBugCheck(0);
|
1999-01-16 21:03:00 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 02:37:41 +00:00
|
|
|
VOID
|
|
|
|
PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus)
|
1999-02-06 18:34:14 +00:00
|
|
|
/*
|
2000-07-07 00:49:02 +00:00
|
|
|
* FUNCTION: Terminate a thread when calling from another thread's context
|
2000-12-23 02:37:41 +00:00
|
|
|
* NOTES: This function must be called with PiThreadListLock held
|
1999-02-06 18:34:14 +00:00
|
|
|
*/
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
2000-02-14 14:13:34 +00:00
|
|
|
DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
|
|
|
|
Thread, ExitStatus);
|
|
|
|
|
2001-01-17 15:38:03 +00:00
|
|
|
/*
|
|
|
|
* We must synchronize the termination of a thread with its execution
|
|
|
|
* so all this routine does is to mark the thread as terminated and
|
|
|
|
* wake it if possible. The thread will then kill itself when it
|
|
|
|
* next exits kernel mode.
|
|
|
|
*/
|
2000-07-07 00:49:02 +00:00
|
|
|
Thread->DeadThread = 1;
|
|
|
|
Thread->ExitStatus = ExitStatus;
|
2000-12-23 02:37:41 +00:00
|
|
|
if (Thread->Tcb.State == THREAD_STATE_FROZEN &&
|
|
|
|
(Thread->Tcb.Alertable || Thread->Tcb.WaitMode == UserMode))
|
|
|
|
{
|
|
|
|
KeRemoveAllWaitsThread(Thread, STATUS_ALERTED);
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
}
|
|
|
|
|
2000-12-23 02:37:41 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
PiTerminateProcess(PEPROCESS Process, NTSTATUS ExitStatus)
|
1999-11-24 11:51:55 +00:00
|
|
|
{
|
2000-04-23 18:01:21 +00:00
|
|
|
DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) RC %d HC %d\n",
|
2000-04-07 02:24:03 +00:00
|
|
|
Process, ExitStatus, ObGetReferenceCount(Process),
|
|
|
|
ObGetHandleCount(Process));
|
1999-11-24 11:51:55 +00:00
|
|
|
|
1999-12-26 15:50:53 +00:00
|
|
|
if (Process->Pcb.ProcessState == PROCESS_STATE_TERMINATED)
|
|
|
|
{
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-12-20 02:14:40 +00:00
|
|
|
ObCloseAllHandles(Process);
|
2000-02-14 14:13:34 +00:00
|
|
|
KeAcquireDispatcherDatabaseLock(FALSE);
|
1999-11-24 11:51:55 +00:00
|
|
|
Process->Pcb.ProcessState = PROCESS_STATE_TERMINATED;
|
|
|
|
Process->Pcb.DispatcherHeader.SignalState = TRUE;
|
|
|
|
KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
|
2000-02-14 14:13:34 +00:00
|
|
|
KeReleaseDispatcherDatabaseLock(FALSE);
|
2000-04-03 21:54:42 +00:00
|
|
|
DPRINT("RC %d\n", ObGetReferenceCount(Process));
|
1999-11-24 11:51:55 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
|
1999-11-02 08:55:45 +00:00
|
|
|
NTSTATUS STDCALL NtTerminateProcess(IN HANDLE ProcessHandle,
|
|
|
|
IN NTSTATUS ExitStatus)
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PEPROCESS Process;
|
1999-04-01 12:39:43 +00:00
|
|
|
|
1999-06-18 22:11:21 +00:00
|
|
|
DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
|
2000-02-14 14:13:34 +00:00
|
|
|
ProcessHandle, ExitStatus);
|
1999-04-01 12:39:43 +00:00
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
Status = ObReferenceObjectByHandle(ProcessHandle,
|
|
|
|
PROCESS_TERMINATE,
|
|
|
|
PsProcessType,
|
|
|
|
UserMode,
|
|
|
|
(PVOID*)&Process,
|
|
|
|
NULL);
|
2000-02-14 14:13:34 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
1999-04-01 12:39:43 +00:00
|
|
|
|
2000-07-07 00:49:02 +00:00
|
|
|
PiTerminateProcessThreads(Process, ExitStatus);
|
2000-08-12 19:33:23 +00:00
|
|
|
if (PsGetCurrentThread()->ThreadsProcess == Process)
|
2000-07-07 00:49:02 +00:00
|
|
|
{
|
2000-08-12 19:33:23 +00:00
|
|
|
ObDereferenceObject(Process);
|
|
|
|
PsTerminateCurrentThread(ExitStatus);
|
2000-07-07 00:49:02 +00:00
|
|
|
}
|
1999-04-01 12:39:43 +00:00
|
|
|
ObDereferenceObject(Process);
|
1999-01-16 21:03:00 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
NTSTATUS STDCALL NtTerminateThread(IN HANDLE ThreadHandle,
|
|
|
|
IN NTSTATUS ExitStatus)
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
|
|
|
PETHREAD Thread;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(ThreadHandle,
|
|
|
|
THREAD_TERMINATE,
|
|
|
|
PsThreadType,
|
|
|
|
UserMode,
|
|
|
|
(PVOID*)&Thread,
|
|
|
|
NULL);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
1999-12-02 20:53:55 +00:00
|
|
|
|
|
|
|
ObDereferenceObject(Thread);
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
if (Thread == PsGetCurrentThread())
|
|
|
|
{
|
|
|
|
PsTerminateCurrentThread(ExitStatus);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PsTerminateOtherThread(Thread, ExitStatus);
|
|
|
|
}
|
1999-02-06 18:34:14 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-01-16 21:03:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-03 21:36:32 +00:00
|
|
|
NTSTATUS STDCALL PsTerminateSystemThread(NTSTATUS ExitStatus)
|
1999-01-16 21:03:00 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Terminates the current thread
|
|
|
|
* ARGUMENTS:
|
|
|
|
* ExitStatus = Status to pass to the creater
|
|
|
|
* RETURNS: Doesn't
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PsTerminateCurrentThread(ExitStatus);
|
1999-02-06 18:34:14 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-01-16 21:03:00 +00:00
|
|
|
}
|
|
|
|
|
2001-01-17 15:38:03 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
NtCallTerminatePorts(PETHREAD Thread)
|
2000-04-03 21:54:42 +00:00
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PEPORT_TERMINATION_REQUEST current;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
|
|
|
|
while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
|
|
|
|
&Thread->TerminationPortList);
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry,
|
|
|
|
EPORT_TERMINATION_REQUEST,
|
|
|
|
ThreadListEntry);
|
|
|
|
KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
|
|
|
|
LpcSendTerminationPort(current->Port,
|
|
|
|
Thread->CreateTime);
|
|
|
|
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
|
2001-01-17 15:38:03 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
|
1999-01-16 21:03:00 +00:00
|
|
|
{
|
2000-04-03 21:54:42 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
PEPORT_TERMINATION_REQUEST Request;
|
|
|
|
PEPORT TerminationPort;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
PETHREAD Thread;
|
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(TerminationPortHandle,
|
|
|
|
PORT_ALL_ACCESS,
|
|
|
|
ExPortType,
|
|
|
|
UserMode,
|
|
|
|
(PVOID*)&TerminationPort,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
Request = ExAllocatePool(NonPagedPool, sizeof(Request));
|
|
|
|
Request->Port = TerminationPort;
|
|
|
|
Thread = PsGetCurrentThread();
|
|
|
|
KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
|
|
|
|
InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
|
|
|
|
KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
1999-01-16 21:03:00 +00:00
|
|
|
}
|