c6fe783cd7447178eced36d5e5f7255831f25858
[reactos.git] / reactos / ntoskrnl / ps / kill.c
1 /*
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)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 */
10
11 /* INCLUDES *****************************************************************/
12
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>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* GLOBALS *******************************************************************/
24
25 extern ULONG PiNrThreads;
26 extern ULONG PiNrRunnableThreads;
27 extern KSPIN_LOCK PiThreadListLock;
28 extern LIST_ENTRY PiThreadListHead;
29
30 /* FUNCTIONS *****************************************************************/
31
32 VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus)
33 {
34 KIRQL oldlvl;
35 PLIST_ENTRY current_entry;
36 PETHREAD current;
37
38 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
39 Process, ExitStatus);
40
41 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
42
43 current_entry = PiThreadListHead.Flink;
44 while (current_entry != &PiThreadListHead)
45 {
46 current = CONTAINING_RECORD(current_entry,ETHREAD,Tcb.QueueListEntry);
47 if (current->ThreadsProcess == Process &&
48 current != PsGetCurrentThread())
49 {
50 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
51 DPRINT("Terminating %x\n", current);
52 PsTerminateOtherThread(current, ExitStatus);
53 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
54 current_entry = PiThreadListHead.Flink;
55 }
56 current_entry = current_entry->Flink;
57 }
58
59 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
60 DPRINT("Finished PiTerminateProcessThreads()\n");
61 }
62
63 VOID PsReapThreads(VOID)
64 {
65 PLIST_ENTRY current_entry;
66 PETHREAD current;
67 KIRQL oldIrql;
68
69 // DPRINT1("PsReapThreads()\n");
70
71 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
72
73 current_entry = PiThreadListHead.Flink;
74
75 while (current_entry != &PiThreadListHead)
76 {
77 current = CONTAINING_RECORD(current_entry, ETHREAD,
78 Tcb.ThreadListEntry);
79
80 current_entry = current_entry->Flink;
81
82 if (current->Tcb.State == THREAD_STATE_TERMINATED_1)
83 {
84 PEPROCESS Process = current->ThreadsProcess;
85 NTSTATUS Status = current->ExitStatus;
86
87 DPRINT("PsProcessType %x\n", PsProcessType);
88 ObReferenceObjectByPointer(Process,
89 0,
90 PsProcessType,
91 KernelMode);
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(&current->Tcb.ProcessThreadListEntry);
96 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
97 ObDereferenceObject(current);
98 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
99 if (IsListEmpty(&Process->Pcb.ThreadListHead))
100 {
101 /*
102 * TODO: Optimize this so it doesnt jerk the IRQL around so
103 * much :)
104 */
105 DPRINT("Last thread terminated, terminating process\n");
106 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
107 PiTerminateProcess(Process, Status);
108 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
109 }
110 DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
111 ObDereferenceObject(Process);
112 current_entry = PiThreadListHead.Flink;
113 }
114 }
115 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
116 }
117
118 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus)
119 /*
120 * FUNCTION: Terminates the current thread
121 */
122 {
123 KIRQL oldIrql;
124 PETHREAD CurrentThread;
125
126 CurrentThread = PsGetCurrentThread();
127
128 DPRINT("terminating %x\n",CurrentThread);
129 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
130
131 CurrentThread->ExitStatus = ExitStatus;
132 KeAcquireDispatcherDatabaseLock(FALSE);
133 CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
134 KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
135 KeReleaseDispatcherDatabaseLock(FALSE);
136
137 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
138 KeBugCheck(0);
139 }
140
141 VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus)
142 /*
143 * FUNCTION: Terminate a thread when calling from that thread's context
144 */
145 {
146 KIRQL oldIrql;
147
148 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
149 Thread, ExitStatus);
150
151 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
152 if (Thread->Tcb.State == THREAD_STATE_RUNNABLE)
153 {
154 DPRINT("Removing from runnable queue\n");
155 RemoveEntryList(&Thread->Tcb.QueueListEntry);
156 }
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))
164 {
165 DPRINT("Terminating associated process\n");
166 PiTerminateProcess(Thread->ThreadsProcess, ExitStatus);
167 }
168 ObDereferenceObject(Thread);
169 }
170
171 NTSTATUS STDCALL PiTerminateProcess(PEPROCESS Process,
172 NTSTATUS ExitStatus)
173 {
174 DPRINT1("PiTerminateProcess(Process %x, ExitStatus %x) RC %d\n",
175 Process, ExitStatus, ObGetReferenceCount(Process));
176
177 if (Process->Pcb.ProcessState == PROCESS_STATE_TERMINATED)
178 {
179 return(STATUS_SUCCESS);
180 }
181
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);
191 }
192
193 NTSTATUS STDCALL NtTerminateProcess(IN HANDLE ProcessHandle,
194 IN NTSTATUS ExitStatus)
195 {
196 NTSTATUS Status;
197 PEPROCESS Process;
198
199 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
200 ProcessHandle, ExitStatus);
201
202 Status = ObReferenceObjectByHandle(ProcessHandle,
203 PROCESS_TERMINATE,
204 PsProcessType,
205 UserMode,
206 (PVOID*)&Process,
207 NULL);
208 if (!NT_SUCCESS(Status))
209 {
210 return(Status);
211 }
212
213 PiTerminateProcess(Process, ExitStatus);
214 if (PsGetCurrentThread()->ThreadsProcess == Process)
215 {
216 ObDereferenceObject(Process);
217 PsTerminateCurrentThread(ExitStatus);
218 }
219 ObDereferenceObject(Process);
220 return(STATUS_SUCCESS);
221 }
222
223
224 NTSTATUS STDCALL NtTerminateThread(IN HANDLE ThreadHandle,
225 IN NTSTATUS ExitStatus)
226 {
227 PETHREAD Thread;
228 NTSTATUS Status;
229
230 Status = ObReferenceObjectByHandle(ThreadHandle,
231 THREAD_TERMINATE,
232 PsThreadType,
233 UserMode,
234 (PVOID*)&Thread,
235 NULL);
236 if (Status != STATUS_SUCCESS)
237 {
238 return(Status);
239 }
240
241 ObDereferenceObject(Thread);
242
243 if (Thread == PsGetCurrentThread())
244 {
245 PsTerminateCurrentThread(ExitStatus);
246 }
247 else
248 {
249 PsTerminateOtherThread(Thread, ExitStatus);
250 }
251 return(STATUS_SUCCESS);
252 }
253
254
255 NTSTATUS PsTerminateSystemThread(NTSTATUS ExitStatus)
256 /*
257 * FUNCTION: Terminates the current thread
258 * ARGUMENTS:
259 * ExitStatus = Status to pass to the creater
260 * RETURNS: Doesn't
261 */
262 {
263 PsTerminateCurrentThread(ExitStatus);
264 return(STATUS_SUCCESS);
265 }
266
267 NTSTATUS STDCALL NtCallTerminatePorts(PETHREAD Thread)
268 {
269 KIRQL oldIrql;
270 PLIST_ENTRY current_entry;
271 PEPORT_TERMINATION_REQUEST current;
272
273 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
274 while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
275 &Thread->TerminationPortList);
276 {
277 current = CONTAINING_RECORD(current_entry,
278 EPORT_TERMINATION_REQUEST,
279 ThreadListEntry);
280 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
281 LpcSendTerminationPort(current->Port,
282 Thread->CreateTime);
283 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
284 }
285 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
286 return(STATUS_SUCCESS);
287 }
288
289 NTSTATUS STDCALL NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
290 {
291 NTSTATUS Status;
292 PEPORT_TERMINATION_REQUEST Request;
293 PEPORT TerminationPort;
294 KIRQL oldIrql;
295 PETHREAD Thread;
296
297 Status = ObReferenceObjectByHandle(TerminationPortHandle,
298 PORT_ALL_ACCESS,
299 ExPortType,
300 UserMode,
301 (PVOID*)&TerminationPort,
302 NULL);
303 if (!NT_SUCCESS(Status))
304 {
305 return(Status);
306 }
307
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);
314
315 return(STATUS_SUCCESS);
316 }