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