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