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 PspShutdownProcessManager(VOID
)
125 PEPROCESS Process
= NULL
;
127 /* Loop every process */
128 Process
= PsGetNextProcess(Process
);
131 /* Make sure this isn't the idle or initial process */
132 if ((Process
!= PsInitialSystemProcess
) && (Process
!= PsIdleProcess
))
135 PspTerminateProcess(Process
, STATUS_SYSTEM_SHUTDOWN
);
138 /* Get the next process */
139 Process
= PsGetNextProcess(Process
);
145 PspExitApcRundown(IN PKAPC Apc
)
155 PspReapRoutine(IN PVOID Context
)
157 PLIST_ENTRY
*ListAddr
;
158 PLIST_ENTRY NextEntry
;
160 PSTRACE(PS_KILL_DEBUG
, "Context: %p\n", Context
);
162 /* Get the Reaper Address Pointer */
163 ListAddr
= &PspReaperListHead
.Flink
;
165 /* Start main loop */
168 /* Write magic value and return the next entry to process */
169 NextEntry
= InterlockedExchangePointer(ListAddr
, (PVOID
)1);
170 ASSERT((NextEntry
!= NULL
) && (NextEntry
!= (PVOID
)1));
172 /* Start inner loop */
175 /* Get the first Thread Entry */
176 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, ReaperLink
);
178 /* Delete this entry's kernel stack */
179 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackLimit
,
180 Thread
->Tcb
.LargeStack
);
181 Thread
->Tcb
.InitialStack
= NULL
;
183 /* Move to the next entry */
184 NextEntry
= NextEntry
->Flink
;
186 /* Dereference this thread */
187 ObDereferenceObject(Thread
);
189 } while ((NextEntry
!= NULL
) && (NextEntry
!= (PVOID
)1));
191 /* Remove magic value, keep looping if it got changed */
192 } while (InterlockedCompareExchangePointer(ListAddr
, 0, 1) != (PVOID
)1);
197 PspDeleteProcess(IN PVOID ObjectBody
)
199 PEPROCESS Process
= (PEPROCESS
)ObjectBody
;
202 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
205 /* Check if it has an Active Process Link */
206 if (Process
->ActiveProcessLinks
.Flink
)
208 /* Remove it from the Active List */
209 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
210 RemoveEntryList(&Process
->ActiveProcessLinks
);
211 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
214 /* Check for Auditing information */
215 if (Process
->SeAuditProcessCreationInfo
.ImageFileName
)
218 ExFreePool(Process
->SeAuditProcessCreationInfo
.ImageFileName
);
219 Process
->SeAuditProcessCreationInfo
.ImageFileName
= NULL
;
222 /* Check if we have a job */
225 /* Remove the process from the job */
226 PspRemoveProcessFromJob(Process
, Process
->Job
);
229 ObDereferenceObject(Process
->Job
);
233 /* Increase the stack count */
234 Process
->Pcb
.StackCount
++;
236 /* Check if we have a debug port */
237 if (Process
->DebugPort
)
239 /* Dererence the Debug Port */
240 ObDereferenceObject(Process
->DebugPort
);
241 Process
->DebugPort
= NULL
;
244 /* Check if we have an exception port */
245 if (Process
->ExceptionPort
)
247 /* Dererence the Exception Port */
248 ObDereferenceObject(Process
->ExceptionPort
);
249 Process
->ExceptionPort
= NULL
;
252 /* Check if we have a section object */
253 if (Process
->SectionObject
)
255 /* Dererence the Section Object */
256 ObDereferenceObject(Process
->SectionObject
);
257 Process
->SectionObject
= NULL
;
260 /* Clean LDT and VDM_OBJECTS */
261 PspDeleteLdt(Process
);
262 PspDeleteVdmObjects(Process
);
264 /* Delete the Object Table */
265 if (Process
->ObjectTable
)
267 /* Attach to the process */
268 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
270 /* Kill the Object Info */
271 ObKillProcess(Process
);
274 KeUnstackDetachProcess(&ApcState
);
278 KDB_DELETEPROCESS_HOOK(Process
);
280 /* Check if we have an address space, and clean it */
281 if (Process
->HasAddressSpace
)
283 /* Attach to the process */
284 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
286 /* Clean the Address Space */
287 PspExitProcess(FALSE
, Process
);
290 KeUnstackDetachProcess(&ApcState
);
292 /* Completely delete the Address Space */
293 MmDeleteProcessAddressSpace(Process
);
296 /* See if we have a PID */
297 if(Process
->UniqueProcessId
)
300 if (!(ExDestroyHandle(PspCidTable
, Process
->UniqueProcessId
)))
302 /* Something wrong happened, bugcheck */
303 KEBUGCHECK(CID_HANDLE_DELETION
);
307 /* Cleanup security information */
308 PspDeleteProcessSecurity(Process
);
310 /* Check if we have kept information on the Working Set */
311 if (Process
->WorkingSetWatch
)
314 ExFreePool(Process
->WorkingSetWatch
);
316 /* And return the quota it was taking up */
317 PsReturnProcessNonPagedPoolQuota(Process
, 0x2000);
320 /* Dereference the Device Map */
321 ObDereferenceDeviceMap(Process
);
323 /* Destroy the Quota Block */
324 PspDestroyQuotaBlock(Process
);
330 PspDeleteThread(IN PVOID ObjectBody
)
332 PETHREAD Thread
= (PETHREAD
)ObjectBody
;
333 PEPROCESS Process
= Thread
->ThreadsProcess
;
335 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
337 ASSERT(Thread
->Tcb
.Win32Thread
== NULL
);
339 /* Check if we have a stack */
340 if (Thread
->Tcb
.InitialStack
)
343 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackLimit
,
344 Thread
->Tcb
.LargeStack
);
347 /* Check if we have a CID Handle */
348 if (Thread
->Cid
.UniqueThread
)
350 /* Delete the CID Handle */
351 if (!(ExDestroyHandle(PspCidTable
, Thread
->Cid
.UniqueThread
)))
353 /* Something wrong happened, bugcheck */
354 KEBUGCHECK(CID_HANDLE_DELETION
);
358 /* Cleanup impersionation information */
359 PspDeleteThreadSecurity(Thread
);
361 /* Make sure the thread was inserted, before continuing */
363 if (!Process
) return;
365 /* Check if the thread list is valid */
366 if (Thread
->ThreadListEntry
.Flink
)
368 /* Lock the thread's process */
369 KeEnterCriticalRegion();
370 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
372 /* Remove us from the list */
373 RemoveEntryList(&Thread
->ThreadListEntry
);
375 /* Release the lock */
376 ExReleasePushLockExclusive(&Process
->ProcessLock
);
377 KeLeaveCriticalRegion();
380 /* Dereference the Process */
381 ObDereferenceObject(Process
);
387 * FUNCTION: Terminates the current thread
388 * See "Windows Internals" - Chapter 13, Page 50-53
392 PspExitThread(IN NTSTATUS ExitStatus
)
394 CLIENT_DIED_MSG TerminationMsg
;
397 PEPROCESS CurrentProcess
;
399 PVOID DeallocationStack
;
401 BOOLEAN Last
= FALSE
;
402 PTERMINATION_PORT TerminationPort
, NextPort
;
403 PLIST_ENTRY FirstEntry
, CurrentEntry
;
407 PSTRACE(PS_KILL_DEBUG
, "ExitStatus: %p\n", ExitStatus
);
409 /* Get the Current Thread and Process */
410 Thread
= PsGetCurrentThread();
411 CurrentProcess
= Thread
->ThreadsProcess
;
412 ASSERT((Thread
) == PsGetCurrentThread());
414 /* Can't terminate a thread if it attached another process */
416 PSREFTRACE(CurrentProcess
);
417 if (KeIsAttachedProcess())
420 KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT
,
421 (ULONG_PTR
)CurrentProcess
,
422 (ULONG_PTR
)Thread
->Tcb
.ApcState
.Process
,
423 (ULONG_PTR
)Thread
->Tcb
.ApcStateIndex
,
427 /* Lower to Passive Level */
428 KfLowerIrql(PASSIVE_LEVEL
);
430 /* Can't be a worker thread */
431 if (Thread
->ActiveExWorker
)
434 KEBUGCHECKEX(ACTIVE_EX_WORKER_THREAD_TERMINATION
,
441 /* Can't have pending APCs */
442 if (Thread
->Tcb
.CombinedApcDisable
!= 0)
445 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT
,
447 Thread
->Tcb
.KernelApcDisable
,
452 /* Lock the thread */
453 ExWaitForRundownProtectionRelease(&Thread
->RundownProtect
);
455 /* Cleanup the power state */
456 PopCleanupPowerState((PPOWER_STATE
)&Thread
->Tcb
.PowerState
);
458 /* Call the WMI Callback for Threads */
459 //WmiTraceThread(Thread, NULL, FALSE);
461 /* Run Thread Notify Routines before we desintegrate the thread */
462 PspRunCreateThreadNotifyRoutines(Thread
, FALSE
);
464 /* Lock the Process before we modify its thread entries */
465 KeEnterCriticalRegion();
466 ExAcquirePushLockExclusive(&CurrentProcess
->ProcessLock
);
468 /* Decrease the active thread count, and check if it's 0 */
469 if (!(--CurrentProcess
->ActiveThreads
))
471 /* Set the delete flag */
472 InterlockedOr((PLONG
)&CurrentProcess
->Flags
, PSF_PROCESS_DELETE_BIT
);
474 /* Remember we are last */
477 /* Check if this termination is due to the thread dying */
478 if (ExitStatus
== STATUS_THREAD_IS_TERMINATING
)
480 /* Check if the last thread was pending */
481 if (CurrentProcess
->ExitStatus
== STATUS_PENDING
)
483 /* Use the last exit status */
484 CurrentProcess
->ExitStatus
= CurrentProcess
->
485 LastThreadExitStatus
;
490 /* Just a normal exit, write the code */
491 CurrentProcess
->ExitStatus
= ExitStatus
;
494 /* FIXME: Wait on the other threads to finish */
496 else if (ExitStatus
!= STATUS_THREAD_IS_TERMINATING
)
498 /* Write down the exit status of the last thread to get killed */
499 CurrentProcess
->LastThreadExitStatus
= ExitStatus
;
502 /* Unlock the Process */
503 ExReleasePushLockExclusive(&CurrentProcess
->ProcessLock
);
504 KeLeaveCriticalRegion();
506 /* Check if the process has a debug port and if this is a user thread */
507 if ((CurrentProcess
->DebugPort
) && !(Thread
->SystemThread
))
509 /* Notify the Debug API. */
510 Last
? DbgkExitProcess(CurrentProcess
->ExitStatus
) :
511 DbgkExitThread(ExitStatus
);
514 /* Check if this is a Critical Thread */
515 if ((KdDebuggerEnabled
) && (Thread
->BreakOnTermination
))
517 /* Break to debugger */
518 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
520 CurrentProcess
->ImageFileName
);
523 /* Check if it's the last thread and this is a Critical Process */
524 if ((Last
) && (CurrentProcess
->BreakOnTermination
))
526 /* Check if a debugger is here to handle this */
527 if (KdDebuggerEnabled
)
529 /* Break to debugger */
530 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n",
532 CurrentProcess
->ImageFileName
);
536 /* Bugcheck, we can't allow this */
537 KEBUGCHECKEX(CRITICAL_PROCESS_DIED
,
538 (ULONG_PTR
)CurrentProcess
,
546 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
548 /* Process the Termination Ports */
549 TerminationPort
= Thread
->TerminationPort
;
552 /* Setup the message header */
553 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
554 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
555 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
556 sizeof(PORT_MESSAGE
);
561 /* Save the Create Time */
562 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
565 /* Send the LPC Message */
566 Status
= LpcRequestPort(TerminationPort
->Port
, &TerminationMsg
.h
);
567 if ((Status
== STATUS_NO_MEMORY
) ||
568 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
570 /* Wait a bit and try again */
571 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
575 /* Dereference this LPC Port */
576 ObDereferenceObject(TerminationPort
->Port
);
578 /* Move to the next one */
579 NextPort
= TerminationPort
->Next
;
581 /* Free the Termination Port Object */
582 ExFreePool(TerminationPort
);
584 /* Keep looping as long as there is a port */
585 } while ((TerminationPort
= NextPort
));
587 else if (((ExitStatus
== STATUS_THREAD_IS_TERMINATING
) &&
588 (Thread
->DeadThread
)) ||
589 !(Thread
->DeadThread
))
592 * This case is special and deserves some extra comments. What
593 * basically happens here is that this thread doesn't have a termination
594 * port, which means that it died before being fully created. Since we
595 * still have to notify an LPC Server, we'll use the exception port,
596 * which we know exists. However, we need to know how far the thread
597 * actually got created. We have three possibilites:
599 * - NtCreateThread returned an error really early: DeadThread is set.
600 * - NtCreateThread managed to create the thread: DeadThread is off.
601 * - NtCreateThread was creating the thread (with Deadthread set,
602 * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING
605 * For the 2 & 3rd scenarios, the thread has been created far enough to
606 * warrant notification to the LPC Server.
609 /* Setup the message header */
610 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
611 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
612 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
613 sizeof(PORT_MESSAGE
);
615 /* Make sure the process has an exception port */
616 if (CurrentProcess
->ExceptionPort
)
618 /* Save the Create Time */
619 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
622 /* Send the LPC Message */
623 Status
= LpcRequestPort(CurrentProcess
->ExceptionPort
,
625 if ((Status
== STATUS_NO_MEMORY
) ||
626 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
628 /* Wait a bit and try again */
629 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortPsLockDelay
);
635 /* Rundown Win32 Thread if there is one */
636 if (Thread
->Tcb
.Win32Thread
) PspW32ThreadCallout(Thread
,
637 PsW32ThreadCalloutExit
);
639 /* If we are the last thread and have a W32 Process */
641 if ((Last
) && (CurrentProcess
->Win32Process
))
643 /* Run it down too */
644 PspW32ProcessCallout(CurrentProcess
, FALSE
);
647 /* Make sure Stack Swap isn't enabled */
648 if (Thread
->Tcb
.EnableStackSwap
)
650 /* Stack swap really shouldn't be on during exit !*/
651 KEBUGCHECKEX(KERNEL_STACK_LOCKED_AT_EXIT
, 0, 0, 0, 0);
654 /* Cancel I/O for the thread. */
655 IoCancelThreadIo(Thread
);
660 /* FIXME: Rundown Registry Notifications (NtChangeNotify)
661 CmNotifyRunDown(Thread); */
663 /* Rundown Mutexes */
666 /* Check if we have a TEB */
667 Teb
= Thread
->Tcb
.Teb
;
670 /* Check if the thread isn't terminated and if we should free stack */
671 if (!(Thread
->Terminated
) && (Teb
->FreeStackOnTermination
))
673 /* Set the TEB's Deallocation Stack as the Base Address */
675 DeallocationStack
= Teb
->DeallocationStack
;
677 /* Free the Thread's Stack */
678 ZwFreeVirtualMemory(NtCurrentProcess(),
684 /* Free the debug handle */
685 if (Teb
->DbgSsReserved
[1]) ObCloseHandle(Teb
->DbgSsReserved
[1],
688 /* Decommit the TEB */
689 MmDeleteTeb(CurrentProcess
, Teb
);
690 Thread
->Tcb
.Teb
= NULL
;
694 LpcExitThread(Thread
);
696 /* Save the exit status and exit time */
697 Thread
->ExitStatus
= ExitStatus
;
698 KeQuerySystemTime(&Thread
->ExitTime
);
701 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
703 /* Check if this is the final thread or not */
705 PSREFTRACE(CurrentProcess
);
708 /* Set the process exit time */
709 CurrentProcess
->ExitTime
= Thread
->ExitTime
;
711 /* Exit the process */
712 PspExitProcess(TRUE
, CurrentProcess
);
714 /* Get the process token and check if we need to audit */
715 PrimaryToken
= PsReferencePrimaryToken(CurrentProcess
);
716 if (SeDetailedAuditingWithToken(PrimaryToken
))
719 SeAuditProcessExit(CurrentProcess
);
722 /* Dereference the process token */
723 ObFastDereferenceObject(&CurrentProcess
->Token
, PrimaryToken
);
725 /* Check if this is a VDM Process and rundown the VDM DPCs if so */
726 if (CurrentProcess
->VdmObjects
);// VdmRundownDpcs(CurrentProcess);
728 /* Kill the process in the Object Manager */
729 ObKillProcess(CurrentProcess
);
730 PSREFTRACE(CurrentProcess
);
732 /* Check if we have a section object */
733 if (CurrentProcess
->SectionObject
)
735 /* Dereference and clear the Section Object */
736 ObDereferenceObject(CurrentProcess
->SectionObject
);
737 CurrentProcess
->SectionObject
= NULL
;
740 /* Check if the process is part of a job */
741 if (CurrentProcess
->Job
)
743 /* Remove the process from the job */
744 PspExitProcessFromJob(CurrentProcess
->Job
, CurrentProcess
);
749 KeEnterCriticalRegion();
751 /* Disable APC queueing, force a resumption */
752 Thread
->Tcb
.ApcQueueable
= FALSE
;
753 KeForceResumeThread(&Thread
->Tcb
);
756 KeLeaveCriticalRegion();
758 /* Flush the User APCs */
759 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, UserMode
);
762 CurrentEntry
= FirstEntry
;
766 Apc
= CONTAINING_RECORD(CurrentEntry
, KAPC
, ApcListEntry
);
768 /* Move to the next one */
769 CurrentEntry
= CurrentEntry
->Flink
;
771 /* Rundown the APC or de-allocate it */
772 if (Apc
->RundownRoutine
)
774 /* Call its own routine */
775 (Apc
->RundownRoutine
)(Apc
);
779 /* Do it ourselves */
783 while (CurrentEntry
!= FirstEntry
);
786 /* Clean address space if this was the last thread */
787 if (Last
) MmCleanProcessAddressSpace(CurrentProcess
);
789 /* Call the Lego routine */
790 if (Thread
->Tcb
.LegoData
) PspRunLegoRoutine(&Thread
->Tcb
);
792 /* Flush the APC queue, which should be empty */
793 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, KernelMode
);
797 KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT
,
798 (ULONG_PTR
)FirstEntry
,
799 Thread
->Tcb
.KernelApcDisable
,
804 /* Signal the process if this was the last thread */
805 if (Last
) KeSetProcess(&CurrentProcess
->Pcb
, 0, FALSE
);
807 /* Terminate the Thread from the Scheduler */
809 PSREFTRACE(CurrentProcess
);
810 KeTerminateThread(0);
815 PsExitSpecialApc(IN PKAPC Apc
,
816 IN OUT PKNORMAL_ROUTINE
* NormalRoutine
,
817 IN OUT PVOID
* NormalContext
,
818 IN OUT PVOID
* SystemArgument1
,
819 IN OUT PVOID
* SystemArgument2
)
823 PSTRACE(PS_KILL_DEBUG
,
824 "Apc: %p SystemArgument2: %p \n", Apc
, SystemArgument2
);
826 /* Don't do anything unless we are in User-Mode */
827 if (Apc
->SystemArgument2
)
830 Status
= (NTSTATUS
)Apc
->NormalContext
;
831 PspExitApcRundown(Apc
);
833 /* Terminate the Thread */
834 PspExitThread(Status
);
840 PspExitNormalApc(IN PVOID NormalContext
,
841 IN PVOID SystemArgument1
,
842 IN PVOID SystemArgument2
)
844 PKAPC Apc
= (PKAPC
)SystemArgument1
;
845 PETHREAD Thread
= PsGetCurrentThread();
847 PSTRACE(PS_KILL_DEBUG
, "SystemArgument2: %p \n", SystemArgument2
);
849 /* This should never happen */
850 ASSERT(!(((ULONG_PTR
)SystemArgument2
) & 1));
852 /* If we're here, this is not a System Thread, so kill it from User-Mode */
855 OriginalApcEnvironment
,
862 /* Now insert the APC with the User-Mode Flag */
863 if (!(KeInsertQueueApc(Apc
,
865 (PVOID
)((ULONG_PTR
)SystemArgument2
| 1),
868 /* Failed to insert, free the APC */
869 PspExitApcRundown(Apc
);
872 /* Set the APC Pending flag */
873 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
877 * See "Windows Internals" - Chapter 13, Page 49
881 PspTerminateThreadByPointer(IN PETHREAD Thread
,
882 IN NTSTATUS ExitStatus
,
886 NTSTATUS Status
= STATUS_SUCCESS
;
889 PSTRACE(PS_KILL_DEBUG
, "Thread: %p ExitStatus: %p\n", Thread
, ExitStatus
);
892 /* Check if this is a Critical Thread, and Bugcheck */
893 if (Thread
->BreakOnTermination
)
895 /* Break to debugger */
896 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
898 Thread
->ThreadsProcess
->ImageFileName
);
901 /* Check if we are already inside the thread */
902 if ((bSelf
) || (PsGetCurrentThread() == Thread
))
904 /* This should only happen at passive */
905 ASSERT_IRQL(PASSIVE_LEVEL
);
907 /* Mark it as terminated */
908 PspSetCrossThreadFlag(Thread
, CT_TERMINATED_BIT
);
910 /* Directly terminate the thread */
911 PspExitThread(ExitStatus
);
914 /* This shouldn't be a system thread */
915 if (Thread
->SystemThread
) return STATUS_ACCESS_DENIED
;
917 /* Allocate the APC */
918 Apc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG_TERMINATE_APC
);
920 /* Set the Terminated Flag */
921 Flags
= Thread
->CrossThreadFlags
| 1;
923 /* Set it, and check if it was already set while we were running */
924 if (!(InterlockedExchange((PLONG
)&Thread
->CrossThreadFlags
, Flags
) & 1))
926 /* Initialize a Kernel Mode APC to Kill the Thread */
929 OriginalApcEnvironment
,
936 /* Insert it into the APC Queue */
937 if (!KeInsertQueueApc(Apc
, Apc
, NULL
, 2))
939 /* The APC was already in the queue, fail */
941 Status
= STATUS_UNSUCCESSFUL
;
945 /* Forcefully resume the thread and return */
946 KeForceResumeThread(&Thread
->Tcb
);
951 /* We failed, free the APC */
961 PspExitProcess(IN BOOLEAN LastThread
,
962 IN PEPROCESS Process
)
966 PSTRACE(PS_KILL_DEBUG
,
967 "LastThread: %p Process: %p\n", LastThread
, Process
);
970 /* Set Process Exit flag */
971 InterlockedOr((PLONG
)&Process
->Flags
, PSF_PROCESS_EXITING_BIT
);
973 /* Check if we are the last thread */
976 /* Notify the WMI Process Callback */
977 //WmiTraceProcess(Process, FALSE);
979 /* Run the Notification Routines */
980 PspRunCreateProcessNotifyRoutines(Process
, FALSE
);
983 /* Cleanup the power state */
984 PopCleanupPowerState((PPOWER_STATE
)&Process
->Pcb
.PowerState
);
986 /* Clear the security port */
987 if (!Process
->SecurityPort
)
989 /* So we don't double-dereference */
990 Process
->SecurityPort
= (PVOID
)1;
992 else if (Process
->SecurityPort
!= (PVOID
)1)
995 ObDereferenceObject(Process
->SecurityPort
);
996 Process
->SecurityPort
= (PVOID
)1;
999 /* Check if we are the last thread */
1000 PSREFTRACE(Process
);
1003 /* Check if we have to set the Timer Resolution */
1004 if (Process
->SetTimerResolution
)
1006 /* Set it to default */
1007 ZwSetTimerResolution(KeMaximumIncrement
, 0, &Actual
);
1010 /* Check if we are part of a Job that has a completion port */
1011 if ((Process
->Job
) && (Process
->Job
->CompletionPort
))
1013 /* FIXME: Check job status code and do I/O completion if needed */
1016 /* FIXME: Notify the Prefetcher */
1020 /* Clear process' address space here */
1021 MmCleanProcessAddressSpace(Process
);
1025 /* PUBLIC FUNCTIONS **********************************************************/
1032 PsTerminateSystemThread(IN NTSTATUS ExitStatus
)
1034 PETHREAD Thread
= PsGetCurrentThread();
1036 /* Make sure this is a system thread */
1037 if (Thread
->SystemThread
) return STATUS_INVALID_PARAMETER
;
1039 /* Terminate it for real */
1040 return PspTerminateThreadByPointer(Thread
, ExitStatus
, TRUE
);
1048 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL
,
1049 IN NTSTATUS ExitStatus
)
1052 PEPROCESS Process
, CurrentProcess
= PsGetCurrentProcess();
1053 PETHREAD Thread
, CurrentThread
= PsGetCurrentThread();
1054 BOOLEAN KillByHandle
;
1056 PSTRACE(PS_KILL_DEBUG
,
1057 "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle
, ExitStatus
);
1059 /* Remember how we will kill it */
1060 KillByHandle
= (ProcessHandle
!= NULL
);
1062 /* Get the Process Object */
1063 Status
= ObReferenceObjectByHandle((KillByHandle
) ?
1064 ProcessHandle
: NtCurrentProcess(),
1067 KeGetPreviousMode(),
1070 if (!NT_SUCCESS(Status
)) return(Status
);
1072 /* Check if this is a Critical Process, and Bugcheck */
1073 if (Process
->BreakOnTermination
)
1075 /* Break to debugger */
1076 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
1078 Process
->ImageFileName
);
1081 /* Lock the Process */
1082 ExAcquireRundownProtection(&Process
->RundownProtect
);
1084 /* Set the delete flag */
1085 if (!KillByHandle
) InterlockedOr((PLONG
)&Process
->Flags
,
1086 PSF_PROCESS_DELETE_BIT
);
1088 /* Get the first thread */
1089 Status
= STATUS_NOTHING_TO_TERMINATE
;
1090 Thread
= PsGetNextProcessThread(Process
, NULL
);
1093 /* We know we have at least a thread */
1094 Status
= STATUS_SUCCESS
;
1096 /* Loop and kill the others */
1099 /* Ensure it's not ours*/
1100 if (Thread
!= CurrentThread
)
1103 PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1106 /* Move to the next thread */
1107 } while((Thread
= PsGetNextProcessThread(Process
, Thread
)));
1110 /* Unlock the process */
1111 ExReleaseRundownProtection(&Process
->RundownProtect
);
1113 /* Check if we are killing ourselves */
1114 if (Process
!= CurrentProcess
)
1116 /* Check for the DBG_TERMINATE_PROCESS exit code */
1117 if (ExitStatus
== DBG_TERMINATE_PROCESS
)
1119 /* FIXME: Disable debugging on this process */
1122 /* Make sure that we got a handle */
1123 else if (KillByHandle
)
1125 /* Dereference the project */
1126 ObDereferenceObject(Process
);
1128 /* Terminate ourselves */
1129 PspTerminateThreadByPointer(CurrentThread
, ExitStatus
, TRUE
);
1132 /* Check if there was nothing to terminate, or if we have a Debug Port */
1133 if ((Status
== STATUS_NOTHING_TO_TERMINATE
) ||
1134 ((Process
->DebugPort
) && (KillByHandle
)))
1136 /* Clear the handle table */
1137 ObClearProcessHandleTable(Process
);
1139 /* Return status now */
1140 Status
= STATUS_SUCCESS
;
1143 /* Decrease the reference count we added */
1144 ObDereferenceObject(Process
);
1152 NtTerminateThread(IN HANDLE ThreadHandle
,
1153 IN NTSTATUS ExitStatus
)
1156 PETHREAD CurrentThread
= PsGetCurrentThread();
1159 PSTRACE(PS_KILL_DEBUG
,
1160 "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle
, ExitStatus
);
1162 /* Handle the special NULL case */
1165 /* Check if we're the only thread left */
1166 if (PsGetCurrentProcess()->ActiveThreads
== 1)
1168 /* This is invalid */
1169 return STATUS_CANT_TERMINATE_SELF
;
1172 /* Terminate us directly */
1175 else if (ThreadHandle
== NtCurrentThread())
1178 /* Terminate this thread */
1179 return PspTerminateThreadByPointer(CurrentThread
,
1184 /* We are terminating another thread, get the Thread Object */
1185 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1188 KeGetPreviousMode(),
1191 if (!NT_SUCCESS(Status
)) return Status
;
1193 /* Check to see if we're running in the same thread */
1194 if (Thread
!= CurrentThread
)
1197 Status
= PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1199 /* Dereference the Thread and return */
1200 ObDereferenceObject(Thread
);
1204 /* Dereference the thread and terminate ourselves */
1205 ObDereferenceObject(Thread
);
1215 NtRegisterThreadTerminatePort(IN HANDLE PortHandle
)
1218 PTERMINATION_PORT TerminationPort
;
1219 PVOID TerminationLpcPort
;
1222 PSTRACE(PS_KILL_DEBUG
, "PortHandle: %p\n", PortHandle
);
1225 Status
= ObReferenceObjectByHandle(PortHandle
,
1228 KeGetPreviousMode(),
1229 &TerminationLpcPort
,
1231 if (!NT_SUCCESS(Status
)) return(Status
);
1233 /* Allocate the Port and make sure it suceeded */
1234 TerminationPort
= ExAllocatePoolWithTag(NonPagedPool
,
1235 sizeof(TERMINATION_PORT
),
1236 TAG('P', 's', 'T', '='));
1239 /* Associate the Port */
1240 Thread
= PsGetCurrentThread();
1241 TerminationPort
->Port
= TerminationLpcPort
;
1242 TerminationPort
->Next
= Thread
->TerminationPort
;
1243 Thread
->TerminationPort
= TerminationPort
;
1245 /* Return success */
1246 return STATUS_SUCCESS
;
1249 /* Dereference and Fail */
1250 ObDereferenceObject(TerminationPort
);
1251 return STATUS_INSUFFICIENT_RESOURCES
;