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 *****************************************************************/
17 /* GLOBALS *******************************************************************/
19 LIST_ENTRY PspReaperListHead
= { NULL
, NULL
};
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: %d\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((PVOID
*)&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
.StackBase
,
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((PVOID
*)&PspReaperListHead
.Flink
,
205 (PVOID
)1) != (PVOID
)1);
211 PspCheckProcessList(VOID
)
215 KeAcquireGuardedMutex(&PspActiveProcessMutex
);
216 DbgPrint("# checking PsActiveProcessHead @ %p\n", &PsActiveProcessHead
);
217 for (Entry
= PsActiveProcessHead
.Flink
;
218 Entry
!= &PsActiveProcessHead
;
219 Entry
= Entry
->Flink
)
221 PEPROCESS Process
= CONTAINING_RECORD(Entry
, EPROCESS
, ActiveProcessLinks
);
222 POBJECT_HEADER Header
;
223 PVOID Info
, HeaderLocation
;
225 /* Get the header and assume this is what we'll free */
226 Header
= OBJECT_TO_OBJECT_HEADER(Process
);
227 HeaderLocation
= Header
;
229 /* To find the header, walk backwards from how we allocated */
230 if ((Info
= OBJECT_HEADER_TO_CREATOR_INFO(Header
)))
232 HeaderLocation
= Info
;
234 if ((Info
= OBJECT_HEADER_TO_NAME_INFO(Header
)))
236 HeaderLocation
= Info
;
238 if ((Info
= OBJECT_HEADER_TO_HANDLE_INFO(Header
)))
240 HeaderLocation
= Info
;
242 if ((Info
= OBJECT_HEADER_TO_QUOTA_INFO(Header
)))
244 HeaderLocation
= Info
;
247 ExpCheckPoolAllocation(HeaderLocation
, NonPagedPool
, 'corP');
250 KeReleaseGuardedMutex(&PspActiveProcessMutex
);
256 PspDeleteProcess(IN PVOID ObjectBody
)
258 PEPROCESS Process
= (PEPROCESS
)ObjectBody
;
261 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
264 /* Check if it has an Active Process Link */
265 if (Process
->ActiveProcessLinks
.Flink
)
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
);
275 /* Check for Auditing information */
276 if (Process
->SeAuditProcessCreationInfo
.ImageFileName
)
279 ExFreePoolWithTag(Process
->SeAuditProcessCreationInfo
.ImageFileName
,
281 Process
->SeAuditProcessCreationInfo
.ImageFileName
= NULL
;
284 /* Check if we have a job */
287 /* Remove the process from the job */
288 PspRemoveProcessFromJob(Process
, Process
->Job
);
291 ObDereferenceObject(Process
->Job
);
295 /* Increase the stack count */
296 Process
->Pcb
.StackCount
++;
298 /* Check if we have a debug port */
299 if (Process
->DebugPort
)
301 /* Deference the Debug Port */
302 ObDereferenceObject(Process
->DebugPort
);
303 Process
->DebugPort
= NULL
;
306 /* Check if we have an exception port */
307 if (Process
->ExceptionPort
)
309 /* Deference the Exception Port */
310 ObDereferenceObject(Process
->ExceptionPort
);
311 Process
->ExceptionPort
= NULL
;
314 /* Check if we have a section object */
315 if (Process
->SectionObject
)
317 /* Deference the Section Object */
318 ObDereferenceObject(Process
->SectionObject
);
319 Process
->SectionObject
= NULL
;
323 /* Clean Ldt and Vdm objects */
324 PspDeleteLdt(Process
);
325 PspDeleteVdmObjects(Process
);
328 /* Delete the Object Table */
329 if (Process
->ObjectTable
)
331 /* Attach to the process */
332 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
334 /* Kill the Object Info */
335 ObKillProcess(Process
);
338 KeUnstackDetachProcess(&ApcState
);
341 /* Check if we have an address space, and clean it */
342 if (Process
->HasAddressSpace
)
344 /* Attach to the process */
345 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
347 /* Clean the Address Space */
348 PspExitProcess(FALSE
, Process
);
351 KeUnstackDetachProcess(&ApcState
);
353 /* Completely delete the Address Space */
354 MmDeleteProcessAddressSpace(Process
);
357 /* See if we have a PID */
358 if (Process
->UniqueProcessId
)
361 if (!(ExDestroyHandle(PspCidTable
, Process
->UniqueProcessId
, NULL
)))
363 /* Something wrong happened, bugcheck */
364 KeBugCheck(CID_HANDLE_DELETION
);
368 /* Cleanup security information */
369 PspDeleteProcessSecurity(Process
);
371 /* Check if we have kept information on the Working Set */
372 if (Process
->WorkingSetWatch
)
375 ExFreePool(Process
->WorkingSetWatch
);
377 /* And return the quota it was taking up */
378 PsReturnProcessNonPagedPoolQuota(Process
, 0x2000);
381 /* Dereference the Device Map */
382 ObDereferenceDeviceMap(Process
);
384 /* Destroy the Quota Block */
385 PspDestroyQuotaBlock(Process
);
390 PspDeleteThread(IN PVOID ObjectBody
)
392 PETHREAD Thread
= (PETHREAD
)ObjectBody
;
393 PEPROCESS Process
= Thread
->ThreadsProcess
;
395 PSTRACE(PS_KILL_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
397 ASSERT(Thread
->Tcb
.Win32Thread
== NULL
);
399 /* Check if we have a stack */
400 if (Thread
->Tcb
.InitialStack
)
403 MmDeleteKernelStack((PVOID
)Thread
->Tcb
.StackBase
,
404 Thread
->Tcb
.LargeStack
);
407 /* Check if we have a CID Handle */
408 if (Thread
->Cid
.UniqueThread
)
410 /* Delete the CID Handle */
411 if (!(ExDestroyHandle(PspCidTable
, Thread
->Cid
.UniqueThread
, NULL
)))
413 /* Something wrong happened, bugcheck */
414 KeBugCheck(CID_HANDLE_DELETION
);
418 /* Cleanup impersionation information */
419 PspDeleteThreadSecurity(Thread
);
421 /* Make sure the thread was inserted, before continuing */
422 if (!Process
) return;
424 /* Check if the thread list is valid */
425 if (Thread
->ThreadListEntry
.Flink
)
427 /* Lock the thread's process */
428 KeEnterCriticalRegion();
429 ExAcquirePushLockExclusive(&Process
->ProcessLock
);
431 /* Remove us from the list */
432 RemoveEntryList(&Thread
->ThreadListEntry
);
434 /* Release the lock */
435 ExReleasePushLockExclusive(&Process
->ProcessLock
);
436 KeLeaveCriticalRegion();
439 /* Dereference the Process */
440 ObDereferenceObject(Process
);
444 * FUNCTION: Terminates the current thread
445 * See "Windows Internals" - Chapter 13, Page 50-53
449 PspExitThread(IN NTSTATUS ExitStatus
)
451 CLIENT_DIED_MSG TerminationMsg
;
454 PEPROCESS CurrentProcess
;
455 PETHREAD Thread
, OtherThread
, PreviousThread
= NULL
;
456 PVOID DeallocationStack
;
458 BOOLEAN Last
= FALSE
;
459 PTERMINATION_PORT TerminationPort
, NextPort
;
460 PLIST_ENTRY FirstEntry
, CurrentEntry
;
464 PSTRACE(PS_KILL_DEBUG
, "ExitStatus: %d\n", ExitStatus
);
466 /* Get the Current Thread and Process */
467 Thread
= PsGetCurrentThread();
468 CurrentProcess
= Thread
->ThreadsProcess
;
469 ASSERT((Thread
) == PsGetCurrentThread());
471 /* Can't terminate a thread if it attached another process */
472 if (KeIsAttachedProcess())
475 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT
,
476 (ULONG_PTR
)CurrentProcess
,
477 (ULONG_PTR
)Thread
->Tcb
.ApcState
.Process
,
478 (ULONG_PTR
)Thread
->Tcb
.ApcStateIndex
,
482 /* Lower to Passive Level */
483 KeLowerIrql(PASSIVE_LEVEL
);
485 /* Can't be a worker thread */
486 if (Thread
->ActiveExWorker
)
489 KeBugCheckEx(ACTIVE_EX_WORKER_THREAD_TERMINATION
,
496 /* Can't have pending APCs */
497 if (Thread
->Tcb
.CombinedApcDisable
!= 0)
500 KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT
,
502 Thread
->Tcb
.CombinedApcDisable
,
507 /* Lock the thread */
508 ExWaitForRundownProtectionRelease(&Thread
->RundownProtect
);
510 /* Cleanup the power state */
511 PopCleanupPowerState((PPOWER_STATE
)&Thread
->Tcb
.PowerState
);
513 /* Call the WMI Callback for Threads */
514 //WmiTraceThread(Thread, NULL, FALSE);
516 /* Run Thread Notify Routines before we desintegrate the thread */
517 PspRunCreateThreadNotifyRoutines(Thread
, FALSE
);
519 /* Lock the Process before we modify its thread entries */
520 KeEnterCriticalRegion();
521 ExAcquirePushLockExclusive(&CurrentProcess
->ProcessLock
);
523 /* Decrease the active thread count, and check if it's 0 */
524 if (!(--CurrentProcess
->ActiveThreads
))
526 /* Set the delete flag */
527 InterlockedOr((PLONG
)&CurrentProcess
->Flags
, PSF_PROCESS_DELETE_BIT
);
529 /* Remember we are last */
532 /* Check if this termination is due to the thread dying */
533 if (ExitStatus
== STATUS_THREAD_IS_TERMINATING
)
535 /* Check if the last thread was pending */
536 if (CurrentProcess
->ExitStatus
== STATUS_PENDING
)
538 /* Use the last exit status */
539 CurrentProcess
->ExitStatus
= CurrentProcess
->
540 LastThreadExitStatus
;
545 /* Just a normal exit, write the code */
546 CurrentProcess
->ExitStatus
= ExitStatus
;
549 /* Loop all the current threads */
550 FirstEntry
= &CurrentProcess
->ThreadListHead
;
551 CurrentEntry
= FirstEntry
->Flink
;
552 while (FirstEntry
!= CurrentEntry
)
554 /* Get the thread on the list */
555 OtherThread
= CONTAINING_RECORD(CurrentEntry
,
559 /* Check if it's a thread that's still alive */
560 if ((OtherThread
!= Thread
) &&
561 !(KeReadStateThread(&OtherThread
->Tcb
)) &&
562 (ObReferenceObjectSafe(OtherThread
)))
564 /* It's a live thread and we referenced it, unlock process */
565 ExReleasePushLockExclusive(&CurrentProcess
->ProcessLock
);
566 KeLeaveCriticalRegion();
568 /* Wait on the thread */
569 KeWaitForSingleObject(OtherThread
,
575 /* Check if we had a previous thread to dereference */
576 if (PreviousThread
) ObDereferenceObject(PreviousThread
);
578 /* Remember the thread and re-lock the process */
579 PreviousThread
= OtherThread
;
580 KeEnterCriticalRegion();
581 ExAcquirePushLockExclusive(&CurrentProcess
->ProcessLock
);
584 /* Go to the next thread */
585 CurrentEntry
= CurrentEntry
->Flink
;
588 else if (ExitStatus
!= STATUS_THREAD_IS_TERMINATING
)
590 /* Write down the exit status of the last thread to get killed */
591 CurrentProcess
->LastThreadExitStatus
= ExitStatus
;
594 /* Unlock the Process */
595 ExReleasePushLockExclusive(&CurrentProcess
->ProcessLock
);
596 KeLeaveCriticalRegion();
598 /* Check if we had a previous thread to dereference */
599 if (PreviousThread
) ObDereferenceObject(PreviousThread
);
601 /* Check if the process has a debug port and if this is a user thread */
602 if ((CurrentProcess
->DebugPort
) && !(Thread
->SystemThread
))
604 /* Notify the Debug API. */
605 Last
? DbgkExitProcess(CurrentProcess
->ExitStatus
) :
606 DbgkExitThread(ExitStatus
);
609 /* Check if this is a Critical Thread */
610 if ((KdDebuggerEnabled
) && (Thread
->BreakOnTermination
))
612 /* Break to debugger */
613 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
615 CurrentProcess
->ImageFileName
);
618 /* Check if it's the last thread and this is a Critical Process */
619 if ((Last
) && (CurrentProcess
->BreakOnTermination
))
621 /* Check if a debugger is here to handle this */
622 if (KdDebuggerEnabled
)
624 /* Break to debugger */
625 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n",
627 CurrentProcess
->ImageFileName
);
631 /* Bugcheck, we can't allow this */
632 KeBugCheckEx(CRITICAL_PROCESS_DIED
,
633 (ULONG_PTR
)CurrentProcess
,
641 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
643 /* Process the Termination Ports */
644 TerminationPort
= Thread
->TerminationPort
;
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
);
657 /* Save the Create Time */
658 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
660 /* Loop trying to send message */
663 /* Send the LPC Message */
664 Status
= LpcRequestPort(TerminationPort
->Port
,
666 if ((Status
== STATUS_NO_MEMORY
) ||
667 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
669 /* Wait a bit and try again */
670 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTime
);
676 /* Dereference this LPC Port */
677 ObDereferenceObject(TerminationPort
->Port
);
679 /* Move to the next one */
680 NextPort
= TerminationPort
->Next
;
682 /* Free the Termination Port Object */
683 ExFreePoolWithTag(TerminationPort
, '=TsP');
685 /* Keep looping as long as there is a port */
686 TerminationPort
= NextPort
;
687 } while (TerminationPort
);
689 else if (((ExitStatus
== STATUS_THREAD_IS_TERMINATING
) &&
690 (Thread
->DeadThread
)) ||
691 !(Thread
->DeadThread
))
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 possibilities:
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
707 * For the 2 & 3rd scenarios, the thread has been created far enough to
708 * warrant notification to the LPC Server.
711 /* Setup the message header */
712 TerminationMsg
.h
.u2
.ZeroInit
= 0;
713 TerminationMsg
.h
.u2
.s2
.Type
= LPC_CLIENT_DIED
;
714 TerminationMsg
.h
.u1
.s1
.TotalLength
= sizeof(TerminationMsg
);
715 TerminationMsg
.h
.u1
.s1
.DataLength
= sizeof(TerminationMsg
) -
716 sizeof(PORT_MESSAGE
);
718 /* Make sure the process has an exception port */
719 if (CurrentProcess
->ExceptionPort
)
721 /* Save the Create Time */
722 TerminationMsg
.CreateTime
= Thread
->CreateTime
;
724 /* Loop trying to send message */
727 /* Send the LPC Message */
728 Status
= LpcRequestPort(CurrentProcess
->ExceptionPort
,
730 if ((Status
== STATUS_NO_MEMORY
) ||
731 (Status
== STATUS_INSUFFICIENT_RESOURCES
))
733 /* Wait a bit and try again */
734 KeDelayExecutionThread(KernelMode
, FALSE
, &ShortTime
);
742 /* Rundown Win32 Thread if there is one */
743 if (Thread
->Tcb
.Win32Thread
) PspW32ThreadCallout(Thread
,
744 PsW32ThreadCalloutExit
);
746 /* If we are the last thread and have a W32 Process */
747 if ((Last
) && (CurrentProcess
->Win32Process
))
749 /* Run it down too */
750 PspW32ProcessCallout(CurrentProcess
, FALSE
);
753 /* Make sure Stack Swap is enabled */
754 if (!Thread
->Tcb
.EnableStackSwap
)
756 /* Stack swap really shouldn't be disabled during exit! */
757 KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT
, 0, 0, 0, 0);
760 /* Cancel I/O for the thread. */
761 IoCancelThreadIo(Thread
);
766 /* FIXME: Rundown Registry Notifications (NtChangeNotify)
767 CmNotifyRunDown(Thread); */
769 /* Rundown Mutexes */
772 /* Check if we have a TEB */
773 Teb
= Thread
->Tcb
.Teb
;
776 /* Check if the thread is still alive */
777 if (!Thread
->DeadThread
)
779 /* Check if we need to free its stack */
780 if (Teb
->FreeStackOnTermination
)
782 /* Set the TEB's Deallocation Stack as the Base Address */
784 DeallocationStack
= Teb
->DeallocationStack
;
786 /* Free the Thread's Stack */
787 ZwFreeVirtualMemory(NtCurrentProcess(),
793 /* Free the debug handle */
794 if (Teb
->DbgSsReserved
[1]) ObCloseHandle(Teb
->DbgSsReserved
[1],
798 /* Decommit the TEB */
799 MmDeleteTeb(CurrentProcess
, Teb
);
800 Thread
->Tcb
.Teb
= NULL
;
804 LpcExitThread(Thread
);
806 /* Save the exit status and exit time */
807 Thread
->ExitStatus
= ExitStatus
;
808 KeQuerySystemTime(&Thread
->ExitTime
);
811 ASSERT(Thread
->Tcb
.CombinedApcDisable
== 0);
813 /* Check if this is the final thread or not */
816 /* Set the process exit time */
817 CurrentProcess
->ExitTime
= Thread
->ExitTime
;
819 /* Exit the process */
820 PspExitProcess(TRUE
, CurrentProcess
);
822 /* Get the process token and check if we need to audit */
823 PrimaryToken
= PsReferencePrimaryToken(CurrentProcess
);
824 if (SeDetailedAuditingWithToken(PrimaryToken
))
827 SeAuditProcessExit(CurrentProcess
);
830 /* Dereference the process token */
831 ObFastDereferenceObject(&CurrentProcess
->Token
, PrimaryToken
);
833 /* Check if this is a VDM Process and rundown the VDM DPCs if so */
834 if (CurrentProcess
->VdmObjects
) { /* VdmRundownDpcs(CurrentProcess); */ }
836 /* Kill the process in the Object Manager */
837 ObKillProcess(CurrentProcess
);
839 /* Check if we have a section object */
840 if (CurrentProcess
->SectionObject
)
842 /* Dereference and clear the Section Object */
843 ObDereferenceObject(CurrentProcess
->SectionObject
);
844 CurrentProcess
->SectionObject
= NULL
;
847 /* Check if the process is part of a job */
848 if (CurrentProcess
->Job
)
850 /* Remove the process from the job */
851 PspExitProcessFromJob(CurrentProcess
->Job
, CurrentProcess
);
856 KeEnterCriticalRegion();
858 /* Disable APC queueing, force a resumption */
859 Thread
->Tcb
.ApcQueueable
= FALSE
;
860 KeForceResumeThread(&Thread
->Tcb
);
863 KeLeaveCriticalRegion();
865 /* Flush the User APCs */
866 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, UserMode
);
869 /* Start with the first entry */
870 CurrentEntry
= FirstEntry
;
874 Apc
= CONTAINING_RECORD(CurrentEntry
, KAPC
, ApcListEntry
);
876 /* Move to the next one */
877 CurrentEntry
= CurrentEntry
->Flink
;
879 /* Rundown the APC or de-allocate it */
880 if (Apc
->RundownRoutine
)
882 /* Call its own routine */
883 Apc
->RundownRoutine(Apc
);
887 /* Do it ourselves */
891 while (CurrentEntry
!= FirstEntry
);
894 /* Clean address space if this was the last thread */
895 if (Last
) MmCleanProcessAddressSpace(CurrentProcess
);
897 /* Call the Lego routine */
898 if (Thread
->Tcb
.LegoData
) PspRunLegoRoutine(&Thread
->Tcb
);
900 /* Flush the APC queue, which should be empty */
901 FirstEntry
= KeFlushQueueApc(&Thread
->Tcb
, KernelMode
);
902 if ((FirstEntry
) || (Thread
->Tcb
.CombinedApcDisable
!= 0))
905 KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT
,
906 (ULONG_PTR
)FirstEntry
,
907 Thread
->Tcb
.CombinedApcDisable
,
912 /* Signal the process if this was the last thread */
913 if (Last
) KeSetProcess(&CurrentProcess
->Pcb
, 0, FALSE
);
915 /* Terminate the Thread from the Scheduler */
916 KeTerminateThread(0);
921 PsExitSpecialApc(IN PKAPC Apc
,
922 IN OUT PKNORMAL_ROUTINE
* NormalRoutine
,
923 IN OUT PVOID
* NormalContext
,
924 IN OUT PVOID
* SystemArgument1
,
925 IN OUT PVOID
* SystemArgument2
)
929 PSTRACE(PS_KILL_DEBUG
,
930 "Apc: %p SystemArgument2: %p \n", Apc
, SystemArgument2
);
932 /* Don't do anything unless we are in User-Mode */
933 if (Apc
->SystemArgument2
)
936 Status
= PtrToUlong(Apc
->NormalContext
);
937 PspExitApcRundown(Apc
);
939 /* Terminate the Thread */
940 PspExitThread(Status
);
946 PspExitNormalApc(IN PVOID NormalContext
,
947 IN PVOID SystemArgument1
,
948 IN PVOID SystemArgument2
)
950 PKAPC Apc
= (PKAPC
)SystemArgument1
;
951 PETHREAD Thread
= PsGetCurrentThread();
953 PSTRACE(PS_KILL_DEBUG
, "SystemArgument2: %p \n", SystemArgument2
);
955 /* This should never happen */
956 ASSERT(!(((ULONG_PTR
)SystemArgument2
) & 1));
958 /* If we're here, this is not a System Thread, so kill it from User-Mode */
961 OriginalApcEnvironment
,
968 /* Now insert the APC with the User-Mode Flag */
969 if (!(KeInsertQueueApc(Apc
,
971 (PVOID
)((ULONG_PTR
)SystemArgument2
| 1),
974 /* Failed to insert, free the APC */
975 PspExitApcRundown(Apc
);
978 /* Set the APC Pending flag */
979 Thread
->Tcb
.ApcState
.UserApcPending
= TRUE
;
983 * See "Windows Internals" - Chapter 13, Page 49
987 PspTerminateThreadByPointer(IN PETHREAD Thread
,
988 IN NTSTATUS ExitStatus
,
992 NTSTATUS Status
= STATUS_SUCCESS
;
995 PSTRACE(PS_KILL_DEBUG
, "Thread: %p ExitStatus: %d\n", Thread
, ExitStatus
);
998 /* Check if this is a Critical Thread, and Bugcheck */
999 if (Thread
->BreakOnTermination
)
1001 /* Break to debugger */
1002 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
1004 Thread
->ThreadsProcess
->ImageFileName
);
1007 /* Check if we are already inside the thread */
1008 if ((bSelf
) || (PsGetCurrentThread() == Thread
))
1010 /* This should only happen at passive */
1011 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL
);
1013 /* Mark it as terminated */
1014 PspSetCrossThreadFlag(Thread
, CT_TERMINATED_BIT
);
1016 /* Directly terminate the thread */
1017 PspExitThread(ExitStatus
);
1020 /* This shouldn't be a system thread */
1021 if (Thread
->SystemThread
) return STATUS_ACCESS_DENIED
;
1023 /* Allocate the APC */
1024 Apc
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KAPC
), TAG_TERMINATE_APC
);
1025 if (!Apc
) return STATUS_INSUFFICIENT_RESOURCES
;
1027 /* Set the Terminated Flag */
1028 Flags
= Thread
->CrossThreadFlags
| CT_TERMINATED_BIT
;
1030 /* Set it, and check if it was already set while we were running */
1031 if (!(InterlockedExchange((PLONG
)&Thread
->CrossThreadFlags
, Flags
) &
1034 /* Initialize a Kernel Mode APC to Kill the Thread */
1035 KeInitializeApc(Apc
,
1037 OriginalApcEnvironment
,
1042 UlongToPtr(ExitStatus
));
1044 /* Insert it into the APC Queue */
1045 if (!KeInsertQueueApc(Apc
, Apc
, NULL
, 2))
1047 /* The APC was already in the queue, fail */
1048 Status
= STATUS_UNSUCCESSFUL
;
1052 /* Forcefully resume the thread and return */
1053 KeForceResumeThread(&Thread
->Tcb
);
1058 /* We failed, free the APC */
1059 ExFreePoolWithTag(Apc
, TAG_TERMINATE_APC
);
1067 PspIsProcessExiting(IN PEPROCESS Process
)
1069 return Process
->Flags
& PSF_PROCESS_EXITING_BIT
;
1074 PspExitProcess(IN BOOLEAN LastThread
,
1075 IN PEPROCESS Process
)
1079 PSTRACE(PS_KILL_DEBUG
,
1080 "LastThread: %u Process: %p\n", LastThread
, Process
);
1081 PSREFTRACE(Process
);
1083 /* Set Process Exit flag */
1084 InterlockedOr((PLONG
)&Process
->Flags
, PSF_PROCESS_EXITING_BIT
);
1086 /* Check if we are the last thread */
1089 /* Notify the WMI Process Callback */
1090 //WmiTraceProcess(Process, FALSE);
1092 /* Run the Notification Routines */
1093 PspRunCreateProcessNotifyRoutines(Process
, FALSE
);
1096 /* Cleanup the power state */
1097 PopCleanupPowerState((PPOWER_STATE
)&Process
->Pcb
.PowerState
);
1099 /* Clear the security port */
1100 if (!Process
->SecurityPort
)
1102 /* So we don't double-dereference */
1103 Process
->SecurityPort
= (PVOID
)1;
1105 else if (Process
->SecurityPort
!= (PVOID
)1)
1107 /* Dereference it */
1108 ObDereferenceObject(Process
->SecurityPort
);
1109 Process
->SecurityPort
= (PVOID
)1;
1112 /* Check if we are the last thread */
1115 /* Check if we have to set the Timer Resolution */
1116 if (Process
->SetTimerResolution
)
1118 /* Set it to default */
1119 ZwSetTimerResolution(KeMaximumIncrement
, 0, &Actual
);
1122 /* Check if we are part of a Job that has a completion port */
1123 if ((Process
->Job
) && (Process
->Job
->CompletionPort
))
1125 /* FIXME: Check job status code and do I/O completion if needed */
1128 /* FIXME: Notify the Prefetcher */
1132 /* Clear process' address space here */
1133 MmCleanProcessAddressSpace(Process
);
1137 /* PUBLIC FUNCTIONS **********************************************************/
1144 PsTerminateSystemThread(IN NTSTATUS ExitStatus
)
1146 PETHREAD Thread
= PsGetCurrentThread();
1148 /* Make sure this is a system thread */
1149 if (!Thread
->SystemThread
) return STATUS_INVALID_PARAMETER
;
1151 /* Terminate it for real */
1152 return PspTerminateThreadByPointer(Thread
, ExitStatus
, TRUE
);
1160 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL
,
1161 IN NTSTATUS ExitStatus
)
1164 PEPROCESS Process
, CurrentProcess
= PsGetCurrentProcess();
1165 PETHREAD Thread
, CurrentThread
= PsGetCurrentThread();
1166 BOOLEAN KillByHandle
;
1168 PSTRACE(PS_KILL_DEBUG
,
1169 "ProcessHandle: %p ExitStatus: %d\n", ProcessHandle
, ExitStatus
);
1171 /* Were we passed a process handle? */
1174 /* Yes we were, use it */
1175 KillByHandle
= TRUE
;
1179 /* We weren't... we assume this is suicide */
1180 KillByHandle
= FALSE
;
1181 ProcessHandle
= NtCurrentProcess();
1184 /* Get the Process Object */
1185 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1188 KeGetPreviousMode(),
1191 if (!NT_SUCCESS(Status
)) return(Status
);
1193 /* Check if this is a Critical Process, and Bugcheck */
1194 if (Process
->BreakOnTermination
)
1196 /* Break to debugger */
1197 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
1199 Process
->ImageFileName
);
1202 /* Lock the Process */
1203 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
1205 /* Failed to lock, fail */
1206 ObDereferenceObject(Process
);
1207 return STATUS_PROCESS_IS_TERMINATING
;
1210 /* Set the delete flag, unless the process is comitting suicide */
1211 if (KillByHandle
) PspSetProcessFlag(Process
, PSF_PROCESS_DELETE_BIT
);
1213 /* Get the first thread */
1214 Status
= STATUS_NOTHING_TO_TERMINATE
;
1215 Thread
= PsGetNextProcessThread(Process
, NULL
);
1218 /* We know we have at least a thread */
1219 Status
= STATUS_SUCCESS
;
1221 /* Loop and kill the others */
1224 /* Ensure it's not ours*/
1225 if (Thread
!= CurrentThread
)
1228 PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1231 /* Move to the next thread */
1232 Thread
= PsGetNextProcessThread(Process
, Thread
);
1236 /* Unlock the process */
1237 ExReleaseRundownProtection(&Process
->RundownProtect
);
1239 /* Check if we are killing ourselves */
1240 if (Process
== CurrentProcess
)
1242 /* Also make sure the caller gave us our handle */
1245 /* Dereference the process */
1246 ObDereferenceObject(Process
);
1248 /* Terminate ourselves */
1249 PspTerminateThreadByPointer(CurrentThread
, ExitStatus
, TRUE
);
1252 else if (ExitStatus
== DBG_TERMINATE_PROCESS
)
1254 /* Disable debugging on this process */
1255 DbgkClearProcessDebugObject(Process
, NULL
);
1258 /* Check if there was nothing to terminate, or if we have a Debug Port */
1259 if ((Status
== STATUS_NOTHING_TO_TERMINATE
) ||
1260 ((Process
->DebugPort
) && (KillByHandle
)))
1262 /* Clear the handle table */
1263 ObClearProcessHandleTable(Process
);
1265 /* Return status now */
1266 Status
= STATUS_SUCCESS
;
1269 /* Decrease the reference count we added */
1270 ObDereferenceObject(Process
);
1278 NtTerminateThread(IN HANDLE ThreadHandle
,
1279 IN NTSTATUS ExitStatus
)
1282 PETHREAD CurrentThread
= PsGetCurrentThread();
1285 PSTRACE(PS_KILL_DEBUG
,
1286 "ThreadHandle: %p ExitStatus: %d\n", ThreadHandle
, ExitStatus
);
1288 /* Handle the special NULL case */
1291 /* Check if we're the only thread left */
1292 if (PsGetCurrentProcess()->ActiveThreads
== 1)
1294 /* This is invalid */
1295 return STATUS_CANT_TERMINATE_SELF
;
1298 /* Terminate us directly */
1301 else if (ThreadHandle
== NtCurrentThread())
1304 /* Terminate this thread */
1305 return PspTerminateThreadByPointer(CurrentThread
,
1310 /* We are terminating another thread, get the Thread Object */
1311 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1314 KeGetPreviousMode(),
1317 if (!NT_SUCCESS(Status
)) return Status
;
1319 /* Check to see if we're running in the same thread */
1320 if (Thread
!= CurrentThread
)
1323 Status
= PspTerminateThreadByPointer(Thread
, ExitStatus
, FALSE
);
1325 /* Dereference the Thread and return */
1326 ObDereferenceObject(Thread
);
1330 /* Dereference the thread and terminate ourselves */
1331 ObDereferenceObject(Thread
);
1341 NtRegisterThreadTerminatePort(IN HANDLE PortHandle
)
1344 PTERMINATION_PORT TerminationPort
;
1345 PVOID TerminationLpcPort
;
1348 PSTRACE(PS_KILL_DEBUG
, "PortHandle: %p\n", PortHandle
);
1351 Status
= ObReferenceObjectByHandle(PortHandle
,
1354 KeGetPreviousMode(),
1355 &TerminationLpcPort
,
1357 if (!NT_SUCCESS(Status
)) return(Status
);
1359 /* Allocate the Port and make sure it suceeded */
1360 TerminationPort
= ExAllocatePoolWithTag(NonPagedPool
,
1361 sizeof(TERMINATION_PORT
),
1365 /* Associate the Port */
1366 Thread
= PsGetCurrentThread();
1367 TerminationPort
->Port
= TerminationLpcPort
;
1368 TerminationPort
->Next
= Thread
->TerminationPort
;
1369 Thread
->TerminationPort
= TerminationPort
;
1371 /* Return success */
1372 return STATUS_SUCCESS
;
1375 /* Dereference and Fail */
1376 ObDereferenceObject(TerminationLpcPort
);
1377 return STATUS_INSUFFICIENT_RESOURCES
;