- Implement the ThreadDescriptorTableEntry case for NtQueryInformationThread. This...
[reactos.git] / reactos / ntoskrnl / ps / kill.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/kill.c
5 * PURPOSE: Process Manager: Process and Thread Termination
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (xnavara@reactos.org)
8 * Thomas Weidenmueller (w3seek@reactos.org
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 LIST_ENTRY PspReaperListHead = { NULL, NULL };
20 WORK_QUEUE_ITEM PspReaperWorkItem;
21 LARGE_INTEGER ShortTime = {{-10 * 100 * 1000, -1}};
22
23 /* PRIVATE FUNCTIONS *********************************************************/
24
25 VOID
26 NTAPI
27 PspCatchCriticalBreak(IN PCHAR Message,
28 IN PVOID ProcessOrThread,
29 IN PCHAR ImageName)
30 {
31 CHAR Action[2];
32 BOOLEAN Handled = FALSE;
33 PAGED_CODE();
34
35 /* Check if a debugger is enabled */
36 if (KdDebuggerEnabled)
37 {
38 /* Print out the message */
39 DbgPrint(Message, ProcessOrThread, ImageName);
40 do
41 {
42 /* If a debugger isn't present, don't prompt */
43 if (KdDebuggerNotPresent) break;
44
45 /* A debuger is active, prompt for action */
46 DbgPrompt("Break, or Ignore (bi)?", Action, sizeof(Action));
47 switch (Action[0])
48 {
49 /* Break */
50 case 'B': case 'b':
51
52 /* Do a breakpoint */
53 DbgBreakPoint();
54
55 /* Ignore */
56 case 'I': case 'i':
57
58 /* Handle it */
59 Handled = TRUE;
60
61 /* Unrecognized */
62 default:
63 break;
64 }
65 } while (!Handled);
66 }
67
68 /* Did we ultimately handle this? */
69 if (!Handled)
70 {
71 /* We didn't, bugcheck */
72 KeBugCheckEx(CRITICAL_OBJECT_TERMINATION,
73 ((PKPROCESS)ProcessOrThread)->Header.Type,
74 (ULONG_PTR)ProcessOrThread,
75 (ULONG_PTR)ImageName,
76 (ULONG_PTR)Message);
77 }
78 }
79
80 NTSTATUS
81 NTAPI
82 PspTerminateProcess(IN PEPROCESS Process,
83 IN NTSTATUS ExitStatus)
84 {
85 PETHREAD Thread;
86 NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE;
87 PAGED_CODE();
88 PSTRACE(PS_KILL_DEBUG,
89 "Process: %p ExitStatus: %p\n", Process, ExitStatus);
90 PSREFTRACE(Process);
91
92 /* Check if this is a Critical Process */
93 if (Process->BreakOnTermination)
94 {
95 /* Break to debugger */
96 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
97 Process,
98 Process->ImageFileName);
99 }
100
101 /* Set the delete flag */
102 InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT);
103
104 /* Get the first thread */
105 Thread = PsGetNextProcessThread(Process, NULL);
106 while (Thread)
107 {
108 /* Kill it */
109 PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
110 Thread = PsGetNextProcessThread(Process, Thread);
111
112 /* We had at least one thread, so termination is OK */
113 Status = STATUS_SUCCESS;
114 }
115
116 /* Check if there was nothing to terminate or if we have a debug port */
117 if ((Status == STATUS_NOTHING_TO_TERMINATE) || (Process->DebugPort))
118 {
119 /* Clear the handle table anyway */
120 ObClearProcessHandleTable(Process);
121 }
122
123 /* Return status */
124 return Status;
125 }
126
127 NTSTATUS
128 NTAPI
129 PsTerminateProcess(IN PEPROCESS Process,
130 IN NTSTATUS ExitStatus)
131 {
132 /* Call the internal API */
133 return PspTerminateProcess(Process, ExitStatus);
134 }
135
136 VOID
137 NTAPI
138 PspShutdownProcessManager(VOID)
139 {
140 PEPROCESS Process = NULL;
141
142 /* Loop every process */
143 Process = PsGetNextProcess(Process);
144 while (Process)
145 {
146 /* Make sure this isn't the idle or initial process */
147 if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess))
148 {
149 /* Kill it */
150 PspTerminateProcess(Process, STATUS_SYSTEM_SHUTDOWN);
151 }
152
153 /* Get the next process */
154 Process = PsGetNextProcess(Process);
155 }
156 }
157
158 VOID
159 NTAPI
160 PspExitApcRundown(IN PKAPC Apc)
161 {
162 PAGED_CODE();
163
164 /* Free the APC */
165 ExFreePool(Apc);
166 }
167
168 VOID
169 NTAPI
170 PspReapRoutine(IN PVOID Context)
171 {
172 PSINGLE_LIST_ENTRY NextEntry;
173 PETHREAD Thread;
174 PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context);
175
176 /* Start main loop */
177 do
178 {
179 /* Write magic value and return the next entry to process */
180 NextEntry = InterlockedExchangePointer(&PspReaperListHead.Flink,
181 (PVOID)1);
182 ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1));
183
184 /* Start inner loop */
185 do
186 {
187 /* Get the first Thread Entry */
188 Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink);
189
190 /* Delete this entry's kernel stack */
191 MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase,
192 Thread->Tcb.LargeStack);
193 Thread->Tcb.InitialStack = NULL;
194
195 /* Move to the next entry */
196 NextEntry = NextEntry->Next;
197
198 /* Dereference this thread */
199 ObDereferenceObject(Thread);
200 } while ((NextEntry != NULL) && (NextEntry != (PVOID)1));
201
202 /* Remove magic value, keep looping if it got changed */
203 } while (InterlockedCompareExchangePointer(&PspReaperListHead.Flink,
204 0,
205 1) != (PVOID)1);
206 }
207
208 VOID
209 NTAPI
210 PspDeleteProcess(IN PVOID ObjectBody)
211 {
212 PEPROCESS Process = (PEPROCESS)ObjectBody;
213 KAPC_STATE ApcState;
214 PAGED_CODE();
215 PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody);
216 PSREFTRACE(Process);
217
218 /* Check if it has an Active Process Link */
219 if (Process->ActiveProcessLinks.Flink)
220 {
221 /* Remove it from the Active List */
222 KeAcquireGuardedMutex(&PspActiveProcessMutex);
223 RemoveEntryList(&Process->ActiveProcessLinks);
224 KeReleaseGuardedMutex(&PspActiveProcessMutex);
225 }
226
227 /* Check for Auditing information */
228 if (Process->SeAuditProcessCreationInfo.ImageFileName)
229 {
230 /* Free it */
231 ExFreePool(Process->SeAuditProcessCreationInfo.ImageFileName);
232 Process->SeAuditProcessCreationInfo.ImageFileName = NULL;
233 }
234
235 /* Check if we have a job */
236 if (Process->Job)
237 {
238 /* Remove the process from the job */
239 PspRemoveProcessFromJob(Process, Process->Job);
240
241 /* Dereference it */
242 ObDereferenceObject(Process->Job);
243 Process->Job = NULL;
244 }
245
246 /* Increase the stack count */
247 Process->Pcb.StackCount++;
248
249 /* Check if we have a debug port */
250 if (Process->DebugPort)
251 {
252 /* Deference the Debug Port */
253 ObDereferenceObject(Process->DebugPort);
254 Process->DebugPort = NULL;
255 }
256
257 /* Check if we have an exception port */
258 if (Process->ExceptionPort)
259 {
260 /* Deference the Exception Port */
261 ObDereferenceObject(Process->ExceptionPort);
262 Process->ExceptionPort = NULL;
263 }
264
265 /* Check if we have a section object */
266 if (Process->SectionObject)
267 {
268 /* Deference the Section Object */
269 ObDereferenceObject(Process->SectionObject);
270 Process->SectionObject = NULL;
271 }
272
273 #if defined(_X86_)
274 /* Clean Ldt and Vdm objects */
275 PspDeleteLdt(Process);
276 PspDeleteVdmObjects(Process);
277 #endif
278
279 /* Delete the Object Table */
280 if (Process->ObjectTable)
281 {
282 /* Attach to the process */
283 KeStackAttachProcess(&Process->Pcb, &ApcState);
284
285 /* Kill the Object Info */
286 ObKillProcess(Process);
287
288 /* Detach */
289 KeUnstackDetachProcess(&ApcState);
290 }
291
292 /* Check if we have an address space, and clean it */
293 if (Process->HasAddressSpace)
294 {
295 /* Attach to the process */
296 KeStackAttachProcess(&Process->Pcb, &ApcState);
297
298 /* Clean the Address Space */
299 PspExitProcess(FALSE, Process);
300
301 /* Detach */
302 KeUnstackDetachProcess(&ApcState);
303
304 /* Completely delete the Address Space */
305 MmDeleteProcessAddressSpace(Process);
306 }
307
308 /* See if we have a PID */
309 if (Process->UniqueProcessId)
310 {
311 /* Delete the PID */
312 if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId, NULL)))
313 {
314 /* Something wrong happened, bugcheck */
315 KeBugCheck(CID_HANDLE_DELETION);
316 }
317 }
318
319 /* Cleanup security information */
320 PspDeleteProcessSecurity(Process);
321
322 /* Check if we have kept information on the Working Set */
323 if (Process->WorkingSetWatch)
324 {
325 /* Free it */
326 ExFreePool(Process->WorkingSetWatch);
327
328 /* And return the quota it was taking up */
329 PsReturnProcessNonPagedPoolQuota(Process, 0x2000);
330 }
331
332 /* Dereference the Device Map */
333 ObDereferenceDeviceMap(Process);
334
335 /* Destroy the Quota Block */
336 PspDestroyQuotaBlock(Process);
337 }
338
339 VOID
340 NTAPI
341 PspDeleteThread(IN PVOID ObjectBody)
342 {
343 PETHREAD Thread = (PETHREAD)ObjectBody;
344 PEPROCESS Process = Thread->ThreadsProcess;
345 PAGED_CODE();
346 PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody);
347 PSREFTRACE(Thread);
348 ASSERT(Thread->Tcb.Win32Thread == NULL);
349
350 /* Check if we have a stack */
351 if (Thread->Tcb.InitialStack)
352 {
353 /* Release it */
354 MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase,
355 Thread->Tcb.LargeStack);
356 }
357
358 /* Check if we have a CID Handle */
359 if (Thread->Cid.UniqueThread)
360 {
361 /* Delete the CID Handle */
362 if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread, NULL)))
363 {
364 /* Something wrong happened, bugcheck */
365 KeBugCheck(CID_HANDLE_DELETION);
366 }
367 }
368
369 /* Cleanup impersionation information */
370 PspDeleteThreadSecurity(Thread);
371
372 /* Make sure the thread was inserted, before continuing */
373 if (!Process) return;
374
375 /* Check if the thread list is valid */
376 if (Thread->ThreadListEntry.Flink)
377 {
378 /* Lock the thread's process */
379 KeEnterCriticalRegion();
380 ExAcquirePushLockExclusive(&Process->ProcessLock);
381
382 /* Remove us from the list */
383 RemoveEntryList(&Thread->ThreadListEntry);
384
385 /* Release the lock */
386 ExReleasePushLockExclusive(&Process->ProcessLock);
387 KeLeaveCriticalRegion();
388 }
389
390 /* Dereference the Process */
391 ObDereferenceObject(Process);
392 }
393
394 /*
395 * FUNCTION: Terminates the current thread
396 * See "Windows Internals" - Chapter 13, Page 50-53
397 */
398 VOID
399 NTAPI
400 PspExitThread(IN NTSTATUS ExitStatus)
401 {
402 CLIENT_DIED_MSG TerminationMsg;
403 NTSTATUS Status;
404 PTEB Teb;
405 PEPROCESS CurrentProcess;
406 PETHREAD Thread, OtherThread, PreviousThread = NULL;
407 PVOID DeallocationStack;
408 ULONG Dummy;
409 BOOLEAN Last = FALSE;
410 PTERMINATION_PORT TerminationPort, NextPort;
411 PLIST_ENTRY FirstEntry, CurrentEntry;
412 PKAPC Apc;
413 PTOKEN PrimaryToken;
414 PAGED_CODE();
415 PSTRACE(PS_KILL_DEBUG, "ExitStatus: %p\n", ExitStatus);
416
417 /* Get the Current Thread and Process */
418 Thread = PsGetCurrentThread();
419 CurrentProcess = Thread->ThreadsProcess;
420 ASSERT((Thread) == PsGetCurrentThread());
421
422 /* Can't terminate a thread if it attached another process */
423 if (KeIsAttachedProcess())
424 {
425 /* Bugcheck */
426 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
427 (ULONG_PTR)CurrentProcess,
428 (ULONG_PTR)Thread->Tcb.ApcState.Process,
429 (ULONG_PTR)Thread->Tcb.ApcStateIndex,
430 (ULONG_PTR)Thread);
431 }
432
433 /* Lower to Passive Level */
434 KeLowerIrql(PASSIVE_LEVEL);
435
436 /* Can't be a worker thread */
437 if (Thread->ActiveExWorker)
438 {
439 /* Bugcheck */
440 KeBugCheckEx(ACTIVE_EX_WORKER_THREAD_TERMINATION,
441 (ULONG_PTR)Thread,
442 0,
443 0,
444 0);
445 }
446
447 /* Can't have pending APCs */
448 if (Thread->Tcb.CombinedApcDisable != 0)
449 {
450 /* Bugcheck */
451 KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT,
452 0,
453 Thread->Tcb.CombinedApcDisable,
454 0,
455 1);
456 }
457
458 /* Lock the thread */
459 ExWaitForRundownProtectionRelease(&Thread->RundownProtect);
460
461 /* Cleanup the power state */
462 PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState);
463
464 /* Call the WMI Callback for Threads */
465 //WmiTraceThread(Thread, NULL, FALSE);
466
467 /* Run Thread Notify Routines before we desintegrate the thread */
468 PspRunCreateThreadNotifyRoutines(Thread, FALSE);
469
470 /* Lock the Process before we modify its thread entries */
471 KeEnterCriticalRegion();
472 ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);
473
474 /* Decrease the active thread count, and check if it's 0 */
475 if (!(--CurrentProcess->ActiveThreads))
476 {
477 /* Set the delete flag */
478 InterlockedOr((PLONG)&CurrentProcess->Flags, PSF_PROCESS_DELETE_BIT);
479
480 /* Remember we are last */
481 Last = TRUE;
482
483 /* Check if this termination is due to the thread dying */
484 if (ExitStatus == STATUS_THREAD_IS_TERMINATING)
485 {
486 /* Check if the last thread was pending */
487 if (CurrentProcess->ExitStatus == STATUS_PENDING)
488 {
489 /* Use the last exit status */
490 CurrentProcess->ExitStatus = CurrentProcess->
491 LastThreadExitStatus;
492 }
493 }
494 else
495 {
496 /* Just a normal exit, write the code */
497 CurrentProcess->ExitStatus = ExitStatus;
498 }
499
500 /* Loop all the current threads */
501 FirstEntry = &CurrentProcess->ThreadListHead;
502 CurrentEntry = FirstEntry->Flink;
503 while (FirstEntry != CurrentEntry)
504 {
505 /* Get the thread on the list */
506 OtherThread = CONTAINING_RECORD(CurrentEntry,
507 ETHREAD,
508 ThreadListEntry);
509
510 /* Check if it's a thread that's still alive */
511 if ((OtherThread != Thread) &&
512 !(KeReadStateThread(&OtherThread->Tcb)) &&
513 (ObReferenceObjectSafe(OtherThread)))
514 {
515 /* It's a live thread and we referenced it, unlock process */
516 ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
517 KeLeaveCriticalRegion();
518
519 /* Wait on the thread */
520 KeWaitForSingleObject(OtherThread,
521 Executive,
522 KernelMode,
523 FALSE,
524 NULL);
525
526 /* Check if we had a previous thread to dereference */
527 if (PreviousThread) ObDereferenceObject(PreviousThread);
528
529 /* Remember the thread and re-lock the process */
530 PreviousThread = OtherThread;
531 KeEnterCriticalRegion();
532 ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);
533 }
534
535 /* Go to the next thread */
536 CurrentEntry = CurrentEntry->Flink;
537 }
538 }
539 else if (ExitStatus != STATUS_THREAD_IS_TERMINATING)
540 {
541 /* Write down the exit status of the last thread to get killed */
542 CurrentProcess->LastThreadExitStatus = ExitStatus;
543 }
544
545 /* Unlock the Process */
546 ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
547 KeLeaveCriticalRegion();
548
549 /* Check if we had a previous thread to dereference */
550 if (PreviousThread) ObDereferenceObject(PreviousThread);
551
552 /* Check if the process has a debug port and if this is a user thread */
553 if ((CurrentProcess->DebugPort) && !(Thread->SystemThread))
554 {
555 /* Notify the Debug API. */
556 Last ? DbgkExitProcess(CurrentProcess->ExitStatus) :
557 DbgkExitThread(ExitStatus);
558 }
559
560 /* Check if this is a Critical Thread */
561 if ((KdDebuggerEnabled) && (Thread->BreakOnTermination))
562 {
563 /* Break to debugger */
564 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
565 Thread,
566 CurrentProcess->ImageFileName);
567 }
568
569 /* Check if it's the last thread and this is a Critical Process */
570 if ((Last) && (CurrentProcess->BreakOnTermination))
571 {
572 /* Check if a debugger is here to handle this */
573 if (KdDebuggerEnabled)
574 {
575 /* Break to debugger */
576 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n",
577 CurrentProcess,
578 CurrentProcess->ImageFileName);
579 }
580 else
581 {
582 /* Bugcheck, we can't allow this */
583 KeBugCheckEx(CRITICAL_PROCESS_DIED,
584 (ULONG_PTR)CurrentProcess,
585 0,
586 0,
587 0);
588 }
589 }
590
591 /* Sanity check */
592 ASSERT(Thread->Tcb.CombinedApcDisable == 0);
593
594 /* Process the Termination Ports */
595 TerminationPort = Thread->TerminationPort;
596 if (TerminationPort)
597 {
598 /* Setup the message header */
599 TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
600 TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
601 TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
602 sizeof(PORT_MESSAGE);
603
604 /* Loop each port */
605 do
606 {
607 /* Save the Create Time */
608 TerminationMsg.CreateTime = Thread->CreateTime;
609
610 /* Loop trying to send message */
611 while (TRUE)
612 {
613 /* Send the LPC Message */
614 Status = LpcRequestPort(TerminationPort->Port,
615 &TerminationMsg.h);
616 if ((Status == STATUS_NO_MEMORY) ||
617 (Status == STATUS_INSUFFICIENT_RESOURCES))
618 {
619 /* Wait a bit and try again */
620 KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
621 continue;
622 }
623 break;
624 }
625
626 /* Dereference this LPC Port */
627 ObDereferenceObject(TerminationPort->Port);
628
629 /* Move to the next one */
630 NextPort = TerminationPort->Next;
631
632 /* Free the Termination Port Object */
633 ExFreePool(TerminationPort);
634
635 /* Keep looping as long as there is a port */
636 TerminationPort = NextPort;
637 } while (TerminationPort);
638 }
639 else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) &&
640 (Thread->DeadThread)) ||
641 !(Thread->DeadThread))
642 {
643 /*
644 * This case is special and deserves some extra comments. What
645 * basically happens here is that this thread doesn't have a termination
646 * port, which means that it died before being fully created. Since we
647 * still have to notify an LPC Server, we'll use the exception port,
648 * which we know exists. However, we need to know how far the thread
649 * actually got created. We have three possibilites:
650 *
651 * - NtCreateThread returned an error really early: DeadThread is set.
652 * - NtCreateThread managed to create the thread: DeadThread is off.
653 * - NtCreateThread was creating the thread (with Deadthread set,
654 * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING
655 * is our exit code.)
656 *
657 * For the 2 & 3rd scenarios, the thread has been created far enough to
658 * warrant notification to the LPC Server.
659 */
660
661 /* Setup the message header */
662 TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
663 TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
664 TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
665 sizeof(PORT_MESSAGE);
666
667 /* Make sure the process has an exception port */
668 if (CurrentProcess->ExceptionPort)
669 {
670 /* Save the Create Time */
671 TerminationMsg.CreateTime = Thread->CreateTime;
672
673 /* Loop trying to send message */
674 while (TRUE)
675 {
676 /* Send the LPC Message */
677 Status = LpcRequestPort(CurrentProcess->ExceptionPort,
678 &TerminationMsg.h);
679 if ((Status == STATUS_NO_MEMORY) ||
680 (Status == STATUS_INSUFFICIENT_RESOURCES))
681 {
682 /* Wait a bit and try again */
683 KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
684 continue;
685 }
686 break;
687 }
688 }
689 }
690
691 /* Rundown Win32 Thread if there is one */
692 if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread,
693 PsW32ThreadCalloutExit);
694
695 /* If we are the last thread and have a W32 Process */
696 if ((Last) && (CurrentProcess->Win32Process))
697 {
698 /* Run it down too */
699 PspW32ProcessCallout(CurrentProcess, FALSE);
700 }
701
702 /* Make sure Stack Swap is enabled */
703 if (!Thread->Tcb.EnableStackSwap)
704 {
705 /* Stack swap really shouldn't be disabled during exit! */
706 KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0);
707 }
708
709 /* Cancel I/O for the thread. */
710 IoCancelThreadIo(Thread);
711
712 /* Rundown Timers */
713 ExTimerRundown();
714
715 /* FIXME: Rundown Registry Notifications (NtChangeNotify)
716 CmNotifyRunDown(Thread); */
717
718 /* Rundown Mutexes */
719 KeRundownThread();
720
721 /* Check if we have a TEB */
722 Teb = Thread->Tcb.Teb;
723 if (Teb)
724 {
725 /* Check if the thread is still alive */
726 if (!Thread->DeadThread)
727 {
728 /* Check if we need to free its stack */
729 if (Teb->FreeStackOnTermination)
730 {
731 /* Set the TEB's Deallocation Stack as the Base Address */
732 Dummy = 0;
733 DeallocationStack = Teb->DeallocationStack;
734
735 /* Free the Thread's Stack */
736 ZwFreeVirtualMemory(NtCurrentProcess(),
737 &DeallocationStack,
738 &Dummy,
739 MEM_RELEASE);
740 }
741
742 /* Free the debug handle */
743 if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1],
744 UserMode);
745 }
746
747 /* Decommit the TEB */
748 MmDeleteTeb(CurrentProcess, Teb);
749 Thread->Tcb.Teb = NULL;
750 }
751
752 /* Free LPC Data */
753 LpcExitThread(Thread);
754
755 /* Save the exit status and exit time */
756 Thread->ExitStatus = ExitStatus;
757 KeQuerySystemTime(&Thread->ExitTime);
758
759 /* Sanity check */
760 ASSERT(Thread->Tcb.CombinedApcDisable == 0);
761
762 /* Check if this is the final thread or not */
763 if (Last)
764 {
765 /* Set the process exit time */
766 CurrentProcess->ExitTime = Thread->ExitTime;
767
768 /* Exit the process */
769 PspExitProcess(TRUE, CurrentProcess);
770
771 /* Get the process token and check if we need to audit */
772 PrimaryToken = PsReferencePrimaryToken(CurrentProcess);
773 if (SeDetailedAuditingWithToken(PrimaryToken))
774 {
775 /* Audit the exit */
776 SeAuditProcessExit(CurrentProcess);
777 }
778
779 /* Dereference the process token */
780 ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken);
781
782 /* Check if this is a VDM Process and rundown the VDM DPCs if so */
783 if (CurrentProcess->VdmObjects) { /* VdmRundownDpcs(CurrentProcess); */ }
784
785 /* Kill the process in the Object Manager */
786 ObKillProcess(CurrentProcess);
787
788 /* Check if we have a section object */
789 if (CurrentProcess->SectionObject)
790 {
791 /* Dereference and clear the Section Object */
792 ObDereferenceObject(CurrentProcess->SectionObject);
793 CurrentProcess->SectionObject = NULL;
794 }
795
796 /* Check if the process is part of a job */
797 if (CurrentProcess->Job)
798 {
799 /* Remove the process from the job */
800 PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess);
801 }
802 }
803
804 /* Disable APCs */
805 KeEnterCriticalRegion();
806
807 /* Disable APC queueing, force a resumption */
808 Thread->Tcb.ApcQueueable = FALSE;
809 KeForceResumeThread(&Thread->Tcb);
810
811 /* Re-enable APCs */
812 KeLeaveCriticalRegion();
813
814 /* Flush the User APCs */
815 FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode);
816 if (FirstEntry)
817 {
818 /* Start with the first entry */
819 CurrentEntry = FirstEntry;
820 do
821 {
822 /* Get the APC */
823 Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
824
825 /* Move to the next one */
826 CurrentEntry = CurrentEntry->Flink;
827
828 /* Rundown the APC or de-allocate it */
829 if (Apc->RundownRoutine)
830 {
831 /* Call its own routine */
832 Apc->RundownRoutine(Apc);
833 }
834 else
835 {
836 /* Do it ourselves */
837 ExFreePool(Apc);
838 }
839 }
840 while (CurrentEntry != FirstEntry);
841 }
842
843 /* Clean address space if this was the last thread */
844 if (Last) MmCleanProcessAddressSpace(CurrentProcess);
845
846 /* Call the Lego routine */
847 if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb);
848
849 /* Flush the APC queue, which should be empty */
850 FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode);
851 if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0))
852 {
853 /* Bugcheck time */
854 KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT,
855 (ULONG_PTR)FirstEntry,
856 Thread->Tcb.CombinedApcDisable,
857 KeGetCurrentIrql(),
858 0);
859 }
860
861 /* Signal the process if this was the last thread */
862 if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE);
863
864 /* Terminate the Thread from the Scheduler */
865 KeTerminateThread(0);
866 }
867
868 VOID
869 NTAPI
870 PsExitSpecialApc(IN PKAPC Apc,
871 IN OUT PKNORMAL_ROUTINE* NormalRoutine,
872 IN OUT PVOID* NormalContext,
873 IN OUT PVOID* SystemArgument1,
874 IN OUT PVOID* SystemArgument2)
875 {
876 NTSTATUS Status;
877 PAGED_CODE();
878 PSTRACE(PS_KILL_DEBUG,
879 "Apc: %p SystemArgument2: %p \n", Apc, SystemArgument2);
880
881 /* Don't do anything unless we are in User-Mode */
882 if (Apc->SystemArgument2)
883 {
884 /* Free the APC */
885 Status = (NTSTATUS)Apc->NormalContext;
886 PspExitApcRundown(Apc);
887
888 /* Terminate the Thread */
889 PspExitThread(Status);
890 }
891 }
892
893 VOID
894 NTAPI
895 PspExitNormalApc(IN PVOID NormalContext,
896 IN PVOID SystemArgument1,
897 IN PVOID SystemArgument2)
898 {
899 PKAPC Apc = (PKAPC)SystemArgument1;
900 PETHREAD Thread = PsGetCurrentThread();
901 PAGED_CODE();
902 PSTRACE(PS_KILL_DEBUG, "SystemArgument2: %p \n", SystemArgument2);
903
904 /* This should never happen */
905 ASSERT(!(((ULONG_PTR)SystemArgument2) & 1));
906
907 /* If we're here, this is not a System Thread, so kill it from User-Mode */
908 KeInitializeApc(Apc,
909 &Thread->Tcb,
910 OriginalApcEnvironment,
911 PsExitSpecialApc,
912 PspExitApcRundown,
913 PspExitNormalApc,
914 UserMode,
915 NormalContext);
916
917 /* Now insert the APC with the User-Mode Flag */
918 if (!(KeInsertQueueApc(Apc,
919 Apc,
920 (PVOID)((ULONG_PTR)SystemArgument2 | 1),
921 2)))
922 {
923 /* Failed to insert, free the APC */
924 PspExitApcRundown(Apc);
925 }
926
927 /* Set the APC Pending flag */
928 Thread->Tcb.ApcState.UserApcPending = TRUE;
929 }
930
931 /*
932 * See "Windows Internals" - Chapter 13, Page 49
933 */
934 NTSTATUS
935 NTAPI
936 PspTerminateThreadByPointer(IN PETHREAD Thread,
937 IN NTSTATUS ExitStatus,
938 IN BOOLEAN bSelf)
939 {
940 PKAPC Apc;
941 NTSTATUS Status = STATUS_SUCCESS;
942 ULONG Flags;
943 PAGED_CODE();
944 PSTRACE(PS_KILL_DEBUG, "Thread: %p ExitStatus: %p\n", Thread, ExitStatus);
945 PSREFTRACE(Thread);
946
947 /* Check if this is a Critical Thread, and Bugcheck */
948 if (Thread->BreakOnTermination)
949 {
950 /* Break to debugger */
951 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
952 Thread,
953 Thread->ThreadsProcess->ImageFileName);
954 }
955
956 /* Check if we are already inside the thread */
957 if ((bSelf) || (PsGetCurrentThread() == Thread))
958 {
959 /* This should only happen at passive */
960 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
961
962 /* Mark it as terminated */
963 PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT);
964
965 /* Directly terminate the thread */
966 PspExitThread(ExitStatus);
967 }
968
969 /* This shouldn't be a system thread */
970 if (Thread->SystemThread) return STATUS_ACCESS_DENIED;
971
972 /* Allocate the APC */
973 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
974 if (!Apc) return STATUS_INSUFFICIENT_RESOURCES;
975
976 /* Set the Terminated Flag */
977 Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT;
978
979 /* Set it, and check if it was already set while we were running */
980 if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) &
981 CT_TERMINATED_BIT))
982 {
983 /* Initialize a Kernel Mode APC to Kill the Thread */
984 KeInitializeApc(Apc,
985 &Thread->Tcb,
986 OriginalApcEnvironment,
987 PsExitSpecialApc,
988 PspExitApcRundown,
989 PspExitNormalApc,
990 KernelMode,
991 (PVOID)ExitStatus);
992
993 /* Insert it into the APC Queue */
994 if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
995 {
996 /* The APC was already in the queue, fail */
997 Status = STATUS_UNSUCCESSFUL;
998 }
999 else
1000 {
1001 /* Forcefully resume the thread and return */
1002 KeForceResumeThread(&Thread->Tcb);
1003 return Status;
1004 }
1005 }
1006
1007 /* We failed, free the APC */
1008 ExFreePool(Apc);
1009
1010 /* Return Status */
1011 return Status;
1012 }
1013
1014 VOID
1015 NTAPI
1016 PspExitProcess(IN BOOLEAN LastThread,
1017 IN PEPROCESS Process)
1018 {
1019 ULONG Actual;
1020 PAGED_CODE();
1021 PSTRACE(PS_KILL_DEBUG,
1022 "LastThread: %p Process: %p\n", LastThread, Process);
1023 PSREFTRACE(Process);
1024
1025 /* Set Process Exit flag */
1026 InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_EXITING_BIT);
1027
1028 /* Check if we are the last thread */
1029 if (LastThread)
1030 {
1031 /* Notify the WMI Process Callback */
1032 //WmiTraceProcess(Process, FALSE);
1033
1034 /* Run the Notification Routines */
1035 PspRunCreateProcessNotifyRoutines(Process, FALSE);
1036 }
1037
1038 /* Cleanup the power state */
1039 PopCleanupPowerState((PPOWER_STATE)&Process->Pcb.PowerState);
1040
1041 /* Clear the security port */
1042 if (!Process->SecurityPort)
1043 {
1044 /* So we don't double-dereference */
1045 Process->SecurityPort = (PVOID)1;
1046 }
1047 else if (Process->SecurityPort != (PVOID)1)
1048 {
1049 /* Dereference it */
1050 ObDereferenceObject(Process->SecurityPort);
1051 Process->SecurityPort = (PVOID)1;
1052 }
1053
1054 /* Check if we are the last thread */
1055 if (LastThread)
1056 {
1057 /* Check if we have to set the Timer Resolution */
1058 if (Process->SetTimerResolution)
1059 {
1060 /* Set it to default */
1061 ZwSetTimerResolution(KeMaximumIncrement, 0, &Actual);
1062 }
1063
1064 /* Check if we are part of a Job that has a completion port */
1065 if ((Process->Job) && (Process->Job->CompletionPort))
1066 {
1067 /* FIXME: Check job status code and do I/O completion if needed */
1068 }
1069
1070 /* FIXME: Notify the Prefetcher */
1071 }
1072 else
1073 {
1074 /* Clear process' address space here */
1075 MmCleanProcessAddressSpace(Process);
1076 }
1077 }
1078
1079 /* PUBLIC FUNCTIONS **********************************************************/
1080
1081 /*
1082 * @implemented
1083 */
1084 NTSTATUS
1085 NTAPI
1086 PsTerminateSystemThread(IN NTSTATUS ExitStatus)
1087 {
1088 PETHREAD Thread = PsGetCurrentThread();
1089
1090 /* Make sure this is a system thread */
1091 if (!Thread->SystemThread) return STATUS_INVALID_PARAMETER;
1092
1093 /* Terminate it for real */
1094 return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE);
1095 }
1096
1097 /*
1098 * @implemented
1099 */
1100 NTSTATUS
1101 NTAPI
1102 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
1103 IN NTSTATUS ExitStatus)
1104 {
1105 NTSTATUS Status;
1106 PEPROCESS Process, CurrentProcess = PsGetCurrentProcess();
1107 PETHREAD Thread, CurrentThread = PsGetCurrentThread();
1108 BOOLEAN KillByHandle;
1109 PAGED_CODE();
1110 PSTRACE(PS_KILL_DEBUG,
1111 "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle, ExitStatus);
1112
1113 /* Were we passed a process handle? */
1114 if (ProcessHandle)
1115 {
1116 /* Yes we were, use it */
1117 KillByHandle = TRUE;
1118 }
1119 else
1120 {
1121 /* We weren't... we assume this is suicide */
1122 KillByHandle = FALSE;
1123 ProcessHandle = NtCurrentProcess();
1124 }
1125
1126 /* Get the Process Object */
1127 Status = ObReferenceObjectByHandle(ProcessHandle,
1128 PROCESS_TERMINATE,
1129 PsProcessType,
1130 KeGetPreviousMode(),
1131 (PVOID*)&Process,
1132 NULL);
1133 if (!NT_SUCCESS(Status)) return(Status);
1134
1135 /* Check if this is a Critical Process, and Bugcheck */
1136 if (Process->BreakOnTermination)
1137 {
1138 /* Break to debugger */
1139 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
1140 Process,
1141 Process->ImageFileName);
1142 }
1143
1144 /* Lock the Process */
1145 if (!ExAcquireRundownProtection(&Process->RundownProtect))
1146 {
1147 /* Failed to lock, fail */
1148 ObDereferenceObject (Process);
1149 return STATUS_PROCESS_IS_TERMINATING;
1150 }
1151
1152 /* Set the delete flag, unless the process is comitting suicide */
1153 if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT);
1154
1155 /* Get the first thread */
1156 Status = STATUS_NOTHING_TO_TERMINATE;
1157 Thread = PsGetNextProcessThread(Process, NULL);
1158 if (Thread)
1159 {
1160 /* We know we have at least a thread */
1161 Status = STATUS_SUCCESS;
1162
1163 /* Loop and kill the others */
1164 do
1165 {
1166 /* Ensure it's not ours*/
1167 if (Thread != CurrentThread)
1168 {
1169 /* Kill it */
1170 PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
1171 }
1172
1173 /* Move to the next thread */
1174 Thread = PsGetNextProcessThread(Process, Thread);
1175 } while (Thread);
1176 }
1177
1178 /* Unlock the process */
1179 ExReleaseRundownProtection(&Process->RundownProtect);
1180
1181 /* Check if we are killing ourselves */
1182 if (Process == CurrentProcess)
1183 {
1184 /* Also make sure the caller gave us our handle */
1185 if (KillByHandle)
1186 {
1187 /* Dereference the process */
1188 ObDereferenceObject(Process);
1189
1190 /* Terminate ourselves */
1191 PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE);
1192 }
1193 }
1194 else if (ExitStatus == DBG_TERMINATE_PROCESS)
1195 {
1196 /* Disable debugging on this process */
1197 DbgkClearProcessDebugObject(Process, NULL);
1198 }
1199
1200 /* Check if there was nothing to terminate, or if we have a Debug Port */
1201 if ((Status == STATUS_NOTHING_TO_TERMINATE) ||
1202 ((Process->DebugPort) && (KillByHandle)))
1203 {
1204 /* Clear the handle table */
1205 ObClearProcessHandleTable(Process);
1206
1207 /* Return status now */
1208 Status = STATUS_SUCCESS;
1209 }
1210
1211 /* Decrease the reference count we added */
1212 ObDereferenceObject(Process);
1213
1214 /* Return status */
1215 return Status;
1216 }
1217
1218 NTSTATUS
1219 NTAPI
1220 NtTerminateThread(IN HANDLE ThreadHandle,
1221 IN NTSTATUS ExitStatus)
1222 {
1223 PETHREAD Thread;
1224 PETHREAD CurrentThread = PsGetCurrentThread();
1225 NTSTATUS Status;
1226 PAGED_CODE();
1227 PSTRACE(PS_KILL_DEBUG,
1228 "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle, ExitStatus);
1229
1230 /* Handle the special NULL case */
1231 if (!ThreadHandle)
1232 {
1233 /* Check if we're the only thread left */
1234 if (PsGetCurrentProcess()->ActiveThreads == 1)
1235 {
1236 /* This is invalid */
1237 return STATUS_CANT_TERMINATE_SELF;
1238 }
1239
1240 /* Terminate us directly */
1241 goto TerminateSelf;
1242 }
1243 else if (ThreadHandle == NtCurrentThread())
1244 {
1245 TerminateSelf:
1246 /* Terminate this thread */
1247 return PspTerminateThreadByPointer(CurrentThread,
1248 ExitStatus,
1249 TRUE);
1250 }
1251
1252 /* We are terminating another thread, get the Thread Object */
1253 Status = ObReferenceObjectByHandle(ThreadHandle,
1254 THREAD_TERMINATE,
1255 PsThreadType,
1256 KeGetPreviousMode(),
1257 (PVOID*)&Thread,
1258 NULL);
1259 if (!NT_SUCCESS(Status)) return Status;
1260
1261 /* Check to see if we're running in the same thread */
1262 if (Thread != CurrentThread)
1263 {
1264 /* Terminate it */
1265 Status = PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
1266
1267 /* Dereference the Thread and return */
1268 ObDereferenceObject(Thread);
1269 }
1270 else
1271 {
1272 /* Dereference the thread and terminate ourselves */
1273 ObDereferenceObject(Thread);
1274 goto TerminateSelf;
1275 }
1276
1277 /* Return status */
1278 return Status;
1279 }
1280
1281 NTSTATUS
1282 NTAPI
1283 NtRegisterThreadTerminatePort(IN HANDLE PortHandle)
1284 {
1285 NTSTATUS Status;
1286 PTERMINATION_PORT TerminationPort;
1287 PVOID TerminationLpcPort;
1288 PETHREAD Thread;
1289 PAGED_CODE();
1290 PSTRACE(PS_KILL_DEBUG, "PortHandle: %p\n", PortHandle);
1291
1292 /* Get the Port */
1293 Status = ObReferenceObjectByHandle(PortHandle,
1294 PORT_ALL_ACCESS,
1295 LpcPortObjectType,
1296 KeGetPreviousMode(),
1297 &TerminationLpcPort,
1298 NULL);
1299 if (!NT_SUCCESS(Status)) return(Status);
1300
1301 /* Allocate the Port and make sure it suceeded */
1302 TerminationPort = ExAllocatePoolWithTag(NonPagedPool,
1303 sizeof(TERMINATION_PORT),
1304 '=TsP');
1305 if(TerminationPort)
1306 {
1307 /* Associate the Port */
1308 Thread = PsGetCurrentThread();
1309 TerminationPort->Port = TerminationLpcPort;
1310 TerminationPort->Next = Thread->TerminationPort;
1311 Thread->TerminationPort = TerminationPort;
1312
1313 /* Return success */
1314 return STATUS_SUCCESS;
1315 }
1316
1317 /* Dereference and Fail */
1318 ObDereferenceObject(TerminationPort);
1319 return STATUS_INSUFFICIENT_RESOURCES;
1320 }