2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/kill.c
5 * PURPOSE: Terminating a thread
6 * PROGRAMMER: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
13 #include <ddk/ntddk.h>
14 #include <internal/ps.h>
15 #include <internal/ke.h>
16 #include <internal/mm.h>
17 #include <internal/ob.h>
18 #include <internal/port.h>
21 #include <internal/debug.h>
23 /* GLOBALS *******************************************************************/
25 extern ULONG PiNrThreads
;
26 extern ULONG PiNrRunnableThreads
;
27 extern KSPIN_LOCK PiThreadListLock
;
28 extern LIST_ENTRY PiThreadListHead
;
30 /* FUNCTIONS *****************************************************************/
32 VOID
PiTerminateProcessThreads(PEPROCESS Process
, NTSTATUS ExitStatus
)
35 PLIST_ENTRY current_entry
;
38 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
41 KeAcquireSpinLock(&PiThreadListLock
, &oldlvl
);
43 current_entry
= PiThreadListHead
.Flink
;
44 while (current_entry
!= &PiThreadListHead
)
46 current
= CONTAINING_RECORD(current_entry
,ETHREAD
,Tcb
.QueueListEntry
);
47 if (current
->ThreadsProcess
== Process
&&
48 current
!= PsGetCurrentThread())
50 KeReleaseSpinLock(&PiThreadListLock
, oldlvl
);
51 DPRINT("Terminating %x\n", current
);
52 PsTerminateOtherThread(current
, ExitStatus
);
53 KeAcquireSpinLock(&PiThreadListLock
, &oldlvl
);
54 current_entry
= PiThreadListHead
.Flink
;
56 current_entry
= current_entry
->Flink
;
59 KeReleaseSpinLock(&PiThreadListLock
, oldlvl
);
60 DPRINT("Finished PiTerminateProcessThreads()\n");
63 VOID
PsReapThreads(VOID
)
65 PLIST_ENTRY current_entry
;
69 // DPRINT1("PsReapThreads()\n");
71 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
73 current_entry
= PiThreadListHead
.Flink
;
75 while (current_entry
!= &PiThreadListHead
)
77 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
80 current_entry
= current_entry
->Flink
;
82 if (current
->Tcb
.State
== THREAD_STATE_TERMINATED_1
)
84 PEPROCESS Process
= current
->ThreadsProcess
;
85 NTSTATUS Status
= current
->ExitStatus
;
87 DPRINT("PsProcessType %x\n", PsProcessType
);
88 ObReferenceObjectByPointer(Process
,
92 DPRINT("Reaping thread %x\n", current
);
93 DPRINT("Ref count %d\n", ObGetReferenceCount(Process
));
94 current
->Tcb
.State
= THREAD_STATE_TERMINATED_2
;
95 RemoveEntryList(¤t
->Tcb
.ProcessThreadListEntry
);
96 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
97 ObDereferenceObject(current
);
98 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
99 if (IsListEmpty(&Process
->Pcb
.ThreadListHead
))
102 * TODO: Optimize this so it doesnt jerk the IRQL around so
105 DPRINT("Last thread terminated, terminating process\n");
106 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
107 PiTerminateProcess(Process
, Status
);
108 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
110 DPRINT("Ref count %d\n", ObGetReferenceCount(Process
));
111 ObDereferenceObject(Process
);
112 current_entry
= PiThreadListHead
.Flink
;
115 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
118 VOID
PsTerminateCurrentThread(NTSTATUS ExitStatus
)
120 * FUNCTION: Terminates the current thread
124 PETHREAD CurrentThread
;
126 CurrentThread
= PsGetCurrentThread();
128 DPRINT("terminating %x\n",CurrentThread
);
129 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
131 CurrentThread
->ExitStatus
= ExitStatus
;
132 KeAcquireDispatcherDatabaseLock(FALSE
);
133 CurrentThread
->Tcb
.DispatcherHeader
.SignalState
= TRUE
;
134 KeDispatcherObjectWake(&CurrentThread
->Tcb
.DispatcherHeader
);
135 KeReleaseDispatcherDatabaseLock(FALSE
);
137 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1
);
141 VOID
PsTerminateOtherThread(PETHREAD Thread
, NTSTATUS ExitStatus
)
143 * FUNCTION: Terminate a thread when calling from that thread's context
148 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
151 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
152 if (Thread
->Tcb
.State
== THREAD_STATE_RUNNABLE
)
154 DPRINT("Removing from runnable queue\n");
155 RemoveEntryList(&Thread
->Tcb
.QueueListEntry
);
157 DPRINT("Removing from process queue\n");
158 RemoveEntryList(&Thread
->Tcb
.ProcessThreadListEntry
);
159 Thread
->Tcb
.State
= THREAD_STATE_TERMINATED_2
;
160 Thread
->Tcb
.DispatcherHeader
.SignalState
= TRUE
;
161 KeDispatcherObjectWake(&Thread
->Tcb
.DispatcherHeader
);
162 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
163 if (IsListEmpty(&Thread
->ThreadsProcess
->Pcb
.ThreadListHead
))
165 DPRINT("Terminating associated process\n");
166 PiTerminateProcess(Thread
->ThreadsProcess
, ExitStatus
);
168 ObDereferenceObject(Thread
);
171 NTSTATUS STDCALL
PiTerminateProcess(PEPROCESS Process
,
174 DPRINT1("PiTerminateProcess(Process %x, ExitStatus %x) RC %d\n",
175 Process
, ExitStatus
, ObGetReferenceCount(Process
));
177 if (Process
->Pcb
.ProcessState
== PROCESS_STATE_TERMINATED
)
179 return(STATUS_SUCCESS
);
182 PiTerminateProcessThreads(Process
, ExitStatus
);
183 ObCloseAllHandles(Process
);
184 KeAcquireDispatcherDatabaseLock(FALSE
);
185 Process
->Pcb
.ProcessState
= PROCESS_STATE_TERMINATED
;
186 Process
->Pcb
.DispatcherHeader
.SignalState
= TRUE
;
187 KeDispatcherObjectWake(&Process
->Pcb
.DispatcherHeader
);
188 KeReleaseDispatcherDatabaseLock(FALSE
);
189 DPRINT("RC %d\n", ObGetReferenceCount(Process
));
190 return(STATUS_SUCCESS
);
193 NTSTATUS STDCALL
NtTerminateProcess(IN HANDLE ProcessHandle
,
194 IN NTSTATUS ExitStatus
)
199 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
200 ProcessHandle
, ExitStatus
);
202 Status
= ObReferenceObjectByHandle(ProcessHandle
,
208 if (!NT_SUCCESS(Status
))
213 PiTerminateProcess(Process
, ExitStatus
);
214 if (PsGetCurrentThread()->ThreadsProcess
== Process
)
216 ObDereferenceObject(Process
);
217 PsTerminateCurrentThread(ExitStatus
);
219 ObDereferenceObject(Process
);
220 return(STATUS_SUCCESS
);
224 NTSTATUS STDCALL
NtTerminateThread(IN HANDLE ThreadHandle
,
225 IN NTSTATUS ExitStatus
)
230 Status
= ObReferenceObjectByHandle(ThreadHandle
,
236 if (Status
!= STATUS_SUCCESS
)
241 ObDereferenceObject(Thread
);
243 if (Thread
== PsGetCurrentThread())
245 PsTerminateCurrentThread(ExitStatus
);
249 PsTerminateOtherThread(Thread
, ExitStatus
);
251 return(STATUS_SUCCESS
);
255 NTSTATUS
PsTerminateSystemThread(NTSTATUS ExitStatus
)
257 * FUNCTION: Terminates the current thread
259 * ExitStatus = Status to pass to the creater
263 PsTerminateCurrentThread(ExitStatus
);
264 return(STATUS_SUCCESS
);
267 NTSTATUS STDCALL
NtCallTerminatePorts(PETHREAD Thread
)
270 PLIST_ENTRY current_entry
;
271 PEPORT_TERMINATION_REQUEST current
;
273 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
274 while ((current_entry
= RemoveHeadList(&Thread
->TerminationPortList
)) !=
275 &Thread
->TerminationPortList
);
277 current
= CONTAINING_RECORD(current_entry
,
278 EPORT_TERMINATION_REQUEST
,
280 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
281 LpcSendTerminationPort(current
->Port
,
283 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
285 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
286 return(STATUS_SUCCESS
);
289 NTSTATUS STDCALL
NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle
)
292 PEPORT_TERMINATION_REQUEST Request
;
293 PEPORT TerminationPort
;
297 Status
= ObReferenceObjectByHandle(TerminationPortHandle
,
301 (PVOID
*)&TerminationPort
,
303 if (!NT_SUCCESS(Status
))
308 Request
= ExAllocatePool(NonPagedPool
, sizeof(Request
));
309 Request
->Port
= TerminationPort
;
310 Thread
= PsGetCurrentThread();
311 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
312 InsertTailList(&Thread
->TerminationPortList
, &Request
->ThreadListEntry
);
313 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
315 return(STATUS_SUCCESS
);