a1149ce1f67aa198f4b8cbab4c9c68e30ba527f2
[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 #include <internal/pool.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* GLOBALS *******************************************************************/
25
26 extern ULONG PiNrThreads;
27 extern ULONG PiNrRunnableThreads;
28 extern KSPIN_LOCK PiThreadListLock;
29 extern LIST_ENTRY PiThreadListHead;
30 extern KSPIN_LOCK PiApcLock;
31
32 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
33
34 #define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C')
35
36 /* FUNCTIONS *****************************************************************/
37
38 VOID
39 PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus)
40 {
41 KIRQL oldlvl;
42 PLIST_ENTRY current_entry;
43 PETHREAD current;
44
45 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
46 Process, ExitStatus);
47
48 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
49
50 current_entry = Process->ThreadListHead.Flink;
51 while (current_entry != &Process->ThreadListHead)
52 {
53 current = CONTAINING_RECORD(current_entry, ETHREAD,
54 Tcb.ProcessThreadListEntry);
55 if (current != PsGetCurrentThread() &&
56 current->DeadThread == 0)
57 {
58 DPRINT("Terminating %x, current thread: %x, "
59 "thread's process: %x\n", current, PsGetCurrentThread(),
60 current->ThreadsProcess);
61 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
62 PsTerminateOtherThread(current, ExitStatus);
63 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
64 current_entry = Process->ThreadListHead.Flink;
65 }
66 else
67 {
68 current_entry = current_entry->Flink;
69 }
70 }
71 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
72 DPRINT("Finished PiTerminateProcessThreads()\n");
73 }
74
75 VOID
76 PsReapThreads(VOID)
77 {
78 PLIST_ENTRY current_entry;
79 PETHREAD current;
80 KIRQL oldIrql;
81
82 // DPRINT1("PsReapThreads()\n");
83
84 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
85
86 current_entry = PiThreadListHead.Flink;
87
88 while (current_entry != &PiThreadListHead)
89 {
90 current = CONTAINING_RECORD(current_entry, ETHREAD,
91 Tcb.ThreadListEntry);
92
93 current_entry = current_entry->Flink;
94
95 if (current->Tcb.State == THREAD_STATE_TERMINATED_1)
96 {
97 PEPROCESS Process = current->ThreadsProcess;
98 NTSTATUS Status = current->ExitStatus;
99
100 DPRINT("PsProcessType %x\n", PsProcessType);
101 DPRINT("Reaping thread %x\n", current);
102 DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
103 current->Tcb.State = THREAD_STATE_TERMINATED_2;
104 RemoveEntryList(&current->Tcb.ProcessThreadListEntry);
105 if (IsListEmpty(&Process->ThreadListHead))
106 {
107 DPRINT("Last thread terminated, terminating process\n");
108 KeReleaseSpinLock( &PiThreadListLock, oldIrql );
109 PiTerminateProcess(Process, Status);
110 KeAcquireSpinLock( &PiThreadListLock, &oldIrql );
111 }
112 DPRINT("Ref count %d\n", ObGetReferenceCount(Process));
113 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
114 ObDereferenceObject(current);
115 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
116 current_entry = PiThreadListHead.Flink;
117 }
118 }
119 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
120 }
121
122 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus)
123 /*
124 * FUNCTION: Terminates the current thread
125 */
126 {
127 KIRQL oldIrql;
128 PETHREAD CurrentThread;
129
130 CurrentThread = PsGetCurrentThread();
131
132 DPRINT("terminating %x\n",CurrentThread);
133 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
134
135 CurrentThread->ExitStatus = ExitStatus;
136 KeCancelTimer(&KeGetCurrentThread()->Timer);
137 KeAcquireDispatcherDatabaseLock(FALSE);
138 CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
139 KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
140 KeReleaseDispatcherDatabaseLock(FALSE);
141
142 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
143 KeBugCheck(0);
144 }
145
146 VOID
147 PiTerminateThreadRundownRoutine(PKAPC Apc)
148 {
149 ExFreePool(Apc);
150 }
151
152 VOID
153 PiTerminateThreadKernelRoutine(PKAPC Apc,
154 PKNORMAL_ROUTINE* NormalRoutine,
155 PVOID* NormalContext,
156 PVOID* SystemArgument1,
157 PVOID* SystemArguemnt2)
158 {
159 ExFreePool(Apc);
160 }
161
162 VOID
163 PiTerminateThreadNormalRoutine(PVOID NormalContext,
164 PVOID SystemArgument1,
165 PVOID SystemArgument2)
166 {
167 PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus);
168 }
169
170 VOID
171 PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus)
172 /*
173 * FUNCTION: Terminate a thread when calling from another thread's context
174 * NOTES: This function must be called with PiThreadListLock held
175 */
176 {
177 PKAPC Apc;
178
179 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
180 Thread, ExitStatus);
181
182 Thread->DeadThread = 1;
183 Thread->ExitStatus = ExitStatus;
184 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
185 KeInitializeApc(Apc,
186 &Thread->Tcb,
187 0,
188 PiTerminateThreadKernelRoutine,
189 PiTerminateThreadRundownRoutine,
190 PiTerminateThreadNormalRoutine,
191 KernelMode,
192 NULL);
193 KeInsertQueueApc(Apc,
194 NULL,
195 NULL,
196 KernelMode);
197 }
198
199 NTSTATUS STDCALL
200 PiTerminateProcess(PEPROCESS Process, NTSTATUS ExitStatus)
201 {
202 DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) RC %d HC %d\n",
203 Process, ExitStatus, ObGetReferenceCount(Process),
204 ObGetHandleCount(Process));
205
206 if (InterlockedExchange((PLONG)&Process->Pcb.State,
207 PROCESS_STATE_TERMINATED) ==
208 PROCESS_STATE_TERMINATED)
209 {
210 return(STATUS_SUCCESS);
211 }
212 KeAttachProcess( Process );
213 ObCloseAllHandles(Process);
214 KeDetachProcess();
215 KeAcquireDispatcherDatabaseLock(FALSE);
216 Process->Pcb.DispatcherHeader.SignalState = TRUE;
217 KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
218 KeReleaseDispatcherDatabaseLock(FALSE);
219 return(STATUS_SUCCESS);
220 }
221
222 NTSTATUS STDCALL NtTerminateProcess(IN HANDLE ProcessHandle,
223 IN NTSTATUS ExitStatus)
224 {
225 NTSTATUS Status;
226 PEPROCESS Process;
227
228 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
229 ProcessHandle, ExitStatus);
230
231 Status = ObReferenceObjectByHandle(ProcessHandle,
232 PROCESS_TERMINATE,
233 PsProcessType,
234 UserMode,
235 (PVOID*)&Process,
236 NULL);
237 if (!NT_SUCCESS(Status))
238 {
239 return(Status);
240 }
241
242 PiTerminateProcessThreads(Process, ExitStatus);
243 if (PsGetCurrentThread()->ThreadsProcess == Process)
244 {
245 ObDereferenceObject(Process);
246 PsTerminateCurrentThread(ExitStatus);
247 }
248 ObDereferenceObject(Process);
249 return(STATUS_SUCCESS);
250 }
251
252
253 NTSTATUS STDCALL NtTerminateThread(IN HANDLE ThreadHandle,
254 IN NTSTATUS ExitStatus)
255 {
256 PETHREAD Thread;
257 NTSTATUS Status;
258
259 Status = ObReferenceObjectByHandle(ThreadHandle,
260 THREAD_TERMINATE,
261 PsThreadType,
262 UserMode,
263 (PVOID*)&Thread,
264 NULL);
265 if (Status != STATUS_SUCCESS)
266 {
267 return(Status);
268 }
269
270 ObDereferenceObject(Thread);
271
272 if (Thread == PsGetCurrentThread())
273 {
274 PsTerminateCurrentThread(ExitStatus);
275 }
276 else
277 {
278 PsTerminateOtherThread(Thread, ExitStatus);
279 }
280 return(STATUS_SUCCESS);
281 }
282
283
284 NTSTATUS STDCALL PsTerminateSystemThread(NTSTATUS ExitStatus)
285 /*
286 * FUNCTION: Terminates the current thread
287 * ARGUMENTS:
288 * ExitStatus = Status to pass to the creater
289 * RETURNS: Doesn't
290 */
291 {
292 PsTerminateCurrentThread(ExitStatus);
293 return(STATUS_SUCCESS);
294 }
295
296 NTSTATUS STDCALL
297 NtCallTerminatePorts(PETHREAD Thread)
298 {
299 KIRQL oldIrql;
300 PLIST_ENTRY current_entry;
301 PEPORT_TERMINATION_REQUEST current;
302
303 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
304 while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
305 &Thread->TerminationPortList);
306 {
307 current = CONTAINING_RECORD(current_entry,
308 EPORT_TERMINATION_REQUEST,
309 ThreadListEntry);
310 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
311 LpcSendTerminationPort(current->Port,
312 Thread->CreateTime);
313 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
314 }
315 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
316 return(STATUS_SUCCESS);
317 }
318
319 NTSTATUS STDCALL
320 NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
321 {
322 NTSTATUS Status;
323 PEPORT_TERMINATION_REQUEST Request;
324 PEPORT TerminationPort;
325 KIRQL oldIrql;
326 PETHREAD Thread;
327
328 Status = ObReferenceObjectByHandle(TerminationPortHandle,
329 PORT_ALL_ACCESS,
330 ExPortType,
331 UserMode,
332 (PVOID*)&TerminationPort,
333 NULL);
334 if (!NT_SUCCESS(Status))
335 {
336 return(Status);
337 }
338
339 Request = ExAllocatePool(NonPagedPool, sizeof(Request));
340 Request->Port = TerminationPort;
341 Thread = PsGetCurrentThread();
342 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
343 InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
344 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
345
346 return(STATUS_SUCCESS);
347 }