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)
12 /* INCLUDES *****************************************************************/
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>
23 #include <internal/debug.h>
25 /* GLOBALS *******************************************************************/
27 extern ULONG PiNrThreads;
28 extern ULONG PiNrRunnableThreads;
29 extern KSPIN_LOCK PiThreadListLock;
30 extern LIST_ENTRY PiThreadListHead;
31 extern KSPIN_LOCK PiApcLock;
33 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
35 #define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C')
37 /* FUNCTIONS *****************************************************************/
40 PiTerminateProcessThreads(PEPROCESS Process,
44 PLIST_ENTRY current_entry;
47 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
50 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
52 current_entry = Process->ThreadListHead.Flink;
53 while (current_entry != &Process->ThreadListHead)
55 current = CONTAINING_RECORD(current_entry, ETHREAD,
56 Tcb.ProcessThreadListEntry);
57 if (current != PsGetCurrentThread() &&
58 current->DeadThread == 0)
60 DPRINT("Terminating %x, current thread: %x, "
61 "thread's process: %x\n", current, PsGetCurrentThread(),
62 current->ThreadsProcess);
63 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
64 PsTerminateOtherThread(current, ExitStatus);
65 KeAcquireSpinLock(&PiThreadListLock, &oldlvl);
66 current_entry = Process->ThreadListHead.Flink;
70 current_entry = current_entry->Flink;
73 KeReleaseSpinLock(&PiThreadListLock, oldlvl);
74 DPRINT("Finished PiTerminateProcessThreads()\n");
80 PLIST_ENTRY current_entry;
84 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
86 current_entry = PiThreadListHead.Flink;
88 while (current_entry != &PiThreadListHead)
90 current = CONTAINING_RECORD(current_entry, ETHREAD,
93 current_entry = current_entry->Flink;
95 if (current->Tcb.State == THREAD_STATE_TERMINATED_1)
97 PEPROCESS Process = current->ThreadsProcess;
98 NTSTATUS Status = current->ExitStatus;
101 PiNrThreadsAwaitingReaping--;
102 current->Tcb.State = THREAD_STATE_TERMINATED_2;
103 RemoveEntryList(¤t->Tcb.ProcessThreadListEntry);
104 Last = IsListEmpty(&Process->ThreadListHead);
105 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
109 PiTerminateProcess(Process, Status);
113 if (current->Tcb.Teb)
115 /* If this is not the last thread for the process than free the memory
116 from user stack and teb. */
120 PVOID DeallocationStack;
121 HANDLE ProcessHandle;
122 Status = ObCreateHandle(PsGetCurrentProcess(), Process, PROCESS_ALL_ACCESS, FALSE, &ProcessHandle);
123 if (!NT_SUCCESS(Status))
125 DPRINT1("ObCreateHandle failed, status = %x\n", Status);
128 Offset = FIELD_OFFSET(TEB, DeallocationStack);
130 NtReadVirtualMemory(ProcessHandle, (PVOID)current->Tcb.Teb + Offset,
131 (PVOID)&DeallocationStack, sizeof(PVOID), &Length);
132 if (DeallocationStack && Length == sizeof(PVOID))
134 NtFreeVirtualMemory(ProcessHandle, &DeallocationStack, &Length, MEM_RELEASE);
137 NtFreeVirtualMemory(ProcessHandle, (PVOID*)¤t->Tcb.Teb, &Length, MEM_RELEASE);
138 NtClose(ProcessHandle);
141 ObDereferenceObject(current);
142 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
143 current_entry = PiThreadListHead.Flink;
146 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
150 PsTerminateCurrentThread(NTSTATUS ExitStatus)
152 * FUNCTION: Terminates the current thread
156 PETHREAD CurrentThread;
158 PLIST_ENTRY current_entry;
161 CurrentThread = PsGetCurrentThread();
163 DPRINT("terminating %x\n",CurrentThread);
164 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
166 CurrentThread->ExitStatus = ExitStatus;
167 Thread = KeGetCurrentThread();
168 KeCancelTimer(&Thread->Timer);
169 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
171 /* abandon all owned mutants */
172 current_entry = Thread->MutantListHead.Flink;
173 while (current_entry != &Thread->MutantListHead)
175 Mutant = CONTAINING_RECORD(current_entry, KMUTANT,
177 KeReleaseMutant(Mutant,
181 current_entry = Thread->MutantListHead.Flink;
184 KeAcquireDispatcherDatabaseLock(FALSE);
185 CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
186 KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
187 KeReleaseDispatcherDatabaseLock(FALSE);
189 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
190 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
195 PiTerminateThreadRundownRoutine(PKAPC Apc)
201 PiTerminateThreadKernelRoutine(PKAPC Apc,
202 PKNORMAL_ROUTINE* NormalRoutine,
203 PVOID* NormalContext,
204 PVOID* SystemArgument1,
205 PVOID* SystemArguemnt2)
211 PiTerminateThreadNormalRoutine(PVOID NormalContext,
212 PVOID SystemArgument1,
213 PVOID SystemArgument2)
215 PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus);
219 PsTerminateOtherThread(PETHREAD Thread,
222 * FUNCTION: Terminate a thread when calling from another thread's context
223 * NOTES: This function must be called with PiThreadListLock held
228 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
231 Thread->DeadThread = 1;
232 Thread->ExitStatus = ExitStatus;
233 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
237 PiTerminateThreadKernelRoutine,
238 PiTerminateThreadRundownRoutine,
239 PiTerminateThreadNormalRoutine,
242 KeInsertQueueApc(Apc,
249 PiTerminateProcess(PEPROCESS Process,
252 DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n",
253 Process, ExitStatus, ObGetObjectPointerCount(Process),
254 ObGetObjectHandleCount(Process));
256 ObReferenceObject(Process);
257 if (InterlockedExchange((PLONG)&Process->Pcb.State,
258 PROCESS_STATE_TERMINATED) ==
259 PROCESS_STATE_TERMINATED)
261 ObDereferenceObject(Process);
262 return(STATUS_SUCCESS);
264 KeAttachProcess( Process );
265 ObCloseAllHandles(Process);
267 KeAcquireDispatcherDatabaseLock(FALSE);
268 Process->Pcb.DispatcherHeader.SignalState = TRUE;
269 KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
270 KeReleaseDispatcherDatabaseLock(FALSE);
271 ObDereferenceObject(Process);
272 return(STATUS_SUCCESS);
276 NtTerminateProcess(IN HANDLE ProcessHandle,
277 IN NTSTATUS ExitStatus)
282 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
283 ProcessHandle, ExitStatus);
285 Status = ObReferenceObjectByHandle(ProcessHandle,
291 if (!NT_SUCCESS(Status))
295 Process->ExitStatus = ExitStatus;
296 PiTerminateProcessThreads(Process, ExitStatus);
297 if (PsGetCurrentThread()->ThreadsProcess == Process)
299 ObDereferenceObject(Process);
300 PsTerminateCurrentThread(ExitStatus);
302 ObDereferenceObject(Process);
303 return(STATUS_SUCCESS);
308 NtTerminateThread(IN HANDLE ThreadHandle,
309 IN NTSTATUS ExitStatus)
314 Status = ObReferenceObjectByHandle(ThreadHandle,
320 if (Status != STATUS_SUCCESS)
325 ObDereferenceObject(Thread);
327 if (Thread == PsGetCurrentThread())
329 PsTerminateCurrentThread(ExitStatus);
333 PsTerminateOtherThread(Thread, ExitStatus);
335 return(STATUS_SUCCESS);
340 PsTerminateSystemThread(NTSTATUS ExitStatus)
342 * FUNCTION: Terminates the current thread
344 * ExitStatus = Status to pass to the creater
348 PsTerminateCurrentThread(ExitStatus);
349 return(STATUS_SUCCESS);
353 NtCallTerminatePorts(PETHREAD Thread)
356 PLIST_ENTRY current_entry;
357 PEPORT_TERMINATION_REQUEST current;
359 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
360 while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
361 &Thread->TerminationPortList);
363 current = CONTAINING_RECORD(current_entry,
364 EPORT_TERMINATION_REQUEST,
366 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
367 LpcSendTerminationPort(current->Port,
369 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
371 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
372 return(STATUS_SUCCESS);
376 NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
379 PEPORT_TERMINATION_REQUEST Request;
380 PEPORT TerminationPort;
384 Status = ObReferenceObjectByHandle(TerminationPortHandle,
388 (PVOID*)&TerminationPort,
390 if (!NT_SUCCESS(Status))
395 Request = ExAllocatePool(NonPagedPool, sizeof(EPORT_TERMINATION_REQUEST));
396 Request->Port = TerminationPort;
397 Thread = PsGetCurrentThread();
398 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
399 InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
400 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
402 return(STATUS_SUCCESS);