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
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 LIST_ENTRY PspReaperListHead
= {0};
20 WORK_QUEUE_ITEM PspReaperWorkItem
;
21 LARGE_INTEGER ShortTime
= {{-10 * 100 * 1000, -1}};
23 /* PRIVATE FUNCTIONS *********************************************************/
27 PspCatchCriticalBreak(IN PCHAR Message
,
28 IN PVOID ProcessOrThread
,
32 BOOLEAN Handled
= FALSE
;
35 /* Check if a debugger is enabled */
36 if (KdDebuggerEnabled
)
38 /* Print out the message */
39 DbgPrint(Message
, ProcessOrThread
, ImageName
);
42 /* If a debugger isn't present, don't prompt */
43 if (KdDebuggerNotPresent
) break;
45 /* A debuger is active, prompt for action */
46 DbgPrompt("Break, or Ignore (bi)?", Action
, sizeof(Action
));
68 /* Did we ultimately handle this? */
71 /* We didn't, bugcheck */
72 KeBugCheckEx(CRITICAL_OBJECT_TERMINATION
,
73 ((PKPROCESS
)ProcessOrThread
)->Header
.Type
,
74 (ULONG_PTR
)ProcessOrThread
,
82 PspTerminateProcess(IN PEPROCESS Process
,
83 IN NTSTATUS ExitStatus
)
86 NTSTATUS Status
= STATUS_NOTHING_TO_TERMINATE
;
88 PSTRACE(PS_KILL_DEBUG
,
89 "Process: %p ExitStatus: %p\n", Process
, ExitStatus
);
92 /* Check if this is a Critical Process */
93 if (Process
->BreakOnTermination
)
95 /* Break to debugger */
96 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
98 Process
->ImageFileName
);
101 /* Set the delete flag */
102 InterlockedOr((PLONG
)&Process
->Flags
, PSF_PROCESS_DELETE_BIT
);
104 /* Get the first thread */
105 Thread
= PsGetNextProcessThread(Process
, NULL
);
109 PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
110 Thread
= PsGetNextProcessThread(Process
, Thread
);
112 /* We had at least one thread, so termination is OK */
113 Status
= STATUS_SUCCESS
;
116 /* Check if there was nothing to terminate or if we have a debug port */
117 if ((Status
== STATUS_NOTHING_TO_TERMINATE
) || (Process
->DebugPort
))
119 /* Clear the handle table anyway */
120 ObClearProcessHandleTable(Process
);
129 PsTerminateProcess(IN PEPROCESS Process
,
130 IN NTSTATUS ExitStatus
)
132 /* Call the internal API */
133 return PspTerminateProcess(Process
, ExitStatus
);
138 PspShutdownProcessManager(VOID
)
140 PEPROCESS Process
= NULL
;
142 /* Loop every process */
143 Process
= PsGetNextProcess(Process
);
146 /* Make sure this isn't the idle or initial process */
147 if ((Process
!= PsInitialSystemProcess
) && (Process
!= PsIdleProcess
))
150 PspTerminateProcess(Process
, STATUS_SYSTEM_SHUTDOWN
);
153 /* Get the next process */
154 Process
= PsGetNextProcess(Process
);
160 PspExitApcRundown(IN PKAPC Apc
)
170 PspReapRoutine(IN PVOID Context
)
172 PSINGLE_LIST_ENTRY NextEntry
;
174 PSTRACE(PS_KILL_DEBUG
, "Context: %p\n", Context
);
176 /* Start main loop */
179 /* Write magic value and return the next entry to process */
180 NextEntry
= InterlockedExchangePointer(&PspReaperListHead
.Flink
,
182 ASSERT((NextEntry
!= NULL
) && (NextEntry
!= (PVOID
)1));
184 /* Start inner loop */
187 /* Get the first Thread Entry */
188 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, ReaperLink
);
190 /* Delete this entry's kernel stack */
191 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackLimit
,
192 Thread
->Tcb
.LargeStack
);
193 Thread
->Tcb
.InitialStack
= NULL
;
195 /* Move to the next entry */
196 NextEntry
= NextEntry
->Next
;
198 /* Dereference this thread */
199 ObDereferenceObject(Thread
);
200 } while ((NextEntry
!= NULL
) && (NextEntry
!= (PVOID
)1));
202 /* Remove magic value, keep looping if it got changed */
203 } while (InterlockedCompareExchangePointer(&PspReaperListHead
.Flink
,
210 PspDeleteProcess(IN PVOID ObjectBody
)
212 PEPROCESS Process
= (PEPROCESS
)ObjectBody
;
215 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
218 /* Check if it has an Active Process Link */
219 if (Process
->ActiveProcessLinks
.Flink
)
221 /* Remove it from the Active List */
222 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
223 RemoveEntryList(&Process
->ActiveProcessLinks
);
224 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
227 /* Check for Auditing information */
228 if (Process
->SeAuditProcessCreationInfo
.ImageFileName
)
231 ExFreePool(Process
->SeAuditProcessCreationInfo
.ImageFileName
);
232 Process
->SeAuditProcessCreationInfo
.ImageFileName
= NULL
;
235 /* Check if we have a job */
238 /* Remove the process from the job */
239 PspRemoveProcessFromJob(Process
, Process
->Job
);
242 ObDereferenceObject(Process
->Job
);
246 /* Increase the stack count */
247 Process
->Pcb
.StackCount
++;
249 /* Check if we have a debug port */
250 if (Process
->DebugPort
)
252 /* Deference the Debug Port */
253 ObDereferenceObject(Process
->DebugPort
);
254 Process
->DebugPort
= NULL
;
257 /* Check if we have an exception port */
258 if (Process
->ExceptionPort
)
260 /* Deference the Exception Port */
261 ObDereferenceObject(Process
->ExceptionPort
);
262 Process
->ExceptionPort
= NULL
;
265 /* Check if we have a section object */
266 if (Process
->SectionObject
)
268 /* Deference the Section Object */
269 ObDereferenceObject(Process
->SectionObject
);
270 Process
->SectionObject
= NULL
;
273 /* Clean LDT and VDM_OBJECTS */
274 PspDeleteLdt(Process
);
275 PspDeleteVdmObjects(Process
);
277 /* Delete the Object Table */
278 if (Process
->ObjectTable
)
280 /* Attach to the process */
281 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
283 /* Kill the Object Info */
284 ObKillProcess(Process
);
287 KeUnstackDetachProcess(&ApcState
);
291 KDB_DELETEPROCESS_HOOK(Process
);
293 /* Check if we have an address space, and clean it */
294 if (Process
->HasAddressSpace
)
296 /* Attach to the process */
297 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
299 /* Clean the Address Space */
300 PspExitProcess(FALSE
, Process
);
303 KeUnstackDetachProcess(&ApcState
);
305 /* Completely delete the Address Space */
306 MmDeleteProcessAddressSpace(Process
);
309 /* See if we have a PID */
310 if (Process
->UniqueProcessId
)
313 if (!(ExDestroyHandle(PspCidTable
, Process
->UniqueProcessId
, NULL
)))
315 /* Something wrong happened, bugcheck */
316 KEBUGCHECK(CID_HANDLE_DELETION
);
320 /* Cleanup security information */
321 PspDeleteProcessSecurity(Process
);
323 /* Check if we have kept information on the Working Set */
324 if (Process
->WorkingSetWatch
)
327 ExFreePool(Process
->WorkingSetWatch
);
329 /* And return the quota it was taking up */
330 PsReturnProcessNonPagedPoolQuota(Process
, 0x2000);
333 /* Dereference the Device Map */
334 ObDereferenceDeviceMap(Process
);
336 /* Destroy the Quota Block */
337 PspDestroyQuotaBlock(Process
);
342 PspDeleteThread(IN PVOID ObjectBody
)
344 PETHREAD Thread
= (PETHREAD
)ObjectBody
;
345 PEPROCESS Process
= Thread
->ThreadsProcess
;
347 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
349 ASSERT(Thread
->Tcb
.Win32Thread
== NULL
);
351 /* Check if we have a stack */
352 if (Thread
->Tcb
.InitialStack
)
355 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackLimit
,
356 Thread
->Tcb
.LargeStack
);
359 /* Check if we have a CID Handle */
360 if (Thread
->Cid
.UniqueThread
)
362 /* Delete the CID Handle */
363 if (!(ExDestroyHandle(PspCidTable
, Thread
->Cid
.UniqueThread
, NULL
)))
365 /* Something wrong happened, bugcheck */
366 KEBUGCHECK(CID_HANDLE_DELETION
);
370 /* Cleanup impersionation information */
371 PspDeleteThreadSecurity(Thread
);
373 /* Make sure the thread was inserted, before continuing */
374 if (!Process
) return;
376 /* Check if the thread list is valid */
377 if (Thread
->ThreadListEntry
.Flink
)
379 /* Lock the thread's process */
380 KeEnterCriticalRegion();
381 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
383 /* Remove us from the list */
384 RemoveEntryList(&Thread
->ThreadListEntry
);
386 /* Release the lock */
387 ExReleasePushLockExclusive(&Process
->ProcessLock
);
388 KeLeaveCriticalRegion();
391 /* Dereference the Process */
392 ObDereferenceObject(Process
);
396 * FUNCTION: Terminates the current thread
397 * See "Windows Internals" - Chapter 13, Page 50-53
401 PspExitThread(IN NTSTATUS ExitStatus
)
403 CLIENT_DIED_MSG TerminationMsg
;
406 PEPROCESS CurrentProcess
;
407 PETHREAD Thread
, OtherThread
, PreviousThread
= NULL
;
408 PVOID DeallocationStack
;
410 BOOLEAN Last
= FALSE
;
411 PTERMINATION_PORT TerminationPort
, NextPort
;
412 PLIST_ENTRY FirstEntry
, CurrentEntry
;
416 PSTRACE(PS_KILL_DEBUG
, "ExitStatus: %p\n", ExitStatus
);
418 /* Get the Current Thread and Process */
419 Thread
= PsGetCurrentThread();
420 CurrentProcess
= Thread
->ThreadsProcess
;
421 ASSERT((Thread
) == PsGetCurrentThread());
423 /* Can't terminate a thread if it attached another process */
424 if (KeIsAttachedProcess())
427 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
428 (ULONG_PTR
)CurrentProcess
,
429 (ULONG_PTR
)Thread
->Tcb
.ApcState
.Process
,
430 (ULONG_PTR
)Thread
->Tcb
.ApcStateIndex
,
434 /* Lower to Passive Level */
435 KeLowerIrql(PASSIVE_LEVEL
);
437 /* Can't be a worker thread */
438 if (Thread
->ActiveExWorker
)
441 KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION
,
448 /* Can't have pending APCs */
449 if (Thread
->Tcb
.CombinedApcDisable
!= 0)
452 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT
,
454 Thread
->Tcb
.CombinedApcDisable
,
459 /* Lock the thread */
460 ExWaitForRundownProtectionRelease(&Thread
->RundownProtect
);
462 /* Cleanup the power state */
463 PopCleanupPowerState((PPOWER_STATE
)&Thread
->Tcb
.PowerState
);
465 /* Call the WMI Callback for Threads */
466 //WmiTraceThread(Thread, NULL, FALSE);
468 /* Run Thread Notify Routines before we desintegrate the thread */
469 PspRunCreateThreadNotifyRoutines(Thread
, FALSE
);
471 /* Lock the Process before we modify its thread entries */
472 KeEnterCriticalRegion();
473 ExAcquirePushLockExclusive(&CurrentProcess
->ProcessLock
);
475 /* Decrease the active thread count, and check if it's 0 */
476 if (!(--CurrentProcess
->ActiveThreads
))
478 /* Set the delete flag */
479 InterlockedOr((PLONG
)&CurrentProcess
->Flags
, PSF_PROCESS_DELETE_BIT
);
481 /* Remember we are last */
484 /* Check if this termination is due to the thread dying */
485 if (ExitStatus
== STATUS_THREAD_IS_TERMINATING
)
487 /* Check if the last thread was pending */
488 if (CurrentProcess
->ExitStatus
== STATUS_PENDING
)
490 /* Use the last exit status */
491 CurrentProcess
->ExitStatus
= CurrentProcess
->
492 LastThreadExitStatus
;
497 /* Just a normal exit, write the code */
498 CurrentProcess
->ExitStatus
= ExitStatus
;
501 /* Loop all the current threads */
502 FirstEntry
= &CurrentProcess
->ThreadListHead
;
503 CurrentEntry
= FirstEntry
->Flink
;
504 while (FirstEntry
!= CurrentEntry
)
506 /* Get the thread on the list */
507 OtherThread
= CONTAINING_RECORD(CurrentEntry
,
511 /* Check if it's a thread that's still alive */
512 if ((OtherThread
!= Thread
) &&
513 !(KeReadStateThread(&OtherThread
->Tcb
)) &&
514 (ObReferenceObjectSafe(OtherThread
)))
516 /* It's a live thread and we referenced it, unlock process */
517 ExReleasePushLockExclusive(&CurrentProcess
->ProcessLock
);
518 KeLeaveCriticalRegion();
520 /* Wait on the thread */
521 KeWaitForSingleObject(OtherThread
,
527 /* Check if we had a previous thread to dereference */
528 if (PreviousThread
) ObDereferenceObject(PreviousThread
);
530 /* Remember the thread and re-lock the process */
531 PreviousThread
= OtherThread
;
532 KeEnterCriticalRegion();
533 ExAcquirePushLockExclusive(&CurrentProcess
->ProcessLock
);
536 /* Go to the next thread */
537 CurrentEntry
= CurrentEntry
->Flink
;
540 else if (ExitStatus
!= STATUS_THREAD_IS_TERMINATING
)
542 /* Write down the exit status of the last thread to get killed */
543 CurrentProcess
->LastThreadExitStatus
= ExitStatus
;
546 /* Unlock the Process */
547 ExReleasePushLockExclusive(&CurrentProcess
->ProcessLock
);
548 KeLeaveCriticalRegion();
550 /* Check if we had a previous thread to dereference */
551 if (PreviousThread
) ObDereferenceObject(PreviousThread
);
553 /* Check if the process has a debug port and if this is a user thread */
554 if ((CurrentProcess
->DebugPort
) && !(Thread
->SystemThread
))
556 /* Notify the Debug API. */
557 Last
? DbgkExitProcess(CurrentProcess
->ExitStatus
) :
558 DbgkExitThread(ExitStatus
);
561 /* Check if this is a Critical Thread */
562 if ((KdDebuggerEnabled
) && (Thread
->BreakOnTermination
))
564 /* Break to debugger */
565 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
567 CurrentProcess
->ImageFileName
);
570 /* Check if it's the last thread and this is a Critical Process */
571 if ((Last
) && (CurrentProcess
->BreakOnTermination
))
573 /* Check if a debugger is here to handle this */
574 if (KdDebuggerEnabled
)
576 /* Break to debugger */
577 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n",
579 CurrentProcess
->ImageFileName
);
583 /* Bugcheck, we can't allow this */
584 KEBUGCHECKEX(CRITICAL_PROCESS_DIED
,
585 (ULONG_PTR
)CurrentProcess
,
593 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
595 /* Process the Termination Ports */
596 TerminationPort
= Thread
->TerminationPort
;
599 /* Setup the message header */
600 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
601 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
602 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
603 sizeof(PORT_MESSAGE
);
608 /* Save the Create Time */
609 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
611 /* Loop trying to send message */
614 /* Send the LPC Message */
615 Status
= LpcRequestPort(TerminationPort
->Port
,
617 if ((Status
== STATUS_NO_MEMORY
) ||
618 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
620 /* Wait a bit and try again */
621 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTime
);
627 /* Dereference this LPC Port */
628 ObDereferenceObject(TerminationPort
->Port
);
630 /* Move to the next one */
631 NextPort
= TerminationPort
->Next
;
633 /* Free the Termination Port Object */
634 ExFreePool(TerminationPort
);
636 /* Keep looping as long as there is a port */
637 TerminationPort
= NextPort
;
638 } while (TerminationPort
);
640 else if (((ExitStatus
== STATUS_THREAD_IS_TERMINATING
) &&
641 (Thread
->DeadThread
)) ||
642 !(Thread
->DeadThread
))
645 * This case is special and deserves some extra comments. What
646 * basically happens here is that this thread doesn't have a termination
647 * port, which means that it died before being fully created. Since we
648 * still have to notify an LPC Server, we'll use the exception port,
649 * which we know exists. However, we need to know how far the thread
650 * actually got created. We have three possibilites:
652 * - NtCreateThread returned an error really early: DeadThread is set.
653 * - NtCreateThread managed to create the thread: DeadThread is off.
654 * - NtCreateThread was creating the thread (with Deadthread set,
655 * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING
658 * For the 2 & 3rd scenarios, the thread has been created far enough to
659 * warrant notification to the LPC Server.
662 /* Setup the message header */
663 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
664 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
665 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
666 sizeof(PORT_MESSAGE
);
668 /* Make sure the process has an exception port */
669 if (CurrentProcess
->ExceptionPort
)
671 /* Save the Create Time */
672 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
674 /* Loop trying to send message */
677 /* Send the LPC Message */
678 Status
= LpcRequestPort(CurrentProcess
->ExceptionPort
,
680 if ((Status
== STATUS_NO_MEMORY
) ||
681 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
683 /* Wait a bit and try again */
684 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTime
);
692 /* Rundown Win32 Thread if there is one */
693 if (Thread
->Tcb
.Win32Thread
) PspW32ThreadCallout(Thread
,
694 PsW32ThreadCalloutExit
);
696 /* If we are the last thread and have a W32 Process */
697 if ((Last
) && (CurrentProcess
->Win32Process
))
699 /* Run it down too */
700 PspW32ProcessCallout(CurrentProcess
, FALSE
);
703 /* Make sure Stack Swap isn't enabled */
704 if (Thread
->Tcb
.EnableStackSwap
)
706 /* Stack swap really shouldn't be on during exit !*/
707 KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT
, 0, 0, 0, 0);
710 /* Cancel I/O for the thread. */
711 IoCancelThreadIo(Thread
);
716 /* FIXME: Rundown Registry Notifications (NtChangeNotify)
717 CmNotifyRunDown(Thread); */
719 /* Rundown Mutexes */
722 /* Check if we have a TEB */
723 Teb
= Thread
->Tcb
.Teb
;
726 /* Check if the thread is still alive */
727 if (!Thread
->DeadThread
)
729 /* Check if we need to free its stack */
730 if (Teb
->FreeStackOnTermination
)
732 /* Set the TEB's Deallocation Stack as the Base Address */
734 DeallocationStack
= Teb
->DeallocationStack
;
736 /* Free the Thread's Stack */
737 ZwFreeVirtualMemory(NtCurrentProcess(),
743 /* Free the debug handle */
744 if (Teb
->DbgSsReserved
[1]) ObCloseHandle(Teb
->DbgSsReserved
[1],
748 /* Decommit the TEB */
749 MmDeleteTeb(CurrentProcess
, Teb
);
750 Thread
->Tcb
.Teb
= NULL
;
754 LpcExitThread(Thread
);
756 /* Save the exit status and exit time */
757 Thread
->ExitStatus
= ExitStatus
;
758 KeQuerySystemTime(&Thread
->ExitTime
);
761 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
763 /* Check if this is the final thread or not */
766 /* Set the process exit time */
767 CurrentProcess
->ExitTime
= Thread
->ExitTime
;
769 /* Exit the process */
770 PspExitProcess(TRUE
, CurrentProcess
);
772 /* Get the process token and check if we need to audit */
773 PrimaryToken
= PsReferencePrimaryToken(CurrentProcess
);
774 if (SeDetailedAuditingWithToken(PrimaryToken
))
777 SeAuditProcessExit(CurrentProcess
);
780 /* Dereference the process token */
781 ObFastDereferenceObject(&CurrentProcess
->Token
, PrimaryToken
);
783 /* Check if this is a VDM Process and rundown the VDM DPCs if so */
784 if (CurrentProcess
->VdmObjects
);// VdmRundownDpcs(CurrentProcess);
786 /* Kill the process in the Object Manager */
787 ObKillProcess(CurrentProcess
);
789 /* Check if we have a section object */
790 if (CurrentProcess
->SectionObject
)
792 /* Dereference and clear the Section Object */
793 ObDereferenceObject(CurrentProcess
->SectionObject
);
794 CurrentProcess
->SectionObject
= NULL
;
797 /* Check if the process is part of a job */
798 if (CurrentProcess
->Job
)
800 /* Remove the process from the job */
801 PspExitProcessFromJob(CurrentProcess
->Job
, CurrentProcess
);
806 KeEnterCriticalRegion();
808 /* Disable APC queueing, force a resumption */
809 Thread
->Tcb
.ApcQueueable
= FALSE
;
810 KeForceResumeThread(&Thread
->Tcb
);
813 KeLeaveCriticalRegion();
815 /* Flush the User APCs */
816 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, UserMode
);
819 /* Start with the first entry */
820 CurrentEntry
= FirstEntry
;
824 Apc
= CONTAINING_RECORD(CurrentEntry
, KAPC
, ApcListEntry
);
826 /* Move to the next one */
827 CurrentEntry
= CurrentEntry
->Flink
;
829 /* Rundown the APC or de-allocate it */
830 if (Apc
->RundownRoutine
)
832 /* Call its own routine */
833 Apc
->RundownRoutine(Apc
);
837 /* Do it ourselves */
841 while (CurrentEntry
!= FirstEntry
);
844 /* Clean address space if this was the last thread */
845 if (Last
) MmCleanProcessAddressSpace(CurrentProcess
);
847 /* Call the Lego routine */
848 if (Thread
->Tcb
.LegoData
) PspRunLegoRoutine(&Thread
->Tcb
);
850 /* Flush the APC queue, which should be empty */
851 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, KernelMode
);
852 if ((FirstEntry
) || (Thread
->Tcb
.CombinedApcDisable
!= 0))
855 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT
,
856 (ULONG_PTR
)FirstEntry
,
857 Thread
->Tcb
.CombinedApcDisable
,
862 /* Signal the process if this was the last thread */
863 if (Last
) KeSetProcess(&CurrentProcess
->Pcb
, 0, FALSE
);
865 /* Terminate the Thread from the Scheduler */
866 KeTerminateThread(0);
871 PsExitSpecialApc(IN PKAPC Apc
,
872 IN OUT PKNORMAL_ROUTINE
* NormalRoutine
,
873 IN OUT PVOID
* NormalContext
,
874 IN OUT PVOID
* SystemArgument1
,
875 IN OUT PVOID
* SystemArgument2
)
879 PSTRACE(PS_KILL_DEBUG
,
880 "Apc: %p SystemArgument2: %p \n", Apc
, SystemArgument2
);
882 /* Don't do anything unless we are in User-Mode */
883 if (Apc
->SystemArgument2
)
886 Status
= (NTSTATUS
)Apc
->NormalContext
;
887 PspExitApcRundown(Apc
);
889 /* Terminate the Thread */
890 PspExitThread(Status
);
896 PspExitNormalApc(IN PVOID NormalContext
,
897 IN PVOID SystemArgument1
,
898 IN PVOID SystemArgument2
)
900 PKAPC Apc
= (PKAPC
)SystemArgument1
;
901 PETHREAD Thread
= PsGetCurrentThread();
903 PSTRACE(PS_KILL_DEBUG
, "SystemArgument2: %p \n", SystemArgument2
);
905 /* This should never happen */
906 ASSERT(!(((ULONG_PTR
)SystemArgument2
) & 1));
908 /* If we're here, this is not a System Thread, so kill it from User-Mode */
911 OriginalApcEnvironment
,
918 /* Now insert the APC with the User-Mode Flag */
919 if (!(KeInsertQueueApc(Apc
,
921 (PVOID
)((ULONG_PTR
)SystemArgument2
| 1),
924 /* Failed to insert, free the APC */
925 PspExitApcRundown(Apc
);
928 /* Set the APC Pending flag */
929 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
933 * See "Windows Internals" - Chapter 13, Page 49
937 PspTerminateThreadByPointer(IN PETHREAD Thread
,
938 IN NTSTATUS ExitStatus
,
942 NTSTATUS Status
= STATUS_SUCCESS
;
945 PSTRACE(PS_KILL_DEBUG
, "Thread: %p ExitStatus: %p\n", Thread
, ExitStatus
);
948 /* Check if this is a Critical Thread, and Bugcheck */
949 if (Thread
->BreakOnTermination
)
951 /* Break to debugger */
952 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
954 Thread
->ThreadsProcess
->ImageFileName
);
957 /* Check if we are already inside the thread */
958 if ((bSelf
) || (PsGetCurrentThread() == Thread
))
960 /* This should only happen at passive */
961 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
963 /* Mark it as terminated */
964 PspSetCrossThreadFlag(Thread
, CT_TERMINATED_BIT
);
966 /* Directly terminate the thread */
967 PspExitThread(ExitStatus
);
970 /* This shouldn't be a system thread */
971 if (Thread
->SystemThread
) return STATUS_ACCESS_DENIED
;
973 /* Allocate the APC */
974 Apc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG_TERMINATE_APC
);
976 /* Set the Terminated Flag */
977 Flags
= Thread
->CrossThreadFlags
| CT_TERMINATED_BIT
;
979 /* Set it, and check if it was already set while we were running */
980 if (!(InterlockedExchange((PLONG
)&Thread
->CrossThreadFlags
, Flags
) &
983 /* Initialize a Kernel Mode APC to Kill the Thread */
986 OriginalApcEnvironment
,
993 /* Insert it into the APC Queue */
994 if (!KeInsertQueueApc(Apc
, Apc
, NULL
, 2))
996 /* The APC was already in the queue, fail */
998 Status
= STATUS_UNSUCCESSFUL
;
1002 /* Forcefully resume the thread and return */
1003 KeForceResumeThread(&Thread
->Tcb
);
1008 /* We failed, free the APC */
1017 PspExitProcess(IN BOOLEAN LastThread
,
1018 IN PEPROCESS Process
)
1022 PSTRACE(PS_KILL_DEBUG
,
1023 "LastThread: %p Process: %p\n", LastThread
, Process
);
1024 PSREFTRACE(Process
);
1026 /* Set Process Exit flag */
1027 InterlockedOr((PLONG
)&Process
->Flags
, PSF_PROCESS_EXITING_BIT
);
1029 /* Check if we are the last thread */
1032 /* Notify the WMI Process Callback */
1033 //WmiTraceProcess(Process, FALSE);
1035 /* Run the Notification Routines */
1036 PspRunCreateProcessNotifyRoutines(Process
, FALSE
);
1039 /* Cleanup the power state */
1040 PopCleanupPowerState((PPOWER_STATE
)&Process
->Pcb
.PowerState
);
1042 /* Clear the security port */
1043 if (!Process
->SecurityPort
)
1045 /* So we don't double-dereference */
1046 Process
->SecurityPort
= (PVOID
)1;
1048 else if (Process
->SecurityPort
!= (PVOID
)1)
1050 /* Dereference it */
1051 ObDereferenceObject(Process
->SecurityPort
);
1052 Process
->SecurityPort
= (PVOID
)1;
1055 /* Check if we are the last thread */
1058 /* Check if we have to set the Timer Resolution */
1059 if (Process
->SetTimerResolution
)
1061 /* Set it to default */
1062 ZwSetTimerResolution(KeMaximumIncrement
, 0, &Actual
);
1065 /* Check if we are part of a Job that has a completion port */
1066 if ((Process
->Job
) && (Process
->Job
->CompletionPort
))
1068 /* FIXME: Check job status code and do I/O completion if needed */
1071 /* FIXME: Notify the Prefetcher */
1075 /* Clear process' address space here */
1076 MmCleanProcessAddressSpace(Process
);
1080 /* PUBLIC FUNCTIONS **********************************************************/
1087 PsTerminateSystemThread(IN NTSTATUS ExitStatus
)
1089 PETHREAD Thread
= PsGetCurrentThread();
1091 /* Make sure this is a system thread */
1092 if (Thread
->SystemThread
) return STATUS_INVALID_PARAMETER
;
1094 /* Terminate it for real */
1095 return PspTerminateThreadByPointer(Thread
, ExitStatus
, TRUE
);
1103 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL
,
1104 IN NTSTATUS ExitStatus
)
1107 PEPROCESS Process
, CurrentProcess
= PsGetCurrentProcess();
1108 PETHREAD Thread
, CurrentThread
= PsGetCurrentThread();
1109 BOOLEAN KillByHandle
;
1111 PSTRACE(PS_KILL_DEBUG
,
1112 "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle
, ExitStatus
);
1114 /* Remember how we will kill it */
1115 KillByHandle
= (ProcessHandle
!= NULL
);
1117 /* Get the Process Object */
1118 Status
= ObReferenceObjectByHandle((KillByHandle
) ?
1119 ProcessHandle
: NtCurrentProcess(),
1122 KeGetPreviousMode(),
1125 if (!NT_SUCCESS(Status
)) return(Status
);
1127 /* Check if this is a Critical Process, and Bugcheck */
1128 if (Process
->BreakOnTermination
)
1130 /* Break to debugger */
1131 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
1133 Process
->ImageFileName
);
1136 /* Lock the Process */
1137 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
1139 /* Failed to lock, fal */
1140 ObDereferenceObject (Process
);
1141 return STATUS_PROCESS_IS_TERMINATING
;
1144 /* Set the delete flag */
1145 if (!KillByHandle
) InterlockedOr((PLONG
)&Process
->Flags
,
1146 PSF_PROCESS_DELETE_BIT
);
1148 /* Get the first thread */
1149 Status
= STATUS_NOTHING_TO_TERMINATE
;
1150 Thread
= PsGetNextProcessThread(Process
, NULL
);
1153 /* We know we have at least a thread */
1154 Status
= STATUS_SUCCESS
;
1156 /* Loop and kill the others */
1159 /* Ensure it's not ours*/
1160 if (Thread
!= CurrentThread
)
1163 PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1166 /* Move to the next thread */
1167 Thread
= PsGetNextProcessThread(Process
, Thread
);
1171 /* Unlock the process */
1172 ExReleaseRundownProtection(&Process
->RundownProtect
);
1174 /* Check if we are killing ourselves */
1175 if (Process
!= CurrentProcess
)
1177 /* Check for the DBG_TERMINATE_PROCESS exit code */
1178 if (ExitStatus
== DBG_TERMINATE_PROCESS
)
1180 /* Disable debugging on this process */
1181 DbgkClearProcessDebugObject(Process
, NULL
);
1184 /* Make sure that we got a handle */
1185 else if (KillByHandle
)
1187 /* Dereference the project */
1188 ObDereferenceObject(Process
);
1190 /* Terminate ourselves */
1191 PspTerminateThreadByPointer(CurrentThread
, ExitStatus
, TRUE
);
1194 /* Check if there was nothing to terminate, or if we have a Debug Port */
1195 if ((Status
== STATUS_NOTHING_TO_TERMINATE
) ||
1196 ((Process
->DebugPort
) && (KillByHandle
)))
1198 /* Clear the handle table */
1199 ObClearProcessHandleTable(Process
);
1201 /* Return status now */
1202 Status
= STATUS_SUCCESS
;
1205 /* Decrease the reference count we added */
1206 ObDereferenceObject(Process
);
1214 NtTerminateThread(IN HANDLE ThreadHandle
,
1215 IN NTSTATUS ExitStatus
)
1218 PETHREAD CurrentThread
= PsGetCurrentThread();
1221 PSTRACE(PS_KILL_DEBUG
,
1222 "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle
, ExitStatus
);
1224 /* Handle the special NULL case */
1227 /* Check if we're the only thread left */
1228 if (PsGetCurrentProcess()->ActiveThreads
== 1)
1230 /* This is invalid */
1231 return STATUS_CANT_TERMINATE_SELF
;
1234 /* Terminate us directly */
1237 else if (ThreadHandle
== NtCurrentThread())
1240 /* Terminate this thread */
1241 return PspTerminateThreadByPointer(CurrentThread
,
1246 /* We are terminating another thread, get the Thread Object */
1247 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1250 KeGetPreviousMode(),
1253 if (!NT_SUCCESS(Status
)) return Status
;
1255 /* Check to see if we're running in the same thread */
1256 if (Thread
!= CurrentThread
)
1259 Status
= PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1261 /* Dereference the Thread and return */
1262 ObDereferenceObject(Thread
);
1266 /* Dereference the thread and terminate ourselves */
1267 ObDereferenceObject(Thread
);
1277 NtRegisterThreadTerminatePort(IN HANDLE PortHandle
)
1280 PTERMINATION_PORT TerminationPort
;
1281 PVOID TerminationLpcPort
;
1284 PSTRACE(PS_KILL_DEBUG
, "PortHandle: %p\n", PortHandle
);
1287 Status
= ObReferenceObjectByHandle(PortHandle
,
1290 KeGetPreviousMode(),
1291 &TerminationLpcPort
,
1293 if (!NT_SUCCESS(Status
)) return(Status
);
1295 /* Allocate the Port and make sure it suceeded */
1296 TerminationPort
= ExAllocatePoolWithTag(NonPagedPool
,
1297 sizeof(TERMINATION_PORT
),
1298 TAG('P', 's', 'T', '='));
1301 /* Associate the Port */
1302 Thread
= PsGetCurrentThread();
1303 TerminationPort
->Port
= TerminationLpcPort
;
1304 TerminationPort
->Next
= Thread
->TerminationPort
;
1305 Thread
->TerminationPort
= TerminationPort
;
1307 /* Return success */
1308 return STATUS_SUCCESS
;
1311 /* Dereference and Fail */
1312 ObDereferenceObject(TerminationPort
);
1313 return STATUS_INSUFFICIENT_RESOURCES
;