1 /* $Id: kill.c,v 1.75 2004/09/14 18:37:40 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 ULONG PiNrThreads
;
21 extern ULONG PiNrRunnableThreads
;
22 extern KSPIN_LOCK PiThreadListLock
;
23 extern LIST_ENTRY PiThreadListHead
;
24 extern KSPIN_LOCK PiApcLock
;
26 VOID
PsTerminateCurrentThread(NTSTATUS ExitStatus
);
28 #define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C')
30 /* FUNCTIONS *****************************************************************/
33 PiTerminateProcessThreads(PEPROCESS Process
,
37 PLIST_ENTRY current_entry
;
40 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
43 KeAcquireSpinLock(&PiThreadListLock
, &oldlvl
);
45 current_entry
= Process
->ThreadListHead
.Flink
;
46 while (current_entry
!= &Process
->ThreadListHead
)
48 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
49 Tcb
.ProcessThreadListEntry
);
50 if (current
!= PsGetCurrentThread() &&
51 current
->DeadThread
== 0)
53 DPRINT("Terminating %x, current thread: %x, "
54 "thread's process: %x\n", current
, PsGetCurrentThread(),
55 current
->ThreadsProcess
);
56 KeReleaseSpinLock(&PiThreadListLock
, oldlvl
);
57 PsTerminateOtherThread(current
, ExitStatus
);
58 KeAcquireSpinLock(&PiThreadListLock
, &oldlvl
);
59 current_entry
= Process
->ThreadListHead
.Flink
;
63 current_entry
= current_entry
->Flink
;
66 KeReleaseSpinLock(&PiThreadListLock
, oldlvl
);
67 DPRINT("Finished PiTerminateProcessThreads()\n");
73 PLIST_ENTRY current_entry
;
77 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
79 current_entry
= PiThreadListHead
.Flink
;
81 while (current_entry
!= &PiThreadListHead
)
83 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
86 current_entry
= current_entry
->Flink
;
88 if (current
->Tcb
.State
== THREAD_STATE_TERMINATED_1
)
90 PiNrThreadsAwaitingReaping
--;
91 current
->Tcb
.State
= THREAD_STATE_TERMINATED_2
;
94 An unbelievably complex chain of events would cause a system crash
95 if PiThreadListLock was still held when the thread object is about
98 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
99 ObDereferenceObject(current
);
100 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
102 current_entry
= PiThreadListHead
.Flink
;
105 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
109 PsTerminateCurrentThread(NTSTATUS ExitStatus
)
111 * FUNCTION: Terminates the current thread
115 PETHREAD CurrentThread
;
116 PLIST_ENTRY current_entry
;
119 PEPROCESS CurrentProcess
;
120 SIZE_T Length
= PAGE_SIZE
;
122 KeLowerIrql(PASSIVE_LEVEL
);
124 CurrentThread
= PsGetCurrentThread();
125 CurrentProcess
= CurrentThread
->ThreadsProcess
;
127 /* Can't terminate a thread if it attached another process */
128 if (AttachedApcEnvironment
== CurrentThread
->Tcb
.ApcStateIndex
)
130 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
, (ULONG
) CurrentProcess
,
131 (ULONG
) CurrentThread
->Tcb
.ApcState
.Process
,
132 (ULONG
) CurrentThread
->Tcb
.ApcStateIndex
,
133 (ULONG
) CurrentThread
);
136 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
138 DPRINT("terminating %x\n",CurrentThread
);
140 CurrentThread
->ExitStatus
= ExitStatus
;
141 KeQuerySystemTime((PLARGE_INTEGER
)&CurrentThread
->u1
.ExitTime
);
142 KeCancelTimer(&CurrentThread
->Tcb
.Timer
);
144 /* Remove the thread from the thread list of its process */
145 RemoveEntryList(&CurrentThread
->Tcb
.ProcessThreadListEntry
);
146 Last
= IsListEmpty(&CurrentProcess
->ThreadListHead
);
148 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
150 /* Notify subsystems of the thread termination */
151 PspRunCreateThreadNotifyRoutines(CurrentThread
, FALSE
);
152 PsTerminateWin32Thread(CurrentThread
);
155 if(CurrentThread
->Tcb
.Teb
)
159 (PVOID
*)&CurrentThread
->Tcb
.Teb
,
164 /* abandon all owned mutants */
165 current_entry
= CurrentThread
->Tcb
.MutantListHead
.Flink
;
166 while (current_entry
!= &CurrentThread
->Tcb
.MutantListHead
)
168 Mutant
= CONTAINING_RECORD(current_entry
, KMUTANT
,
170 KeReleaseMutant(Mutant
,
174 current_entry
= CurrentThread
->Tcb
.MutantListHead
.Flink
;
177 oldIrql
= KeAcquireDispatcherDatabaseLock();
178 CurrentThread
->Tcb
.DispatcherHeader
.SignalState
= TRUE
;
179 KeDispatcherObjectWake(&CurrentThread
->Tcb
.DispatcherHeader
);
180 KeReleaseDispatcherDatabaseLock (oldIrql
);
182 /* The last thread shall close the door on exit */
185 PspRunCreateProcessNotifyRoutines(CurrentProcess
, FALSE
);
186 PsTerminateWin32Process(CurrentProcess
);
187 PiTerminateProcess(CurrentProcess
, ExitStatus
);
190 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
192 ExpSwapThreadEventPair(CurrentThread
, NULL
); /* Release the associated eventpair object, if there was one */
193 KeRemoveAllWaitsThread (CurrentThread
, STATUS_UNSUCCESSFUL
, FALSE
);
195 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1
);
196 DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread
, PsGetCurrentThread());
201 PiTerminateThreadRundownRoutine(PKAPC Apc
)
207 PiTerminateThreadKernelRoutine(PKAPC Apc
,
208 PKNORMAL_ROUTINE
* NormalRoutine
,
209 PVOID
* NormalContext
,
210 PVOID
* SystemArgument1
,
211 PVOID
* SystemArguemnt2
)
217 PiTerminateThreadNormalRoutine(PVOID NormalContext
,
218 PVOID SystemArgument1
,
219 PVOID SystemArgument2
)
221 PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus
);
225 PsTerminateOtherThread(PETHREAD Thread
,
228 * FUNCTION: Terminate a thread when calling from another thread's context
229 * NOTES: This function must be called with PiThreadListLock held
235 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
238 Thread
->DeadThread
= 1;
239 Thread
->ExitStatus
= ExitStatus
;
240 Apc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG_TERMINATE_APC
);
243 OriginalApcEnvironment
,
244 PiTerminateThreadKernelRoutine
,
245 PiTerminateThreadRundownRoutine
,
246 PiTerminateThreadNormalRoutine
,
249 KeInsertQueueApc(Apc
,
253 if (THREAD_STATE_BLOCKED
== Thread
->Tcb
.State
&& UserMode
== Thread
->Tcb
.WaitMode
)
255 DPRINT("Unblocking thread\n");
256 Status
= STATUS_THREAD_IS_TERMINATING
;
257 KeRemoveAllWaitsThread(Thread
, Status
, TRUE
);
262 PiTerminateProcess(PEPROCESS Process
,
266 PEPROCESS CurrentProcess
;
268 DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n",
269 Process
, ExitStatus
, ObGetObjectPointerCount(Process
),
270 ObGetObjectHandleCount(Process
));
272 ObReferenceObject(Process
);
273 if (InterlockedExchange((PLONG
)&Process
->Pcb
.State
,
274 PROCESS_STATE_TERMINATED
) ==
275 PROCESS_STATE_TERMINATED
)
277 ObDereferenceObject(Process
);
278 return(STATUS_SUCCESS
);
280 CurrentProcess
= PsGetCurrentProcess();
281 if (Process
!= CurrentProcess
)
283 KeAttachProcess( Process
);
285 ObCloseAllHandles(Process
);
286 if (Process
!= CurrentProcess
)
290 OldIrql
= KeAcquireDispatcherDatabaseLock ();
291 Process
->Pcb
.DispatcherHeader
.SignalState
= TRUE
;
292 KeDispatcherObjectWake(&Process
->Pcb
.DispatcherHeader
);
293 KeReleaseDispatcherDatabaseLock (OldIrql
);
294 ObDereferenceObject(Process
);
295 return(STATUS_SUCCESS
);
299 NtTerminateProcess(IN HANDLE ProcessHandle
,
300 IN NTSTATUS ExitStatus
)
305 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
306 ProcessHandle
, ExitStatus
);
308 Status
= ObReferenceObjectByHandle(ProcessHandle
,
311 KeGetCurrentThread()->PreviousMode
,
314 if (!NT_SUCCESS(Status
))
318 Process
->ExitStatus
= ExitStatus
;
319 PiTerminateProcessThreads(Process
, ExitStatus
);
320 if (PsGetCurrentThread()->ThreadsProcess
== Process
)
322 ObDereferenceObject(Process
);
323 PsTerminateCurrentThread(ExitStatus
);
325 ObDereferenceObject(Process
);
326 return(STATUS_SUCCESS
);
331 NtTerminateThread(IN HANDLE ThreadHandle
,
332 IN NTSTATUS ExitStatus
)
337 Status
= ObReferenceObjectByHandle(ThreadHandle
,
340 KeGetCurrentThread()->PreviousMode
,
343 if (Status
!= STATUS_SUCCESS
)
348 ObDereferenceObject(Thread
);
350 if (Thread
== PsGetCurrentThread())
352 PsTerminateCurrentThread(ExitStatus
);
356 PsTerminateOtherThread(Thread
, ExitStatus
);
358 return(STATUS_SUCCESS
);
366 PsTerminateSystemThread(NTSTATUS ExitStatus
)
368 * FUNCTION: Terminates the current thread
370 * ExitStatus = Status to pass to the creater
374 PsTerminateCurrentThread(ExitStatus
);
375 return(STATUS_SUCCESS
);
379 NtCallTerminatePorts(PETHREAD Thread
)
382 PLIST_ENTRY current_entry
;
383 PEPORT_TERMINATION_REQUEST current
;
385 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
386 while ((current_entry
= RemoveHeadList(&Thread
->TerminationPortList
)) !=
387 &Thread
->TerminationPortList
);
389 current
= CONTAINING_RECORD(current_entry
,
390 EPORT_TERMINATION_REQUEST
,
392 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
393 LpcSendTerminationPort(current
->Port
,
395 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
397 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
398 return(STATUS_SUCCESS
);
402 NtRegisterThreadTerminatePort(HANDLE TerminationPortHandle
)
405 PEPORT_TERMINATION_REQUEST Request
;
406 PEPORT TerminationPort
;
410 Status
= ObReferenceObjectByHandle(TerminationPortHandle
,
413 KeGetCurrentThread()->PreviousMode
,
414 (PVOID
*)&TerminationPort
,
416 if (!NT_SUCCESS(Status
))
421 Request
= ExAllocatePool(NonPagedPool
, sizeof(EPORT_TERMINATION_REQUEST
));
422 Request
->Port
= TerminationPort
;
423 Thread
= PsGetCurrentThread();
424 KeAcquireSpinLock(&Thread
->ActiveTimerListLock
, &oldIrql
);
425 InsertTailList(&Thread
->TerminationPortList
, &Request
->ThreadListEntry
);
426 KeReleaseSpinLock(&Thread
->ActiveTimerListLock
, oldIrql
);
428 return(STATUS_SUCCESS
);