1 /* $Id: kill.c,v 1.79 2004/10/03 21:03:03 gvg Exp $
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 *****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
20 extern KSPIN_LOCK PiThreadLock
;
21 extern KSPIN_LOCK PiApcLock
;
23 VOID
PsTerminateCurrentThread(NTSTATUS ExitStatus
);
25 #define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C')
27 LIST_ENTRY ThreadsToReapHead
;
29 /* FUNCTIONS *****************************************************************/
32 PsInitializeThreadReaper(VOID
)
34 InitializeListHead(&ThreadsToReapHead
);
42 PLIST_ENTRY ListEntry
;
44 KeAcquireSpinLock(&PiThreadLock
, &oldlvl
);
45 while((ListEntry
= RemoveHeadList(&ThreadsToReapHead
)) != &ThreadsToReapHead
)
47 PiNrThreadsAwaitingReaping
--;
48 KeReleaseSpinLock(&PiThreadLock
, oldlvl
);
50 Thread
= CONTAINING_RECORD(ListEntry
, ETHREAD
, TerminationPortList
);
52 ObDereferenceObject(Thread
);
54 KeAcquireSpinLock(&PiThreadLock
, &oldlvl
);
56 KeReleaseSpinLock(&PiThreadLock
, oldlvl
);
60 PsQueueThreadReap(PETHREAD Thread
)
62 InsertTailList(&ThreadsToReapHead
, &Thread
->TerminationPortList
);
63 PiNrThreadsAwaitingReaping
++;
67 PiTerminateProcessThreads(PEPROCESS Process
,
71 PLIST_ENTRY current_entry
;
72 PETHREAD current
, CurrentThread
= PsGetCurrentThread();
74 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
77 KeAcquireSpinLock(&PiThreadLock
, &oldlvl
);
79 current_entry
= Process
->ThreadListHead
.Flink
;
80 while (current_entry
!= &Process
->ThreadListHead
)
82 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
84 if (current
!= CurrentThread
&& current
->HasTerminated
== 0)
86 DPRINT("Terminating %x, current thread: %x, "
87 "thread's process: %x\n", current
, PsGetCurrentThread(),
88 current
->ThreadsProcess
);
89 KeReleaseSpinLock(&PiThreadLock
, oldlvl
);
90 PsTerminateOtherThread(current
, ExitStatus
);
91 KeAcquireSpinLock(&PiThreadLock
, &oldlvl
);
92 current_entry
= Process
->ThreadListHead
.Flink
;
96 current_entry
= current_entry
->Flink
;
99 KeReleaseSpinLock(&PiThreadLock
, oldlvl
);
100 DPRINT("Finished PiTerminateProcessThreads()\n");
104 PsTerminateCurrentThread(NTSTATUS ExitStatus
)
106 * FUNCTION: Terminates the current thread
110 PETHREAD CurrentThread
;
111 PLIST_ENTRY current_entry
;
114 PEPROCESS CurrentProcess
;
115 SIZE_T Length
= PAGE_SIZE
;
118 KeLowerIrql(PASSIVE_LEVEL
);
120 CurrentThread
= PsGetCurrentThread();
121 CurrentProcess
= CurrentThread
->ThreadsProcess
;
123 /* Can't terminate a thread if it attached another process */
124 if (AttachedApcEnvironment
== CurrentThread
->Tcb
.ApcStateIndex
)
126 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
, (ULONG
) CurrentProcess
,
127 (ULONG
) CurrentThread
->Tcb
.ApcState
.Process
,
128 (ULONG
) CurrentThread
->Tcb
.ApcStateIndex
,
129 (ULONG
) CurrentThread
);
132 KeAcquireSpinLock(&PiThreadLock
, &oldIrql
);
134 DPRINT("terminating %x\n",CurrentThread
);
136 CurrentThread
->ExitStatus
= ExitStatus
;
137 KeQuerySystemTime((PLARGE_INTEGER
)&CurrentThread
->ExitTime
);
138 KeCancelTimer(&CurrentThread
->Tcb
.Timer
);
140 /* Remove the thread from the thread list of its process */
141 RemoveEntryList(&CurrentThread
->ThreadListEntry
);
142 Last
= IsListEmpty(&CurrentProcess
->ThreadListHead
);
144 KeReleaseSpinLock(&PiThreadLock
, oldIrql
);
146 /* Notify subsystems of the thread termination */
147 PspRunCreateThreadNotifyRoutines(CurrentThread
, FALSE
);
148 PsTerminateWin32Thread(CurrentThread
);
151 if(CurrentThread
->Tcb
.Teb
)
153 DPRINT("Decommit teb at %p\n", CurrentThread
->Tcb
.Teb
);
154 ExAcquireFastMutex(&CurrentProcess
->TebLock
);
155 TebBlock
= MM_ROUND_DOWN(CurrentThread
->Tcb
.Teb
, MM_VIRTMEM_GRANULARITY
);
156 ZwFreeVirtualMemory(NtCurrentProcess(),
157 (PVOID
*)&CurrentThread
->Tcb
.Teb
,
160 DPRINT("teb %p, TebBlock %p\n", CurrentThread
->Tcb
.Teb
, TebBlock
);
161 if (TebBlock
!= CurrentProcess
->TebBlock
||
162 CurrentProcess
->TebBlock
== CurrentProcess
->TebLastAllocated
)
164 MmLockAddressSpace(&CurrentProcess
->AddressSpace
);
165 MmReleaseMemoryAreaIfDecommitted(CurrentProcess
, &CurrentProcess
->AddressSpace
, TebBlock
);
166 MmUnlockAddressSpace(&CurrentProcess
->AddressSpace
);
168 ExReleaseFastMutex(&CurrentProcess
->TebLock
);
171 /* abandon all owned mutants */
172 current_entry
= CurrentThread
->Tcb
.MutantListHead
.Flink
;
173 while (current_entry
!= &CurrentThread
->Tcb
.MutantListHead
)
175 Mutant
= CONTAINING_RECORD(current_entry
, KMUTANT
,
177 KeReleaseMutant(Mutant
,
181 current_entry
= CurrentThread
->Tcb
.MutantListHead
.Flink
;
184 oldIrql
= KeAcquireDispatcherDatabaseLock();
185 CurrentThread
->Tcb
.DispatcherHeader
.SignalState
= TRUE
;
186 KeDispatcherObjectWake(&CurrentThread
->Tcb
.DispatcherHeader
);
187 KeReleaseDispatcherDatabaseLock (oldIrql
);
189 /* The last thread shall close the door on exit */
192 PspRunCreateProcessNotifyRoutines(CurrentProcess
, FALSE
);
193 PsTerminateWin32Process(CurrentProcess
);
194 PiTerminateProcess(CurrentProcess
, ExitStatus
);
197 KeAcquireSpinLock(&PiThreadLock
, &oldIrql
);
199 #ifdef _ENABLE_THRDEVTPAIR
200 ExpSwapThreadEventPair(CurrentThread
, NULL
); /* Release the associated eventpair object, if there was one */
201 #endif /* _ENABLE_THRDEVTPAIR */
202 KeRemoveAllWaitsThread (CurrentThread
, STATUS_UNSUCCESSFUL
, FALSE
);
204 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1
);
205 DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread
, PsGetCurrentThread());
210 PiTerminateThreadRundownRoutine(PKAPC Apc
)
216 PiTerminateThreadKernelRoutine(PKAPC Apc
,
217 PKNORMAL_ROUTINE
* NormalRoutine
,
218 PVOID
* NormalContext
,
219 PVOID
* SystemArgument1
,
220 PVOID
* SystemArguemnt2
)
226 PiTerminateThreadNormalRoutine(PVOID NormalContext
,
227 PVOID SystemArgument1
,
228 PVOID SystemArgument2
)
230 PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus
);
234 PsTerminateOtherThread(PETHREAD Thread
,
237 * FUNCTION: Terminate a thread when calling from another thread's context
238 * NOTES: This function must be called with PiThreadLock held
244 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
247 Thread
->HasTerminated
= TRUE
;
248 Thread
->ExitStatus
= ExitStatus
;
249 Apc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG_TERMINATE_APC
);
252 OriginalApcEnvironment
,
253 PiTerminateThreadKernelRoutine
,
254 PiTerminateThreadRundownRoutine
,
255 PiTerminateThreadNormalRoutine
,
258 KeInsertQueueApc(Apc
,
262 if (THREAD_STATE_BLOCKED
== Thread
->Tcb
.State
&& UserMode
== Thread
->Tcb
.WaitMode
)
264 DPRINT("Unblocking thread\n");
265 Status
= STATUS_THREAD_IS_TERMINATING
;
266 KeRemoveAllWaitsThread(Thread
, Status
, TRUE
);
271 PiTerminateProcess(PEPROCESS Process
,
275 PEPROCESS CurrentProcess
;
277 DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n",
278 Process
, ExitStatus
, ObGetObjectPointerCount(Process
),
279 ObGetObjectHandleCount(Process
));
281 ObReferenceObject(Process
);
282 if (InterlockedExchange((PLONG
)&Process
->Pcb
.State
,
283 PROCESS_STATE_TERMINATED
) ==
284 PROCESS_STATE_TERMINATED
)
286 ObDereferenceObject(Process
);
287 return(STATUS_SUCCESS
);
289 CurrentProcess
= PsGetCurrentProcess();
290 if (Process
!= CurrentProcess
)
292 KeAttachProcess( Process
);
294 ObCloseAllHandles(Process
);
295 if (Process
!= CurrentProcess
)
299 OldIrql
= KeAcquireDispatcherDatabaseLock ();
300 Process
->Pcb
.DispatcherHeader
.SignalState
= TRUE
;
301 KeDispatcherObjectWake(&Process
->Pcb
.DispatcherHeader
);
302 KeReleaseDispatcherDatabaseLock (OldIrql
);
303 ObDereferenceObject(Process
);
304 return(STATUS_SUCCESS
);
308 NtTerminateProcess(IN HANDLE ProcessHandle
,
309 IN NTSTATUS ExitStatus
)
314 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
315 ProcessHandle
, ExitStatus
);
317 Status
= ObReferenceObjectByHandle(ProcessHandle
,
320 KeGetCurrentThread()->PreviousMode
,
323 if (!NT_SUCCESS(Status
))
327 Process
->ExitStatus
= ExitStatus
;
328 PiTerminateProcessThreads(Process
, ExitStatus
);
329 if (PsGetCurrentThread()->ThreadsProcess
== Process
)
331 ObDereferenceObject(Process
);
332 PsTerminateCurrentThread(ExitStatus
);
334 * We should never get here!
336 return(STATUS_SUCCESS
);
338 ObDereferenceObject(Process
);
339 return(STATUS_SUCCESS
);
344 NtTerminateThread(IN HANDLE ThreadHandle
,
345 IN NTSTATUS ExitStatus
)
350 Status
= ObReferenceObjectByHandle(ThreadHandle
,
353 KeGetCurrentThread()->PreviousMode
,
356 if (Status
!= STATUS_SUCCESS
)
361 if (Thread
== PsGetCurrentThread())
363 /* dereference the thread object before we kill our thread */
364 ObDereferenceObject(Thread
);
365 PsTerminateCurrentThread(ExitStatus
);
367 * We should never get here!
372 PsTerminateOtherThread(Thread
, ExitStatus
);
373 ObDereferenceObject(Thread
);
375 return(STATUS_SUCCESS
);
383 PsTerminateSystemThread(NTSTATUS ExitStatus
)
385 * FUNCTION: Terminates the current thread
387 * ExitStatus = Status to pass to the creater
391 PsTerminateCurrentThread(ExitStatus
);
392 return(STATUS_SUCCESS
);
396 NtCallTerminatePorts(PETHREAD Thread
)
399 PLIST_ENTRY current_entry
;
400 PEPORT_TERMINATION_REQUEST current
;
402 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
403 while ((current_entry
= RemoveHeadList(&Thread
->TerminationPortList
)) !=
404 &Thread
->TerminationPortList
);
406 current
= CONTAINING_RECORD(current_entry
,
407 EPORT_TERMINATION_REQUEST
,
409 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
410 LpcSendTerminationPort(current
->Port
,
413 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
415 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
416 return(STATUS_SUCCESS
);
420 NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle
)
423 PEPORT_TERMINATION_REQUEST Request
;
424 PEPORT TerminationPort
;
428 Status
= ObReferenceObjectByHandle(TerminationPortHandle
,
431 KeGetCurrentThread()->PreviousMode
,
432 (PVOID
*)&TerminationPort
,
434 if (!NT_SUCCESS(Status
))
439 Request
= ExAllocatePool(NonPagedPool
, sizeof(EPORT_TERMINATION_REQUEST
));
442 Request
->Port
= TerminationPort
;
443 Thread
= PsGetCurrentThread();
444 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
445 InsertTailList(&Thread
->TerminationPortList
, &Request
->ThreadListEntry
);
446 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
448 return(STATUS_SUCCESS
);
452 ObDereferenceObject(TerminationPort
);
453 return(STATUS_INSUFFICIENT_RESOURCES
);