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