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;
162 DPRINT("terminating %x\n",CurrentThread);
163 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
165 CurrentThread = PsGetCurrentThread();
167 CurrentThread->ExitStatus = ExitStatus;
168 Thread = KeGetCurrentThread();
169 KeCancelTimer(&Thread->Timer);
170 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
172 /* abandon all owned mutants */
173 current_entry = Thread->MutantListHead.Flink;
174 while (current_entry != &Thread->MutantListHead)
176 Mutant = CONTAINING_RECORD(current_entry, KMUTANT,
178 KeReleaseMutant(Mutant,
182 current_entry = Thread->MutantListHead.Flink;
185 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
187 KeAcquireDispatcherDatabaseLock(FALSE);
188 CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
189 KeDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
190 KeReleaseDispatcherDatabaseLockAtDpcLevel(FALSE);
192 KeRemoveAllWaitsThread (CurrentThread, STATUS_UNSUCCESSFUL, FALSE);
194 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
195 DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
200 PiTerminateThreadRundownRoutine(PKAPC Apc)
206 PiTerminateThreadKernelRoutine(PKAPC Apc,
207 PKNORMAL_ROUTINE* NormalRoutine,
208 PVOID* NormalContext,
209 PVOID* SystemArgument1,
210 PVOID* SystemArguemnt2)
216 PiTerminateThreadNormalRoutine(PVOID NormalContext,
217 PVOID SystemArgument1,
218 PVOID SystemArgument2)
220 PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus);
224 PsTerminateOtherThread(PETHREAD Thread,
227 * FUNCTION: Terminate a thread when calling from another thread's context
228 * NOTES: This function must be called with PiThreadListLock held
234 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
237 Thread->DeadThread = 1;
238 Thread->ExitStatus = ExitStatus;
239 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
242 OriginalApcEnvironment,
243 PiTerminateThreadKernelRoutine,
244 PiTerminateThreadRundownRoutine,
245 PiTerminateThreadNormalRoutine,
248 KeInsertQueueApc(Apc,
252 if (THREAD_STATE_BLOCKED == Thread->Tcb.State && UserMode == Thread->Tcb.WaitMode)
254 DPRINT("Unblocking thread\n");
255 Status = STATUS_THREAD_IS_TERMINATING;
256 PsUnblockThread(Thread, &Status);
261 PiTerminateProcess(PEPROCESS Process,
264 DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n",
265 Process, ExitStatus, ObGetObjectPointerCount(Process),
266 ObGetObjectHandleCount(Process));
268 ObReferenceObject(Process);
269 if (InterlockedExchange((PLONG)&Process->Pcb.State,
270 PROCESS_STATE_TERMINATED) ==
271 PROCESS_STATE_TERMINATED)
273 ObDereferenceObject(Process);
274 return(STATUS_SUCCESS);
276 KeAttachProcess( Process );
277 ObCloseAllHandles(Process);
279 KeAcquireDispatcherDatabaseLock(FALSE);
280 Process->Pcb.DispatcherHeader.SignalState = TRUE;
281 KeDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
282 KeReleaseDispatcherDatabaseLock(FALSE);
283 ObDereferenceObject(Process);
284 return(STATUS_SUCCESS);
288 NtTerminateProcess(IN HANDLE ProcessHandle,
289 IN NTSTATUS ExitStatus)
294 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
295 ProcessHandle, ExitStatus);
297 Status = ObReferenceObjectByHandle(ProcessHandle,
303 if (!NT_SUCCESS(Status))
307 Process->ExitStatus = ExitStatus;
308 PiTerminateProcessThreads(Process, ExitStatus);
309 if (PsGetCurrentThread()->ThreadsProcess == Process)
311 ObDereferenceObject(Process);
312 PsTerminateCurrentThread(ExitStatus);
314 ObDereferenceObject(Process);
315 return(STATUS_SUCCESS);
320 NtTerminateThread(IN HANDLE ThreadHandle,
321 IN NTSTATUS ExitStatus)
326 Status = ObReferenceObjectByHandle(ThreadHandle,
332 if (Status != STATUS_SUCCESS)
337 ObDereferenceObject(Thread);
339 if (Thread == PsGetCurrentThread())
341 PsTerminateCurrentThread(ExitStatus);
345 PsTerminateOtherThread(Thread, ExitStatus);
347 return(STATUS_SUCCESS);
355 PsTerminateSystemThread(NTSTATUS ExitStatus)
357 * FUNCTION: Terminates the current thread
359 * ExitStatus = Status to pass to the creater
363 PsTerminateCurrentThread(ExitStatus);
364 return(STATUS_SUCCESS);
368 NtCallTerminatePorts(PETHREAD Thread)
371 PLIST_ENTRY current_entry;
372 PEPORT_TERMINATION_REQUEST current;
374 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
375 while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
376 &Thread->TerminationPortList);
378 current = CONTAINING_RECORD(current_entry,
379 EPORT_TERMINATION_REQUEST,
381 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
382 LpcSendTerminationPort(current->Port,
384 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
386 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
387 return(STATUS_SUCCESS);
391 NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle)
394 PEPORT_TERMINATION_REQUEST Request;
395 PEPORT TerminationPort;
399 Status = ObReferenceObjectByHandle(TerminationPortHandle,
403 (PVOID*)&TerminationPort,
405 if (!NT_SUCCESS(Status))
410 Request = ExAllocatePool(NonPagedPool, sizeof(EPORT_TERMINATION_REQUEST));
411 Request->Port = TerminationPort;
412 Thread = PsGetCurrentThread();
413 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
414 InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
415 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
417 return(STATUS_SUCCESS);