kill.c: remove useless call to KeRemoveAllWaitsThread + misc
[reactos.git] / reactos / ntoskrnl / ps / kill.c
1 /* $Id: kill.c,v 1.86 2004/11/21 18:42:58 gdalsnes 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 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 extern KSPIN_LOCK PiThreadLock;
21
22 VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
23 NTSTATUS STDCALL NtCallTerminatePorts(PETHREAD Thread);
24
25 #define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C')
26
27 LIST_ENTRY ThreadsToReapHead;
28
29 /* FUNCTIONS *****************************************************************/
30
31 VOID
32 PsInitializeThreadReaper(VOID)
33 {
34 InitializeListHead(&ThreadsToReapHead);
35 }
36
37 VOID
38 PsReapThreads(VOID)
39 {
40 KIRQL oldlvl;
41 PETHREAD Thread;
42 PLIST_ENTRY ListEntry;
43
44 KeAcquireSpinLock(&PiThreadLock, &oldlvl);
45 while((ListEntry = RemoveHeadList(&ThreadsToReapHead)) != &ThreadsToReapHead)
46 {
47 PiNrThreadsAwaitingReaping--;
48 KeReleaseSpinLock(&PiThreadLock, oldlvl);
49
50 Thread = CONTAINING_RECORD(ListEntry, ETHREAD, TerminationPortList);
51
52 ObDereferenceObject(Thread);
53
54 KeAcquireSpinLock(&PiThreadLock, &oldlvl);
55 }
56 KeReleaseSpinLock(&PiThreadLock, oldlvl);
57 }
58
59 VOID
60 PsQueueThreadReap(PETHREAD Thread)
61 {
62 InsertTailList(&ThreadsToReapHead, &Thread->TerminationPortList);
63 PiNrThreadsAwaitingReaping++;
64 }
65
66 VOID
67 PiTerminateProcessThreads(PEPROCESS Process,
68 NTSTATUS ExitStatus)
69 {
70 KIRQL oldlvl;
71 PLIST_ENTRY current_entry;
72 PETHREAD current, CurrentThread = PsGetCurrentThread();
73
74 DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n",
75 Process, ExitStatus);
76
77 KeAcquireSpinLock(&PiThreadLock, &oldlvl);
78
79 current_entry = Process->ThreadListHead.Flink;
80 while (current_entry != &Process->ThreadListHead)
81 {
82 current = CONTAINING_RECORD(current_entry, ETHREAD,
83 ThreadListEntry);
84 if (current != CurrentThread && current->HasTerminated == 0)
85 {
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;
93 }
94 else
95 {
96 current_entry = current_entry->Flink;
97 }
98 }
99 KeReleaseSpinLock(&PiThreadLock, oldlvl);
100 DPRINT("Finished PiTerminateProcessThreads()\n");
101 }
102
103 VOID
104 PsTerminateCurrentThread(NTSTATUS ExitStatus)
105 /*
106 * FUNCTION: Terminates the current thread
107 */
108 {
109 KIRQL oldIrql;
110 PETHREAD CurrentThread;
111 PLIST_ENTRY current_entry;
112 PKMUTANT Mutant;
113 BOOLEAN Last;
114 PEPROCESS CurrentProcess;
115 SIZE_T Length = PAGE_SIZE;
116 PVOID TebBlock;
117
118 KeLowerIrql(PASSIVE_LEVEL);
119
120 CurrentThread = PsGetCurrentThread();
121 CurrentProcess = CurrentThread->ThreadsProcess;
122
123 /* Can't terminate a thread if it attached another process */
124 if (AttachedApcEnvironment == CurrentThread->Tcb.ApcStateIndex)
125 {
126 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG) CurrentProcess,
127 (ULONG) CurrentThread->Tcb.ApcState.Process,
128 (ULONG) CurrentThread->Tcb.ApcStateIndex,
129 (ULONG) CurrentThread);
130 }
131
132 KeAcquireSpinLock(&PiThreadLock, &oldIrql);
133
134 DPRINT("terminating %x\n",CurrentThread);
135
136 CurrentThread->HasTerminated = TRUE;
137 CurrentThread->ExitStatus = ExitStatus;
138 KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime);
139 KeCancelTimer(&CurrentThread->Tcb.Timer);
140
141 /* If the ProcessoR Control Block's NpxThread points to the current thread
142 * unset it.
143 */
144 InterlockedCompareExchange((LONG *)&KeGetCurrentKPCR()->PrcbData.NpxThread,
145 (LONG)NULL, (LONG)ETHREAD_TO_KTHREAD(CurrentThread));
146
147 KeReleaseSpinLock(&PiThreadLock, oldIrql);
148
149 PsLockProcess(CurrentProcess, FALSE);
150
151 /* Remove the thread from the thread list of its process */
152 RemoveEntryList(&CurrentThread->ThreadListEntry);
153 Last = IsListEmpty(&CurrentProcess->ThreadListHead);
154 PsUnlockProcess(CurrentProcess);
155
156 /* Notify subsystems of the thread termination */
157 PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
158 PsTerminateWin32Thread(CurrentThread);
159
160 /* Free the TEB */
161 if(CurrentThread->Tcb.Teb)
162 {
163 DPRINT("Decommit teb at %p\n", CurrentThread->Tcb.Teb);
164 ExAcquireFastMutex(&CurrentProcess->TebLock);
165 TebBlock = MM_ROUND_DOWN(CurrentThread->Tcb.Teb, MM_VIRTMEM_GRANULARITY);
166 ZwFreeVirtualMemory(NtCurrentProcess(),
167 (PVOID *)&CurrentThread->Tcb.Teb,
168 &Length,
169 MEM_DECOMMIT);
170 DPRINT("teb %p, TebBlock %p\n", CurrentThread->Tcb.Teb, TebBlock);
171 if (TebBlock != CurrentProcess->TebBlock ||
172 CurrentProcess->TebBlock == CurrentProcess->TebLastAllocated)
173 {
174 MmLockAddressSpace(&CurrentProcess->AddressSpace);
175 MmReleaseMemoryAreaIfDecommitted(CurrentProcess, &CurrentProcess->AddressSpace, TebBlock);
176 MmUnlockAddressSpace(&CurrentProcess->AddressSpace);
177 }
178 ExReleaseFastMutex(&CurrentProcess->TebLock);
179 }
180
181 /* abandon all owned mutants */
182 current_entry = CurrentThread->Tcb.MutantListHead.Flink;
183 while (current_entry != &CurrentThread->Tcb.MutantListHead)
184 {
185 Mutant = CONTAINING_RECORD(current_entry, KMUTANT,
186 MutantListEntry);
187 KeReleaseMutant(Mutant,
188 MUTANT_INCREMENT,
189 TRUE,
190 FALSE);
191 current_entry = CurrentThread->Tcb.MutantListHead.Flink;
192 }
193
194 oldIrql = KeAcquireDispatcherDatabaseLock();
195 CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE;
196 KiDispatcherObjectWake(&CurrentThread->Tcb.DispatcherHeader);
197 KeReleaseDispatcherDatabaseLock (oldIrql);
198
199 /* The last thread shall close the door on exit */
200 if(Last)
201 {
202 /* save the last thread exit status */
203 CurrentProcess->LastThreadExitStatus = ExitStatus;
204
205 PspRunCreateProcessNotifyRoutines(CurrentProcess, FALSE);
206 PsTerminateWin32Process(CurrentProcess);
207 PiTerminateProcess(CurrentProcess, ExitStatus);
208 }
209
210 KeAcquireSpinLock(&PiThreadLock, &oldIrql);
211
212 #ifdef _ENABLE_THRDEVTPAIR
213 ExpSwapThreadEventPair(CurrentThread, NULL); /* Release the associated eventpair object, if there was one */
214 #endif /* _ENABLE_THRDEVTPAIR */
215
216 ASSERT(CurrentThread->Tcb.WaitBlockList == NULL);
217
218 PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1);
219 DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
220 KEBUGCHECK(0);
221 }
222
223 VOID STDCALL
224 PiTerminateThreadRundownRoutine(PKAPC Apc)
225 {
226 ExFreePool(Apc);
227 }
228
229 VOID STDCALL
230 PiTerminateThreadKernelRoutine(PKAPC Apc,
231 PKNORMAL_ROUTINE* NormalRoutine,
232 PVOID* NormalContext,
233 PVOID* SystemArgument1,
234 PVOID* SystemArguemnt2)
235 {
236 ExFreePool(Apc);
237 }
238
239 VOID STDCALL
240 PiTerminateThreadNormalRoutine(PVOID NormalContext,
241 PVOID SystemArgument1,
242 PVOID SystemArgument2)
243 {
244 PsTerminateCurrentThread(PsGetCurrentThread()->ExitStatus);
245 }
246
247 VOID
248 PsTerminateOtherThread(PETHREAD Thread,
249 NTSTATUS ExitStatus)
250 /*
251 * FUNCTION: Terminate a thread when calling from another thread's context
252 * NOTES: This function must be called with PiThreadLock held
253 */
254 {
255 PKAPC Apc;
256 KIRQL OldIrql;
257
258 DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n",
259 Thread, ExitStatus);
260
261 Thread->HasTerminated = TRUE;
262 Thread->ExitStatus = ExitStatus;
263 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
264 KeInitializeApc(Apc,
265 &Thread->Tcb,
266 OriginalApcEnvironment,
267 PiTerminateThreadKernelRoutine,
268 PiTerminateThreadRundownRoutine,
269 PiTerminateThreadNormalRoutine,
270 KernelMode,
271 NULL);
272 KeInsertQueueApc(Apc,
273 NULL,
274 NULL,
275 IO_NO_INCREMENT);
276
277 OldIrql = KeAcquireDispatcherDatabaseLock();
278 if (THREAD_STATE_BLOCKED == Thread->Tcb.State && UserMode == Thread->Tcb.WaitMode)
279 {
280 DPRINT("Unblocking thread\n");
281 KiAbortWaitThread((PKTHREAD)Thread, STATUS_THREAD_IS_TERMINATING);
282 }
283 KeReleaseDispatcherDatabaseLock(OldIrql);
284 }
285
286 NTSTATUS STDCALL
287 PiTerminateProcess(PEPROCESS Process,
288 NTSTATUS ExitStatus)
289 {
290 KIRQL OldIrql;
291 PEPROCESS CurrentProcess;
292
293 DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n",
294 Process, ExitStatus, ObGetObjectPointerCount(Process),
295 ObGetObjectHandleCount(Process));
296
297 ObReferenceObject(Process);
298 if (InterlockedExchange((PLONG)&Process->Pcb.State,
299 PROCESS_STATE_TERMINATED) ==
300 PROCESS_STATE_TERMINATED)
301 {
302 ObDereferenceObject(Process);
303 return(STATUS_SUCCESS);
304 }
305 CurrentProcess = PsGetCurrentProcess();
306 if (Process != CurrentProcess)
307 {
308 KeAttachProcess(&Process->Pcb);
309 }
310 ObCloseAllHandles(Process);
311 if (Process != CurrentProcess)
312 {
313 KeDetachProcess();
314 }
315 OldIrql = KeAcquireDispatcherDatabaseLock ();
316 Process->Pcb.DispatcherHeader.SignalState = TRUE;
317 KiDispatcherObjectWake(&Process->Pcb.DispatcherHeader);
318 KeReleaseDispatcherDatabaseLock (OldIrql);
319 ObDereferenceObject(Process);
320 return(STATUS_SUCCESS);
321 }
322
323 NTSTATUS STDCALL
324 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
325 IN NTSTATUS ExitStatus)
326 {
327 NTSTATUS Status;
328 PEPROCESS Process;
329
330 DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n",
331 ProcessHandle, ExitStatus);
332
333 Status = ObReferenceObjectByHandle(ProcessHandle,
334 PROCESS_TERMINATE,
335 PsProcessType,
336 KeGetCurrentThread()->PreviousMode,
337 (PVOID*)&Process,
338 NULL);
339 if (!NT_SUCCESS(Status))
340 {
341 return(Status);
342 }
343 Process->ExitStatus = ExitStatus;
344 PiTerminateProcessThreads(Process, ExitStatus);
345 if (PsGetCurrentThread()->ThreadsProcess == Process)
346 {
347 ObDereferenceObject(Process);
348 PsTerminateCurrentThread(ExitStatus);
349 /*
350 * We should never get here!
351 */
352 return(STATUS_SUCCESS);
353 }
354 ObDereferenceObject(Process);
355 return(STATUS_SUCCESS);
356 }
357
358
359 NTSTATUS STDCALL
360 NtTerminateThread(IN HANDLE ThreadHandle,
361 IN NTSTATUS ExitStatus)
362 {
363 PETHREAD Thread;
364 NTSTATUS Status;
365
366 Status = ObReferenceObjectByHandle(ThreadHandle,
367 THREAD_TERMINATE,
368 PsThreadType,
369 KeGetCurrentThread()->PreviousMode,
370 (PVOID*)&Thread,
371 NULL);
372 if (Status != STATUS_SUCCESS)
373 {
374 return(Status);
375 }
376
377 if (Thread == PsGetCurrentThread())
378 {
379 /* dereference the thread object before we kill our thread */
380 ObDereferenceObject(Thread);
381 PsTerminateCurrentThread(ExitStatus);
382 /*
383 * We should never get here!
384 */
385 }
386 else
387 {
388 PsTerminateOtherThread(Thread, ExitStatus);
389 ObDereferenceObject(Thread);
390 }
391 return(STATUS_SUCCESS);
392 }
393
394
395 /*
396 * @implemented
397 */
398 NTSTATUS STDCALL
399 PsTerminateSystemThread(NTSTATUS ExitStatus)
400 /*
401 * FUNCTION: Terminates the current thread
402 * ARGUMENTS:
403 * ExitStatus = Status to pass to the creater
404 * RETURNS: Doesn't
405 */
406 {
407 PsTerminateCurrentThread(ExitStatus);
408 return(STATUS_SUCCESS);
409 }
410
411 NTSTATUS STDCALL
412 NtCallTerminatePorts(PETHREAD Thread)
413 {
414 KIRQL oldIrql;
415 PLIST_ENTRY current_entry;
416 PEPORT_TERMINATION_REQUEST current;
417
418 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
419 while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) !=
420 &Thread->TerminationPortList);
421 {
422 current = CONTAINING_RECORD(current_entry,
423 EPORT_TERMINATION_REQUEST,
424 ThreadListEntry);
425 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
426 LpcSendTerminationPort(current->Port,
427 Thread->CreateTime);
428 ExFreePool(current);
429 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
430 }
431 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
432 return(STATUS_SUCCESS);
433 }
434
435 NTSTATUS STDCALL
436 NtRegisterThreadTerminatePort(HANDLE PortHandle)
437 {
438 NTSTATUS Status;
439 PEPORT_TERMINATION_REQUEST Request;
440 PEPORT TerminationPort;
441 KIRQL oldIrql;
442 PETHREAD Thread;
443
444 Status = ObReferenceObjectByHandle(PortHandle,
445 PORT_ALL_ACCESS,
446 ExPortType,
447 KeGetCurrentThread()->PreviousMode,
448 (PVOID*)&TerminationPort,
449 NULL);
450 if (!NT_SUCCESS(Status))
451 {
452 return(Status);
453 }
454
455 Request = ExAllocatePool(NonPagedPool, sizeof(EPORT_TERMINATION_REQUEST));
456 if(Request != NULL)
457 {
458 Request->Port = TerminationPort;
459 Thread = PsGetCurrentThread();
460 KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql);
461 InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry);
462 KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql);
463
464 return(STATUS_SUCCESS);
465 }
466 else
467 {
468 ObDereferenceObject(TerminationPort);
469 return(STATUS_INSUFFICIENT_RESOURCES);
470 }
471 }