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
;
22 /* PRIVATE FUNCTIONS *********************************************************/
26 PspCatchCriticalBreak(IN PCHAR Message
,
27 IN PVOID ProcessOrThread
,
31 BOOLEAN Handled
= FALSE
;
34 /* Check if a debugger is enabled */
35 if (KdDebuggerEnabled
)
37 /* Print out the message */
38 DbgPrint(Message
, ProcessOrThread
, ImageName
);
41 /* If a debugger isn't present, don't prompt */
42 if (KdDebuggerNotPresent
) break;
44 /* A debuger is active, prompt for action */
45 DbgPrompt("Break, or Ignore (bi)?", Action
, sizeof(Action
));
67 /* Did we ultimately handle this? */
70 /* We didn't, bugcheck */
71 KeBugCheckEx(CRITICAL_OBJECT_TERMINATION
,
72 ((PKPROCESS
)ProcessOrThread
)->Header
.Type
,
73 (ULONG_PTR
)ProcessOrThread
,
81 PspTerminateProcess(IN PEPROCESS Process
,
82 IN NTSTATUS ExitStatus
)
84 PETHREAD Thread
= NULL
;
86 PSTRACE(PS_KILL_DEBUG
,
87 "Process: %p ExitStatus: %p\n", Process
, ExitStatus
);
90 /* Check if this is a Critical Process */
91 if (Process
->BreakOnTermination
)
93 /* Break to debugger */
94 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
96 Process
->ImageFileName
);
99 /* Set the delete flag */
100 InterlockedOr((PLONG
)&Process
->Flags
, PSF_PROCESS_DELETE_BIT
);
102 /* Get the first thread */
103 Thread
= PsGetNextProcessThread(Process
, Thread
);
108 PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
110 Thread
= PsGetNextProcessThread(Process
, Thread
);
113 /* Clear the handle table */
114 if (Process
->ObjectTable
) ObClearProcessHandleTable(Process
);
118 return STATUS_SUCCESS
;
123 PsTerminateProcess(IN PEPROCESS Process
,
124 IN NTSTATUS ExitStatus
)
126 /* Call the internal API */
127 return PspTerminateProcess(Process
, ExitStatus
);
132 PspShutdownProcessManager(VOID
)
134 PEPROCESS Process
= NULL
;
136 /* Loop every process */
137 Process
= PsGetNextProcess(Process
);
140 /* Make sure this isn't the idle or initial process */
141 if ((Process
!= PsInitialSystemProcess
) && (Process
!= PsIdleProcess
))
144 PspTerminateProcess(Process
, STATUS_SYSTEM_SHUTDOWN
);
147 /* Get the next process */
148 Process
= PsGetNextProcess(Process
);
154 PspExitApcRundown(IN PKAPC Apc
)
164 PspReapRoutine(IN PVOID Context
)
166 PLIST_ENTRY
*ListAddr
;
167 PLIST_ENTRY NextEntry
;
169 PSTRACE(PS_KILL_DEBUG
, "Context: %p\n", Context
);
171 /* Get the Reaper Address Pointer */
172 ListAddr
= &PspReaperListHead
.Flink
;
174 /* Start main loop */
177 /* Write magic value and return the next entry to process */
178 NextEntry
= InterlockedExchangePointer(ListAddr
, (PVOID
)1);
179 ASSERT((NextEntry
!= NULL
) && (NextEntry
!= (PVOID
)1));
181 /* Start inner loop */
184 /* Get the first Thread Entry */
185 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, ReaperLink
);
187 /* Delete this entry's kernel stack */
188 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackLimit
,
189 Thread
->Tcb
.LargeStack
);
190 Thread
->Tcb
.InitialStack
= NULL
;
192 /* Move to the next entry */
193 NextEntry
= NextEntry
->Flink
;
195 /* Dereference this thread */
196 ObDereferenceObject(Thread
);
198 } while ((NextEntry
!= NULL
) && (NextEntry
!= (PVOID
)1));
200 /* Remove magic value, keep looping if it got changed */
201 } while (InterlockedCompareExchangePointer(ListAddr
, 0, 1) != (PVOID
)1);
206 PspDeleteProcess(IN PVOID ObjectBody
)
208 PEPROCESS Process
= (PEPROCESS
)ObjectBody
;
211 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
214 /* Check if it has an Active Process Link */
215 if (Process
->ActiveProcessLinks
.Flink
)
217 /* Remove it from the Active List */
218 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
219 RemoveEntryList(&Process
->ActiveProcessLinks
);
220 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
223 /* Check for Auditing information */
224 if (Process
->SeAuditProcessCreationInfo
.ImageFileName
)
227 ExFreePool(Process
->SeAuditProcessCreationInfo
.ImageFileName
);
228 Process
->SeAuditProcessCreationInfo
.ImageFileName
= NULL
;
231 /* Check if we have a job */
234 /* Remove the process from the job */
235 PspRemoveProcessFromJob(Process
, Process
->Job
);
238 ObDereferenceObject(Process
->Job
);
242 /* Increase the stack count */
243 Process
->Pcb
.StackCount
++;
245 /* Check if we have a debug port */
246 if (Process
->DebugPort
)
248 /* Dererence the Debug Port */
249 ObDereferenceObject(Process
->DebugPort
);
250 Process
->DebugPort
= NULL
;
253 /* Check if we have an exception port */
254 if (Process
->ExceptionPort
)
256 /* Dererence the Exception Port */
257 ObDereferenceObject(Process
->ExceptionPort
);
258 Process
->ExceptionPort
= NULL
;
261 /* Check if we have a section object */
262 if (Process
->SectionObject
)
264 /* Dererence the Section Object */
265 ObDereferenceObject(Process
->SectionObject
);
266 Process
->SectionObject
= NULL
;
269 /* Clean LDT and VDM_OBJECTS */
270 PspDeleteLdt(Process
);
271 PspDeleteVdmObjects(Process
);
273 /* Delete the Object Table */
274 if (Process
->ObjectTable
)
276 /* Attach to the process */
277 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
279 /* Kill the Object Info */
280 ObKillProcess(Process
);
283 KeUnstackDetachProcess(&ApcState
);
287 KDB_DELETEPROCESS_HOOK(Process
);
289 /* Check if we have an address space, and clean it */
290 if (Process
->HasAddressSpace
)
292 /* Attach to the process */
293 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
295 /* Clean the Address Space */
296 PspExitProcess(FALSE
, Process
);
299 KeUnstackDetachProcess(&ApcState
);
301 /* Completely delete the Address Space */
302 MmDeleteProcessAddressSpace(Process
);
305 /* See if we have a PID */
306 if(Process
->UniqueProcessId
)
309 if (!(ExDestroyHandle(PspCidTable
, Process
->UniqueProcessId
)))
311 /* Something wrong happened, bugcheck */
312 KEBUGCHECK(CID_HANDLE_DELETION
);
316 /* Cleanup security information */
317 PspDeleteProcessSecurity(Process
);
319 /* Check if we have kept information on the Working Set */
320 if (Process
->WorkingSetWatch
)
323 ExFreePool(Process
->WorkingSetWatch
);
325 /* And return the quota it was taking up */
326 PsReturnProcessNonPagedPoolQuota(Process
, 0x2000);
329 /* Dereference the Device Map */
330 ObDereferenceDeviceMap(Process
);
332 /* Destroy the Quota Block */
333 PspDestroyQuotaBlock(Process
);
339 PspDeleteThread(IN PVOID ObjectBody
)
341 PETHREAD Thread
= (PETHREAD
)ObjectBody
;
342 PEPROCESS Process
= Thread
->ThreadsProcess
;
344 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
346 ASSERT(Thread
->Tcb
.Win32Thread
== NULL
);
348 /* Check if we have a stack */
349 if (Thread
->Tcb
.InitialStack
)
352 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackLimit
,
353 Thread
->Tcb
.LargeStack
);
356 /* Check if we have a CID Handle */
357 if (Thread
->Cid
.UniqueThread
)
359 /* Delete the CID Handle */
360 if (!(ExDestroyHandle(PspCidTable
, Thread
->Cid
.UniqueThread
)))
362 /* Something wrong happened, bugcheck */
363 KEBUGCHECK(CID_HANDLE_DELETION
);
367 /* Cleanup impersionation information */
368 PspDeleteThreadSecurity(Thread
);
370 /* Make sure the thread was inserted, before continuing */
372 if (!Process
) return;
374 /* Check if the thread list is valid */
375 if (Thread
->ThreadListEntry
.Flink
)
377 /* Lock the thread's process */
378 KeEnterCriticalRegion();
379 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
381 /* Remove us from the list */
382 RemoveEntryList(&Thread
->ThreadListEntry
);
384 /* Release the lock */
385 ExReleasePushLockExclusive(&Process
->ProcessLock
);
386 KeLeaveCriticalRegion();
389 /* Dereference the Process */
390 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
;
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 */
425 PSREFTRACE(CurrentProcess
);
426 if (KeIsAttachedProcess())
429 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
430 (ULONG_PTR
)CurrentProcess
,
431 (ULONG_PTR
)Thread
->Tcb
.ApcState
.Process
,
432 (ULONG_PTR
)Thread
->Tcb
.ApcStateIndex
,
436 /* Lower to Passive Level */
437 KfLowerIrql(PASSIVE_LEVEL
);
439 /* Can't be a worker thread */
440 if (Thread
->ActiveExWorker
)
443 KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION
,
450 /* Can't have pending APCs */
451 if (Thread
->Tcb
.CombinedApcDisable
!= 0)
454 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT
,
456 Thread
->Tcb
.KernelApcDisable
,
461 /* Lock the thread */
462 ExWaitForRundownProtectionRelease(&Thread
->RundownProtect
);
464 /* Cleanup the power state */
465 PopCleanupPowerState((PPOWER_STATE
)&Thread
->Tcb
.PowerState
);
467 /* Call the WMI Callback for Threads */
468 //WmiTraceThread(Thread, NULL, FALSE);
470 /* Run Thread Notify Routines before we desintegrate the thread */
471 PspRunCreateThreadNotifyRoutines(Thread
, FALSE
);
473 /* Lock the Process before we modify its thread entries */
474 KeEnterCriticalRegion();
475 ExAcquirePushLockExclusive(&CurrentProcess
->ProcessLock
);
477 /* Decrease the active thread count, and check if it's 0 */
478 if (!(--CurrentProcess
->ActiveThreads
))
480 /* Set the delete flag */
481 InterlockedOr((PLONG
)&CurrentProcess
->Flags
, PSF_PROCESS_DELETE_BIT
);
483 /* Remember we are last */
486 /* Check if this termination is due to the thread dying */
487 if (ExitStatus
== STATUS_THREAD_IS_TERMINATING
)
489 /* Check if the last thread was pending */
490 if (CurrentProcess
->ExitStatus
== STATUS_PENDING
)
492 /* Use the last exit status */
493 CurrentProcess
->ExitStatus
= CurrentProcess
->
494 LastThreadExitStatus
;
499 /* Just a normal exit, write the code */
500 CurrentProcess
->ExitStatus
= ExitStatus
;
503 /* FIXME: Wait on the other threads to finish */
505 else if (ExitStatus
!= STATUS_THREAD_IS_TERMINATING
)
507 /* Write down the exit status of the last thread to get killed */
508 CurrentProcess
->LastThreadExitStatus
= ExitStatus
;
511 /* Unlock the Process */
512 ExReleasePushLockExclusive(&CurrentProcess
->ProcessLock
);
513 KeLeaveCriticalRegion();
515 /* Check if the process has a debug port and if this is a user thread */
516 if ((CurrentProcess
->DebugPort
) && !(Thread
->SystemThread
))
518 /* Notify the Debug API. */
519 Last
? DbgkExitProcess(CurrentProcess
->ExitStatus
) :
520 DbgkExitThread(ExitStatus
);
523 /* Check if this is a Critical Thread */
524 if ((KdDebuggerEnabled
) && (Thread
->BreakOnTermination
))
526 /* Break to debugger */
527 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
529 CurrentProcess
->ImageFileName
);
532 /* Check if it's the last thread and this is a Critical Process */
533 if ((Last
) && (CurrentProcess
->BreakOnTermination
))
535 /* Check if a debugger is here to handle this */
536 if (KdDebuggerEnabled
)
538 /* Break to debugger */
539 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n",
541 CurrentProcess
->ImageFileName
);
545 /* Bugcheck, we can't allow this */
546 KEBUGCHECKEX(CRITICAL_PROCESS_DIED
,
547 (ULONG_PTR
)CurrentProcess
,
555 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
557 /* Process the Termination Ports */
558 TerminationPort
= Thread
->TerminationPort
;
561 /* Setup the message header */
562 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
563 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
564 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
565 sizeof(PORT_MESSAGE
);
570 /* Save the Create Time */
571 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
574 /* Send the LPC Message */
575 Status
= LpcRequestPort(TerminationPort
->Port
, &TerminationMsg
.h
);
576 if ((Status
== STATUS_NO_MEMORY
) ||
577 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
579 /* Wait a bit and try again */
580 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
584 /* Dereference this LPC Port */
585 ObDereferenceObject(TerminationPort
->Port
);
587 /* Move to the next one */
588 NextPort
= TerminationPort
->Next
;
590 /* Free the Termination Port Object */
591 ExFreePool(TerminationPort
);
593 /* Keep looping as long as there is a port */
594 } while ((TerminationPort
= NextPort
));
596 else if (((ExitStatus
== STATUS_THREAD_IS_TERMINATING
) &&
597 (Thread
->DeadThread
)) ||
598 !(Thread
->DeadThread
))
601 * This case is special and deserves some extra comments. What
602 * basically happens here is that this thread doesn't have a termination
603 * port, which means that it died before being fully created. Since we
604 * still have to notify an LPC Server, we'll use the exception port,
605 * which we know exists. However, we need to know how far the thread
606 * actually got created. We have three possibilites:
608 * - NtCreateThread returned an error really early: DeadThread is set.
609 * - NtCreateThread managed to create the thread: DeadThread is off.
610 * - NtCreateThread was creating the thread (with Deadthread set,
611 * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING
614 * For the 2 & 3rd scenarios, the thread has been created far enough to
615 * warrant notification to the LPC Server.
618 /* Setup the message header */
619 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
620 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
621 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
622 sizeof(PORT_MESSAGE
);
624 /* Make sure the process has an exception port */
625 if (CurrentProcess
->ExceptionPort
)
627 /* Save the Create Time */
628 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
631 /* Send the LPC Message */
632 Status
= LpcRequestPort(CurrentProcess
->ExceptionPort
,
634 if ((Status
== STATUS_NO_MEMORY
) ||
635 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
637 /* Wait a bit and try again */
638 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
644 /* Rundown Win32 Thread if there is one */
645 if (Thread
->Tcb
.Win32Thread
) PspW32ThreadCallout(Thread
,
646 PsW32ThreadCalloutExit
);
648 /* If we are the last thread and have a W32 Process */
650 if ((Last
) && (CurrentProcess
->Win32Process
))
652 /* Run it down too */
653 PspW32ProcessCallout(CurrentProcess
, FALSE
);
656 /* Make sure Stack Swap isn't enabled */
657 if (Thread
->Tcb
.EnableStackSwap
)
659 /* Stack swap really shouldn't be on during exit !*/
660 KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT
, 0, 0, 0, 0);
663 /* Cancel I/O for the thread. */
664 IoCancelThreadIo(Thread
);
669 /* FIXME: Rundown Registry Notifications (NtChangeNotify)
670 CmNotifyRunDown(Thread); */
672 /* Rundown Mutexes */
675 /* Check if we have a TEB */
676 Teb
= Thread
->Tcb
.Teb
;
679 /* Check if the thread isn't terminated and if we should free stack */
680 if (!(Thread
->Terminated
) && (Teb
->FreeStackOnTermination
))
682 /* Set the TEB's Deallocation Stack as the Base Address */
684 DeallocationStack
= Teb
->DeallocationStack
;
686 /* Free the Thread's Stack */
687 ZwFreeVirtualMemory(NtCurrentProcess(),
693 /* Free the debug handle */
694 if (Teb
->DbgSsReserved
[1]) ObCloseHandle(Teb
->DbgSsReserved
[1],
697 /* Decommit the TEB */
698 MmDeleteTeb(CurrentProcess
, Teb
);
699 Thread
->Tcb
.Teb
= NULL
;
703 LpcExitThread(Thread
);
705 /* Save the exit status and exit time */
706 Thread
->ExitStatus
= ExitStatus
;
707 KeQuerySystemTime(&Thread
->ExitTime
);
710 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
712 /* Check if this is the final thread or not */
714 PSREFTRACE(CurrentProcess
);
717 /* Set the process exit time */
718 CurrentProcess
->ExitTime
= Thread
->ExitTime
;
720 /* Exit the process */
721 PspExitProcess(TRUE
, CurrentProcess
);
723 /* Get the process token and check if we need to audit */
724 PrimaryToken
= PsReferencePrimaryToken(CurrentProcess
);
725 if (SeDetailedAuditingWithToken(PrimaryToken
))
728 SeAuditProcessExit(CurrentProcess
);
731 /* Dereference the process token */
732 ObFastDereferenceObject(&CurrentProcess
->Token
, PrimaryToken
);
734 /* Check if this is a VDM Process and rundown the VDM DPCs if so */
735 if (CurrentProcess
->VdmObjects
);// VdmRundownDpcs(CurrentProcess);
737 /* Kill the process in the Object Manager */
738 ObKillProcess(CurrentProcess
);
739 PSREFTRACE(CurrentProcess
);
741 /* Check if we have a section object */
742 if (CurrentProcess
->SectionObject
)
744 /* Dereference and clear the Section Object */
745 ObDereferenceObject(CurrentProcess
->SectionObject
);
746 CurrentProcess
->SectionObject
= NULL
;
749 /* Check if the process is part of a job */
750 if (CurrentProcess
->Job
)
752 /* Remove the process from the job */
753 PspExitProcessFromJob(CurrentProcess
->Job
, CurrentProcess
);
758 KeEnterCriticalRegion();
760 /* Disable APC queueing, force a resumption */
761 Thread
->Tcb
.ApcQueueable
= FALSE
;
762 KeForceResumeThread(&Thread
->Tcb
);
765 KeLeaveCriticalRegion();
767 /* Flush the User APCs */
768 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, UserMode
);
771 CurrentEntry
= FirstEntry
;
775 Apc
= CONTAINING_RECORD(CurrentEntry
, KAPC
, ApcListEntry
);
777 /* Move to the next one */
778 CurrentEntry
= CurrentEntry
->Flink
;
780 /* Rundown the APC or de-allocate it */
781 if (Apc
->RundownRoutine
)
783 /* Call its own routine */
784 (Apc
->RundownRoutine
)(Apc
);
788 /* Do it ourselves */
792 while (CurrentEntry
!= FirstEntry
);
795 /* Clean address space if this was the last thread */
796 if (Last
) MmCleanProcessAddressSpace(CurrentProcess
);
798 /* Call the Lego routine */
799 if (Thread
->Tcb
.LegoData
) PspRunLegoRoutine(&Thread
->Tcb
);
801 /* Flush the APC queue, which should be empty */
802 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, KernelMode
);
806 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT
,
807 (ULONG_PTR
)FirstEntry
,
808 Thread
->Tcb
.KernelApcDisable
,
813 /* Signal the process if this was the last thread */
814 if (Last
) KeSetProcess(&CurrentProcess
->Pcb
, 0, FALSE
);
816 /* Terminate the Thread from the Scheduler */
818 PSREFTRACE(CurrentProcess
);
819 KeTerminateThread(0);
824 PsExitSpecialApc(IN PKAPC Apc
,
825 IN OUT PKNORMAL_ROUTINE
* NormalRoutine
,
826 IN OUT PVOID
* NormalContext
,
827 IN OUT PVOID
* SystemArgument1
,
828 IN OUT PVOID
* SystemArgument2
)
832 PSTRACE(PS_KILL_DEBUG
,
833 "Apc: %p SystemArgument2: %p \n", Apc
, SystemArgument2
);
835 /* Don't do anything unless we are in User-Mode */
836 if (Apc
->SystemArgument2
)
839 Status
= (NTSTATUS
)Apc
->NormalContext
;
840 PspExitApcRundown(Apc
);
842 /* Terminate the Thread */
843 PspExitThread(Status
);
849 PspExitNormalApc(IN PVOID NormalContext
,
850 IN PVOID SystemArgument1
,
851 IN PVOID SystemArgument2
)
853 PKAPC Apc
= (PKAPC
)SystemArgument1
;
854 PETHREAD Thread
= PsGetCurrentThread();
856 PSTRACE(PS_KILL_DEBUG
, "SystemArgument2: %p \n", SystemArgument2
);
858 /* This should never happen */
859 ASSERT(!(((ULONG_PTR
)SystemArgument2
) & 1));
861 /* If we're here, this is not a System Thread, so kill it from User-Mode */
864 OriginalApcEnvironment
,
871 /* Now insert the APC with the User-Mode Flag */
872 if (!(KeInsertQueueApc(Apc
,
874 (PVOID
)((ULONG_PTR
)SystemArgument2
| 1),
877 /* Failed to insert, free the APC */
878 PspExitApcRundown(Apc
);
881 /* Set the APC Pending flag */
882 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
886 * See "Windows Internals" - Chapter 13, Page 49
890 PspTerminateThreadByPointer(IN PETHREAD Thread
,
891 IN NTSTATUS ExitStatus
,
895 NTSTATUS Status
= STATUS_SUCCESS
;
898 PSTRACE(PS_KILL_DEBUG
, "Thread: %p ExitStatus: %p\n", Thread
, ExitStatus
);
901 /* Check if this is a Critical Thread, and Bugcheck */
902 if (Thread
->BreakOnTermination
)
904 /* Break to debugger */
905 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
907 Thread
->ThreadsProcess
->ImageFileName
);
910 /* Check if we are already inside the thread */
911 if ((bSelf
) || (PsGetCurrentThread() == Thread
))
913 /* This should only happen at passive */
914 ASSERT_IRQL(PASSIVE_LEVEL
);
916 /* Mark it as terminated */
917 PspSetCrossThreadFlag(Thread
, CT_TERMINATED_BIT
);
919 /* Directly terminate the thread */
920 PspExitThread(ExitStatus
);
923 /* This shouldn't be a system thread */
924 if (Thread
->SystemThread
) return STATUS_ACCESS_DENIED
;
926 /* Allocate the APC */
927 Apc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG_TERMINATE_APC
);
929 /* Set the Terminated Flag */
930 Flags
= Thread
->CrossThreadFlags
| 1;
932 /* Set it, and check if it was already set while we were running */
933 if (!(InterlockedExchange((PLONG
)&Thread
->CrossThreadFlags
, Flags
) & 1))
935 /* Initialize a Kernel Mode APC to Kill the Thread */
938 OriginalApcEnvironment
,
945 /* Insert it into the APC Queue */
946 if (!KeInsertQueueApc(Apc
, Apc
, NULL
, 2))
948 /* The APC was already in the queue, fail */
950 Status
= STATUS_UNSUCCESSFUL
;
954 /* Forcefully resume the thread and return */
955 KeForceResumeThread(&Thread
->Tcb
);
960 /* We failed, free the APC */
970 PspExitProcess(IN BOOLEAN LastThread
,
971 IN PEPROCESS Process
)
975 PSTRACE(PS_KILL_DEBUG
,
976 "LastThread: %p Process: %p\n", LastThread
, Process
);
979 /* Set Process Exit flag */
980 InterlockedOr((PLONG
)&Process
->Flags
, PSF_PROCESS_EXITING_BIT
);
982 /* Check if we are the last thread */
985 /* Notify the WMI Process Callback */
986 //WmiTraceProcess(Process, FALSE);
988 /* Run the Notification Routines */
989 PspRunCreateProcessNotifyRoutines(Process
, FALSE
);
992 /* Cleanup the power state */
993 PopCleanupPowerState((PPOWER_STATE
)&Process
->Pcb
.PowerState
);
995 /* Clear the security port */
996 if (!Process
->SecurityPort
)
998 /* So we don't double-dereference */
999 Process
->SecurityPort
= (PVOID
)1;
1001 else if (Process
->SecurityPort
!= (PVOID
)1)
1003 /* Dereference it */
1004 ObDereferenceObject(Process
->SecurityPort
);
1005 Process
->SecurityPort
= (PVOID
)1;
1008 /* Check if we are the last thread */
1009 PSREFTRACE(Process
);
1012 /* Check if we have to set the Timer Resolution */
1013 if (Process
->SetTimerResolution
)
1015 /* Set it to default */
1016 ZwSetTimerResolution(KeMaximumIncrement
, 0, &Actual
);
1019 /* Check if we are part of a Job that has a completion port */
1020 if ((Process
->Job
) && (Process
->Job
->CompletionPort
))
1022 /* FIXME: Check job status code and do I/O completion if needed */
1025 /* FIXME: Notify the Prefetcher */
1029 /* Clear process' address space here */
1030 MmCleanProcessAddressSpace(Process
);
1034 /* PUBLIC FUNCTIONS **********************************************************/
1041 PsTerminateSystemThread(IN NTSTATUS ExitStatus
)
1043 PETHREAD Thread
= PsGetCurrentThread();
1045 /* Make sure this is a system thread */
1046 if (Thread
->SystemThread
) return STATUS_INVALID_PARAMETER
;
1048 /* Terminate it for real */
1049 return PspTerminateThreadByPointer(Thread
, ExitStatus
, TRUE
);
1057 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL
,
1058 IN NTSTATUS ExitStatus
)
1061 PEPROCESS Process
, CurrentProcess
= PsGetCurrentProcess();
1062 PETHREAD Thread
, CurrentThread
= PsGetCurrentThread();
1063 BOOLEAN KillByHandle
;
1065 PSTRACE(PS_KILL_DEBUG
,
1066 "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle
, ExitStatus
);
1068 /* Remember how we will kill it */
1069 KillByHandle
= (ProcessHandle
!= NULL
);
1071 /* Get the Process Object */
1072 Status
= ObReferenceObjectByHandle((KillByHandle
) ?
1073 ProcessHandle
: NtCurrentProcess(),
1076 KeGetPreviousMode(),
1079 if (!NT_SUCCESS(Status
)) return(Status
);
1081 /* Check if this is a Critical Process, and Bugcheck */
1082 if (Process
->BreakOnTermination
)
1084 /* Break to debugger */
1085 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
1087 Process
->ImageFileName
);
1090 /* Lock the Process */
1091 ExAcquireRundownProtection(&Process
->RundownProtect
);
1093 /* Set the delete flag */
1094 if (!KillByHandle
) InterlockedOr((PLONG
)&Process
->Flags
,
1095 PSF_PROCESS_DELETE_BIT
);
1097 /* Get the first thread */
1098 Status
= STATUS_NOTHING_TO_TERMINATE
;
1099 Thread
= PsGetNextProcessThread(Process
, NULL
);
1102 /* We know we have at least a thread */
1103 Status
= STATUS_SUCCESS
;
1105 /* Loop and kill the others */
1108 /* Ensure it's not ours*/
1109 if (Thread
!= CurrentThread
)
1112 PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1115 /* Move to the next thread */
1116 } while((Thread
= PsGetNextProcessThread(Process
, Thread
)));
1119 /* Unlock the process */
1120 ExReleaseRundownProtection(&Process
->RundownProtect
);
1122 /* Check if we are killing ourselves */
1123 if (Process
!= CurrentProcess
)
1125 /* Check for the DBG_TERMINATE_PROCESS exit code */
1126 if (ExitStatus
== DBG_TERMINATE_PROCESS
)
1128 /* Disable debugging on this process */
1129 DbgkClearProcessDebugObject(Process
, NULL
);
1132 /* Make sure that we got a handle */
1133 else if (KillByHandle
)
1135 /* Dereference the project */
1136 ObDereferenceObject(Process
);
1138 /* Terminate ourselves */
1139 PspTerminateThreadByPointer(CurrentThread
, ExitStatus
, TRUE
);
1142 /* Check if there was nothing to terminate, or if we have a Debug Port */
1143 if ((Status
== STATUS_NOTHING_TO_TERMINATE
) ||
1144 ((Process
->DebugPort
) && (KillByHandle
)))
1146 /* Clear the handle table */
1147 ObClearProcessHandleTable(Process
);
1149 /* Return status now */
1150 Status
= STATUS_SUCCESS
;
1153 /* Decrease the reference count we added */
1154 ObDereferenceObject(Process
);
1162 NtTerminateThread(IN HANDLE ThreadHandle
,
1163 IN NTSTATUS ExitStatus
)
1166 PETHREAD CurrentThread
= PsGetCurrentThread();
1169 PSTRACE(PS_KILL_DEBUG
,
1170 "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle
, ExitStatus
);
1172 /* Handle the special NULL case */
1175 /* Check if we're the only thread left */
1176 if (PsGetCurrentProcess()->ActiveThreads
== 1)
1178 /* This is invalid */
1179 return STATUS_CANT_TERMINATE_SELF
;
1182 /* Terminate us directly */
1185 else if (ThreadHandle
== NtCurrentThread())
1188 /* Terminate this thread */
1189 return PspTerminateThreadByPointer(CurrentThread
,
1194 /* We are terminating another thread, get the Thread Object */
1195 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1198 KeGetPreviousMode(),
1201 if (!NT_SUCCESS(Status
)) return Status
;
1203 /* Check to see if we're running in the same thread */
1204 if (Thread
!= CurrentThread
)
1207 Status
= PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1209 /* Dereference the Thread and return */
1210 ObDereferenceObject(Thread
);
1214 /* Dereference the thread and terminate ourselves */
1215 ObDereferenceObject(Thread
);
1225 NtRegisterThreadTerminatePort(IN HANDLE PortHandle
)
1228 PTERMINATION_PORT TerminationPort
;
1229 PVOID TerminationLpcPort
;
1232 PSTRACE(PS_KILL_DEBUG
, "PortHandle: %p\n", PortHandle
);
1235 Status
= ObReferenceObjectByHandle(PortHandle
,
1238 KeGetPreviousMode(),
1239 &TerminationLpcPort
,
1241 if (!NT_SUCCESS(Status
)) return(Status
);
1243 /* Allocate the Port and make sure it suceeded */
1244 TerminationPort
= ExAllocatePoolWithTag(NonPagedPool
,
1245 sizeof(TERMINATION_PORT
),
1246 TAG('P', 's', 'T', '='));
1249 /* Associate the Port */
1250 Thread
= PsGetCurrentThread();
1251 TerminationPort
->Port
= TerminationLpcPort
;
1252 TerminationPort
->Next
= Thread
->TerminationPort
;
1253 Thread
->TerminationPort
= TerminationPort
;
1255 /* Return success */
1256 return STATUS_SUCCESS
;
1259 /* Dereference and Fail */
1260 ObDereferenceObject(TerminationPort
);
1261 return STATUS_INSUFFICIENT_RESOURCES
;