Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenkill.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ps/kill.c 00005 * PURPOSE: Process Manager: Process and Thread Termination 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Filip Navara (xnavara@reactos.org) 00008 * Thomas Weidenmueller (w3seek@reactos.org 00009 */ 00010 00011 /* INCLUDES *****************************************************************/ 00012 00013 #include <ntoskrnl.h> 00014 #define NDEBUG 00015 #include <debug.h> 00016 00017 /* GLOBALS *******************************************************************/ 00018 00019 LIST_ENTRY PspReaperListHead = { NULL, NULL }; 00020 WORK_QUEUE_ITEM PspReaperWorkItem; 00021 LARGE_INTEGER ShortTime = {{-10 * 100 * 1000, -1}}; 00022 00023 /* PRIVATE FUNCTIONS *********************************************************/ 00024 00025 VOID 00026 NTAPI 00027 PspCatchCriticalBreak(IN PCHAR Message, 00028 IN PVOID ProcessOrThread, 00029 IN PCHAR ImageName) 00030 { 00031 CHAR Action[2]; 00032 BOOLEAN Handled = FALSE; 00033 PAGED_CODE(); 00034 00035 /* Check if a debugger is enabled */ 00036 if (KdDebuggerEnabled) 00037 { 00038 /* Print out the message */ 00039 DbgPrint(Message, ProcessOrThread, ImageName); 00040 do 00041 { 00042 /* If a debugger isn't present, don't prompt */ 00043 if (KdDebuggerNotPresent) break; 00044 00045 /* A debuger is active, prompt for action */ 00046 DbgPrompt("Break, or Ignore (bi)?", Action, sizeof(Action)); 00047 switch (Action[0]) 00048 { 00049 /* Break */ 00050 case 'B': case 'b': 00051 00052 /* Do a breakpoint */ 00053 DbgBreakPoint(); 00054 00055 /* Ignore */ 00056 case 'I': case 'i': 00057 00058 /* Handle it */ 00059 Handled = TRUE; 00060 00061 /* Unrecognized */ 00062 default: 00063 break; 00064 } 00065 } while (!Handled); 00066 } 00067 00068 /* Did we ultimately handle this? */ 00069 if (!Handled) 00070 { 00071 /* We didn't, bugcheck */ 00072 KeBugCheckEx(CRITICAL_OBJECT_TERMINATION, 00073 ((PKPROCESS)ProcessOrThread)->Header.Type, 00074 (ULONG_PTR)ProcessOrThread, 00075 (ULONG_PTR)ImageName, 00076 (ULONG_PTR)Message); 00077 } 00078 } 00079 00080 NTSTATUS 00081 NTAPI 00082 PspTerminateProcess(IN PEPROCESS Process, 00083 IN NTSTATUS ExitStatus) 00084 { 00085 PETHREAD Thread; 00086 NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE; 00087 PAGED_CODE(); 00088 PSTRACE(PS_KILL_DEBUG, 00089 "Process: %p ExitStatus: %p\n", Process, ExitStatus); 00090 PSREFTRACE(Process); 00091 00092 /* Check if this is a Critical Process */ 00093 if (Process->BreakOnTermination) 00094 { 00095 /* Break to debugger */ 00096 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n", 00097 Process, 00098 Process->ImageFileName); 00099 } 00100 00101 /* Set the delete flag */ 00102 InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT); 00103 00104 /* Get the first thread */ 00105 Thread = PsGetNextProcessThread(Process, NULL); 00106 while (Thread) 00107 { 00108 /* Kill it */ 00109 PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); 00110 Thread = PsGetNextProcessThread(Process, Thread); 00111 00112 /* We had at least one thread, so termination is OK */ 00113 Status = STATUS_SUCCESS; 00114 } 00115 00116 /* Check if there was nothing to terminate or if we have a debug port */ 00117 if ((Status == STATUS_NOTHING_TO_TERMINATE) || (Process->DebugPort)) 00118 { 00119 /* Clear the handle table anyway */ 00120 ObClearProcessHandleTable(Process); 00121 } 00122 00123 /* Return status */ 00124 return Status; 00125 } 00126 00127 NTSTATUS 00128 NTAPI 00129 PsTerminateProcess(IN PEPROCESS Process, 00130 IN NTSTATUS ExitStatus) 00131 { 00132 /* Call the internal API */ 00133 return PspTerminateProcess(Process, ExitStatus); 00134 } 00135 00136 VOID 00137 NTAPI 00138 PspShutdownProcessManager(VOID) 00139 { 00140 PEPROCESS Process = NULL; 00141 00142 /* Loop every process */ 00143 Process = PsGetNextProcess(Process); 00144 while (Process) 00145 { 00146 /* Make sure this isn't the idle or initial process */ 00147 if ((Process != PsInitialSystemProcess) && (Process != PsIdleProcess)) 00148 { 00149 /* Kill it */ 00150 PspTerminateProcess(Process, STATUS_SYSTEM_SHUTDOWN); 00151 } 00152 00153 /* Get the next process */ 00154 Process = PsGetNextProcess(Process); 00155 } 00156 } 00157 00158 VOID 00159 NTAPI 00160 PspExitApcRundown(IN PKAPC Apc) 00161 { 00162 PAGED_CODE(); 00163 00164 /* Free the APC */ 00165 ExFreePool(Apc); 00166 } 00167 00168 VOID 00169 NTAPI 00170 PspReapRoutine(IN PVOID Context) 00171 { 00172 PSINGLE_LIST_ENTRY NextEntry; 00173 PETHREAD Thread; 00174 PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context); 00175 00176 /* Start main loop */ 00177 do 00178 { 00179 /* Write magic value and return the next entry to process */ 00180 NextEntry = InterlockedExchangePointer(&PspReaperListHead.Flink, 00181 (PVOID)1); 00182 ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1)); 00183 00184 /* Start inner loop */ 00185 do 00186 { 00187 /* Get the first Thread Entry */ 00188 Thread = CONTAINING_RECORD(NextEntry, ETHREAD, ReaperLink); 00189 00190 /* Delete this entry's kernel stack */ 00191 MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase, 00192 Thread->Tcb.LargeStack); 00193 Thread->Tcb.InitialStack = NULL; 00194 00195 /* Move to the next entry */ 00196 NextEntry = NextEntry->Next; 00197 00198 /* Dereference this thread */ 00199 ObDereferenceObject(Thread); 00200 } while ((NextEntry != NULL) && (NextEntry != (PVOID)1)); 00201 00202 /* Remove magic value, keep looping if it got changed */ 00203 } while (InterlockedCompareExchangePointer(&PspReaperListHead.Flink, 00204 0, 00205 (PVOID)1) != (PVOID)1); 00206 } 00207 00208 VOID 00209 NTAPI 00210 PspDeleteProcess(IN PVOID ObjectBody) 00211 { 00212 PEPROCESS Process = (PEPROCESS)ObjectBody; 00213 KAPC_STATE ApcState; 00214 PAGED_CODE(); 00215 PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody); 00216 PSREFTRACE(Process); 00217 00218 /* Check if it has an Active Process Link */ 00219 if (Process->ActiveProcessLinks.Flink) 00220 { 00221 /* Remove it from the Active List */ 00222 KeAcquireGuardedMutex(&PspActiveProcessMutex); 00223 RemoveEntryList(&Process->ActiveProcessLinks); 00224 KeReleaseGuardedMutex(&PspActiveProcessMutex); 00225 } 00226 00227 /* Check for Auditing information */ 00228 if (Process->SeAuditProcessCreationInfo.ImageFileName) 00229 { 00230 /* Free it */ 00231 ExFreePool(Process->SeAuditProcessCreationInfo.ImageFileName); 00232 Process->SeAuditProcessCreationInfo.ImageFileName = NULL; 00233 } 00234 00235 /* Check if we have a job */ 00236 if (Process->Job) 00237 { 00238 /* Remove the process from the job */ 00239 PspRemoveProcessFromJob(Process, Process->Job); 00240 00241 /* Dereference it */ 00242 ObDereferenceObject(Process->Job); 00243 Process->Job = NULL; 00244 } 00245 00246 /* Increase the stack count */ 00247 Process->Pcb.StackCount++; 00248 00249 /* Check if we have a debug port */ 00250 if (Process->DebugPort) 00251 { 00252 /* Deference the Debug Port */ 00253 ObDereferenceObject(Process->DebugPort); 00254 Process->DebugPort = NULL; 00255 } 00256 00257 /* Check if we have an exception port */ 00258 if (Process->ExceptionPort) 00259 { 00260 /* Deference the Exception Port */ 00261 ObDereferenceObject(Process->ExceptionPort); 00262 Process->ExceptionPort = NULL; 00263 } 00264 00265 /* Check if we have a section object */ 00266 if (Process->SectionObject) 00267 { 00268 /* Deference the Section Object */ 00269 ObDereferenceObject(Process->SectionObject); 00270 Process->SectionObject = NULL; 00271 } 00272 00273 #if defined(_X86_) 00274 /* Clean Ldt and Vdm objects */ 00275 PspDeleteLdt(Process); 00276 PspDeleteVdmObjects(Process); 00277 #endif 00278 00279 /* Delete the Object Table */ 00280 if (Process->ObjectTable) 00281 { 00282 /* Attach to the process */ 00283 KeStackAttachProcess(&Process->Pcb, &ApcState); 00284 00285 /* Kill the Object Info */ 00286 ObKillProcess(Process); 00287 00288 /* Detach */ 00289 KeUnstackDetachProcess(&ApcState); 00290 } 00291 00292 /* Check if we have an address space, and clean it */ 00293 if (Process->HasAddressSpace) 00294 { 00295 /* Attach to the process */ 00296 KeStackAttachProcess(&Process->Pcb, &ApcState); 00297 00298 /* Clean the Address Space */ 00299 PspExitProcess(FALSE, Process); 00300 00301 /* Detach */ 00302 KeUnstackDetachProcess(&ApcState); 00303 00304 /* Completely delete the Address Space */ 00305 MmDeleteProcessAddressSpace(Process); 00306 } 00307 00308 /* See if we have a PID */ 00309 if (Process->UniqueProcessId) 00310 { 00311 /* Delete the PID */ 00312 if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId, NULL))) 00313 { 00314 /* Something wrong happened, bugcheck */ 00315 KeBugCheck(CID_HANDLE_DELETION); 00316 } 00317 } 00318 00319 /* Cleanup security information */ 00320 PspDeleteProcessSecurity(Process); 00321 00322 /* Check if we have kept information on the Working Set */ 00323 if (Process->WorkingSetWatch) 00324 { 00325 /* Free it */ 00326 ExFreePool(Process->WorkingSetWatch); 00327 00328 /* And return the quota it was taking up */ 00329 PsReturnProcessNonPagedPoolQuota(Process, 0x2000); 00330 } 00331 00332 /* Dereference the Device Map */ 00333 ObDereferenceDeviceMap(Process); 00334 00335 /* Destroy the Quota Block */ 00336 PspDestroyQuotaBlock(Process); 00337 } 00338 00339 VOID 00340 NTAPI 00341 PspDeleteThread(IN PVOID ObjectBody) 00342 { 00343 PETHREAD Thread = (PETHREAD)ObjectBody; 00344 PEPROCESS Process = Thread->ThreadsProcess; 00345 PAGED_CODE(); 00346 PSTRACE(PS_KILL_DEBUG, "ObjectBody: %p\n", ObjectBody); 00347 PSREFTRACE(Thread); 00348 ASSERT(Thread->Tcb.Win32Thread == NULL); 00349 00350 /* Check if we have a stack */ 00351 if (Thread->Tcb.InitialStack) 00352 { 00353 /* Release it */ 00354 MmDeleteKernelStack((PVOID)Thread->Tcb.StackBase, 00355 Thread->Tcb.LargeStack); 00356 } 00357 00358 /* Check if we have a CID Handle */ 00359 if (Thread->Cid.UniqueThread) 00360 { 00361 /* Delete the CID Handle */ 00362 if (!(ExDestroyHandle(PspCidTable, Thread->Cid.UniqueThread, NULL))) 00363 { 00364 /* Something wrong happened, bugcheck */ 00365 KeBugCheck(CID_HANDLE_DELETION); 00366 } 00367 } 00368 00369 /* Cleanup impersionation information */ 00370 PspDeleteThreadSecurity(Thread); 00371 00372 /* Make sure the thread was inserted, before continuing */ 00373 if (!Process) return; 00374 00375 /* Check if the thread list is valid */ 00376 if (Thread->ThreadListEntry.Flink) 00377 { 00378 /* Lock the thread's process */ 00379 KeEnterCriticalRegion(); 00380 ExAcquirePushLockExclusive(&Process->ProcessLock); 00381 00382 /* Remove us from the list */ 00383 RemoveEntryList(&Thread->ThreadListEntry); 00384 00385 /* Release the lock */ 00386 ExReleasePushLockExclusive(&Process->ProcessLock); 00387 KeLeaveCriticalRegion(); 00388 } 00389 00390 /* Dereference the Process */ 00391 ObDereferenceObject(Process); 00392 } 00393 00394 /* 00395 * FUNCTION: Terminates the current thread 00396 * See "Windows Internals" - Chapter 13, Page 50-53 00397 */ 00398 VOID 00399 NTAPI 00400 PspExitThread(IN NTSTATUS ExitStatus) 00401 { 00402 CLIENT_DIED_MSG TerminationMsg; 00403 NTSTATUS Status; 00404 PTEB Teb; 00405 PEPROCESS CurrentProcess; 00406 PETHREAD Thread, OtherThread, PreviousThread = NULL; 00407 PVOID DeallocationStack; 00408 SIZE_T Dummy; 00409 BOOLEAN Last = FALSE; 00410 PTERMINATION_PORT TerminationPort, NextPort; 00411 PLIST_ENTRY FirstEntry, CurrentEntry; 00412 PKAPC Apc; 00413 PTOKEN PrimaryToken; 00414 PAGED_CODE(); 00415 PSTRACE(PS_KILL_DEBUG, "ExitStatus: %p\n", ExitStatus); 00416 00417 /* Get the Current Thread and Process */ 00418 Thread = PsGetCurrentThread(); 00419 CurrentProcess = Thread->ThreadsProcess; 00420 ASSERT((Thread) == PsGetCurrentThread()); 00421 00422 /* Can't terminate a thread if it attached another process */ 00423 if (KeIsAttachedProcess()) 00424 { 00425 /* Bugcheck */ 00426 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 00427 (ULONG_PTR)CurrentProcess, 00428 (ULONG_PTR)Thread->Tcb.ApcState.Process, 00429 (ULONG_PTR)Thread->Tcb.ApcStateIndex, 00430 (ULONG_PTR)Thread); 00431 } 00432 00433 /* Lower to Passive Level */ 00434 KeLowerIrql(PASSIVE_LEVEL); 00435 00436 /* Can't be a worker thread */ 00437 if (Thread->ActiveExWorker) 00438 { 00439 /* Bugcheck */ 00440 KeBugCheckEx(ACTIVE_EX_WORKER_THREAD_TERMINATION, 00441 (ULONG_PTR)Thread, 00442 0, 00443 0, 00444 0); 00445 } 00446 00447 /* Can't have pending APCs */ 00448 if (Thread->Tcb.CombinedApcDisable != 0) 00449 { 00450 /* Bugcheck */ 00451 KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT, 00452 0, 00453 Thread->Tcb.CombinedApcDisable, 00454 0, 00455 1); 00456 } 00457 00458 /* Lock the thread */ 00459 ExWaitForRundownProtectionRelease(&Thread->RundownProtect); 00460 00461 /* Cleanup the power state */ 00462 PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState); 00463 00464 /* Call the WMI Callback for Threads */ 00465 //WmiTraceThread(Thread, NULL, FALSE); 00466 00467 /* Run Thread Notify Routines before we desintegrate the thread */ 00468 PspRunCreateThreadNotifyRoutines(Thread, FALSE); 00469 00470 /* Lock the Process before we modify its thread entries */ 00471 KeEnterCriticalRegion(); 00472 ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock); 00473 00474 /* Decrease the active thread count, and check if it's 0 */ 00475 if (!(--CurrentProcess->ActiveThreads)) 00476 { 00477 /* Set the delete flag */ 00478 InterlockedOr((PLONG)&CurrentProcess->Flags, PSF_PROCESS_DELETE_BIT); 00479 00480 /* Remember we are last */ 00481 Last = TRUE; 00482 00483 /* Check if this termination is due to the thread dying */ 00484 if (ExitStatus == STATUS_THREAD_IS_TERMINATING) 00485 { 00486 /* Check if the last thread was pending */ 00487 if (CurrentProcess->ExitStatus == STATUS_PENDING) 00488 { 00489 /* Use the last exit status */ 00490 CurrentProcess->ExitStatus = CurrentProcess-> 00491 LastThreadExitStatus; 00492 } 00493 } 00494 else 00495 { 00496 /* Just a normal exit, write the code */ 00497 CurrentProcess->ExitStatus = ExitStatus; 00498 } 00499 00500 /* Loop all the current threads */ 00501 FirstEntry = &CurrentProcess->ThreadListHead; 00502 CurrentEntry = FirstEntry->Flink; 00503 while (FirstEntry != CurrentEntry) 00504 { 00505 /* Get the thread on the list */ 00506 OtherThread = CONTAINING_RECORD(CurrentEntry, 00507 ETHREAD, 00508 ThreadListEntry); 00509 00510 /* Check if it's a thread that's still alive */ 00511 if ((OtherThread != Thread) && 00512 !(KeReadStateThread(&OtherThread->Tcb)) && 00513 (ObReferenceObjectSafe(OtherThread))) 00514 { 00515 /* It's a live thread and we referenced it, unlock process */ 00516 ExReleasePushLockExclusive(&CurrentProcess->ProcessLock); 00517 KeLeaveCriticalRegion(); 00518 00519 /* Wait on the thread */ 00520 KeWaitForSingleObject(OtherThread, 00521 Executive, 00522 KernelMode, 00523 FALSE, 00524 NULL); 00525 00526 /* Check if we had a previous thread to dereference */ 00527 if (PreviousThread) ObDereferenceObject(PreviousThread); 00528 00529 /* Remember the thread and re-lock the process */ 00530 PreviousThread = OtherThread; 00531 KeEnterCriticalRegion(); 00532 ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock); 00533 } 00534 00535 /* Go to the next thread */ 00536 CurrentEntry = CurrentEntry->Flink; 00537 } 00538 } 00539 else if (ExitStatus != STATUS_THREAD_IS_TERMINATING) 00540 { 00541 /* Write down the exit status of the last thread to get killed */ 00542 CurrentProcess->LastThreadExitStatus = ExitStatus; 00543 } 00544 00545 /* Unlock the Process */ 00546 ExReleasePushLockExclusive(&CurrentProcess->ProcessLock); 00547 KeLeaveCriticalRegion(); 00548 00549 /* Check if we had a previous thread to dereference */ 00550 if (PreviousThread) ObDereferenceObject(PreviousThread); 00551 00552 /* Check if the process has a debug port and if this is a user thread */ 00553 if ((CurrentProcess->DebugPort) && !(Thread->SystemThread)) 00554 { 00555 /* Notify the Debug API. */ 00556 Last ? DbgkExitProcess(CurrentProcess->ExitStatus) : 00557 DbgkExitThread(ExitStatus); 00558 } 00559 00560 /* Check if this is a Critical Thread */ 00561 if ((KdDebuggerEnabled) && (Thread->BreakOnTermination)) 00562 { 00563 /* Break to debugger */ 00564 PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n", 00565 Thread, 00566 CurrentProcess->ImageFileName); 00567 } 00568 00569 /* Check if it's the last thread and this is a Critical Process */ 00570 if ((Last) && (CurrentProcess->BreakOnTermination)) 00571 { 00572 /* Check if a debugger is here to handle this */ 00573 if (KdDebuggerEnabled) 00574 { 00575 /* Break to debugger */ 00576 PspCatchCriticalBreak("Critical process 0x%p (in %s) exited\n", 00577 CurrentProcess, 00578 CurrentProcess->ImageFileName); 00579 } 00580 else 00581 { 00582 /* Bugcheck, we can't allow this */ 00583 KeBugCheckEx(CRITICAL_PROCESS_DIED, 00584 (ULONG_PTR)CurrentProcess, 00585 0, 00586 0, 00587 0); 00588 } 00589 } 00590 00591 /* Sanity check */ 00592 ASSERT(Thread->Tcb.CombinedApcDisable == 0); 00593 00594 /* Process the Termination Ports */ 00595 TerminationPort = Thread->TerminationPort; 00596 if (TerminationPort) 00597 { 00598 /* Setup the message header */ 00599 TerminationMsg.h.u2.ZeroInit = 0; 00600 TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; 00601 TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); 00602 TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - 00603 sizeof(PORT_MESSAGE); 00604 00605 /* Loop each port */ 00606 do 00607 { 00608 /* Save the Create Time */ 00609 TerminationMsg.CreateTime = Thread->CreateTime; 00610 00611 /* Loop trying to send message */ 00612 while (TRUE) 00613 { 00614 /* Send the LPC Message */ 00615 Status = LpcRequestPort(TerminationPort->Port, 00616 &TerminationMsg.h); 00617 if ((Status == STATUS_NO_MEMORY) || 00618 (Status == STATUS_INSUFFICIENT_RESOURCES)) 00619 { 00620 /* Wait a bit and try again */ 00621 KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); 00622 continue; 00623 } 00624 break; 00625 } 00626 00627 /* Dereference this LPC Port */ 00628 ObDereferenceObject(TerminationPort->Port); 00629 00630 /* Move to the next one */ 00631 NextPort = TerminationPort->Next; 00632 00633 /* Free the Termination Port Object */ 00634 ExFreePool(TerminationPort); 00635 00636 /* Keep looping as long as there is a port */ 00637 TerminationPort = NextPort; 00638 } while (TerminationPort); 00639 } 00640 else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) && 00641 (Thread->DeadThread)) || 00642 !(Thread->DeadThread)) 00643 { 00644 /* 00645 * This case is special and deserves some extra comments. What 00646 * basically happens here is that this thread doesn't have a termination 00647 * port, which means that it died before being fully created. Since we 00648 * still have to notify an LPC Server, we'll use the exception port, 00649 * which we know exists. However, we need to know how far the thread 00650 * actually got created. We have three possibilites: 00651 * 00652 * - NtCreateThread returned an error really early: DeadThread is set. 00653 * - NtCreateThread managed to create the thread: DeadThread is off. 00654 * - NtCreateThread was creating the thread (with Deadthread set, 00655 * but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING 00656 * is our exit code.) 00657 * 00658 * For the 2 & 3rd scenarios, the thread has been created far enough to 00659 * warrant notification to the LPC Server. 00660 */ 00661 00662 /* Setup the message header */ 00663 TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED; 00664 TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg); 00665 TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) - 00666 sizeof(PORT_MESSAGE); 00667 00668 /* Make sure the process has an exception port */ 00669 if (CurrentProcess->ExceptionPort) 00670 { 00671 /* Save the Create Time */ 00672 TerminationMsg.CreateTime = Thread->CreateTime; 00673 00674 /* Loop trying to send message */ 00675 while (TRUE) 00676 { 00677 /* Send the LPC Message */ 00678 Status = LpcRequestPort(CurrentProcess->ExceptionPort, 00679 &TerminationMsg.h); 00680 if ((Status == STATUS_NO_MEMORY) || 00681 (Status == STATUS_INSUFFICIENT_RESOURCES)) 00682 { 00683 /* Wait a bit and try again */ 00684 KeDelayExecutionThread(KernelMode, FALSE, &ShortTime); 00685 continue; 00686 } 00687 break; 00688 } 00689 } 00690 } 00691 00692 /* Rundown Win32 Thread if there is one */ 00693 if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread, 00694 PsW32ThreadCalloutExit); 00695 00696 /* If we are the last thread and have a W32 Process */ 00697 if ((Last) && (CurrentProcess->Win32Process)) 00698 { 00699 /* Run it down too */ 00700 PspW32ProcessCallout(CurrentProcess, FALSE); 00701 } 00702 00703 /* Make sure Stack Swap is enabled */ 00704 if (!Thread->Tcb.EnableStackSwap) 00705 { 00706 /* Stack swap really shouldn't be disabled during exit! */ 00707 KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0); 00708 } 00709 00710 /* Cancel I/O for the thread. */ 00711 IoCancelThreadIo(Thread); 00712 00713 /* Rundown Timers */ 00714 ExTimerRundown(); 00715 00716 /* FIXME: Rundown Registry Notifications (NtChangeNotify) 00717 CmNotifyRunDown(Thread); */ 00718 00719 /* Rundown Mutexes */ 00720 KeRundownThread(); 00721 00722 /* Check if we have a TEB */ 00723 Teb = Thread->Tcb.Teb; 00724 if (Teb) 00725 { 00726 /* Check if the thread is still alive */ 00727 if (!Thread->DeadThread) 00728 { 00729 /* Check if we need to free its stack */ 00730 if (Teb->FreeStackOnTermination) 00731 { 00732 /* Set the TEB's Deallocation Stack as the Base Address */ 00733 Dummy = 0; 00734 DeallocationStack = Teb->DeallocationStack; 00735 00736 /* Free the Thread's Stack */ 00737 ZwFreeVirtualMemory(NtCurrentProcess(), 00738 &DeallocationStack, 00739 &Dummy, 00740 MEM_RELEASE); 00741 } 00742 00743 /* Free the debug handle */ 00744 if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1], 00745 UserMode); 00746 } 00747 00748 /* Decommit the TEB */ 00749 MmDeleteTeb(CurrentProcess, Teb); 00750 Thread->Tcb.Teb = NULL; 00751 } 00752 00753 /* Free LPC Data */ 00754 LpcExitThread(Thread); 00755 00756 /* Save the exit status and exit time */ 00757 Thread->ExitStatus = ExitStatus; 00758 KeQuerySystemTime(&Thread->ExitTime); 00759 00760 /* Sanity check */ 00761 ASSERT(Thread->Tcb.CombinedApcDisable == 0); 00762 00763 /* Check if this is the final thread or not */ 00764 if (Last) 00765 { 00766 /* Set the process exit time */ 00767 CurrentProcess->ExitTime = Thread->ExitTime; 00768 00769 /* Exit the process */ 00770 PspExitProcess(TRUE, CurrentProcess); 00771 00772 /* Get the process token and check if we need to audit */ 00773 PrimaryToken = PsReferencePrimaryToken(CurrentProcess); 00774 if (SeDetailedAuditingWithToken(PrimaryToken)) 00775 { 00776 /* Audit the exit */ 00777 SeAuditProcessExit(CurrentProcess); 00778 } 00779 00780 /* Dereference the process token */ 00781 ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken); 00782 00783 /* Check if this is a VDM Process and rundown the VDM DPCs if so */ 00784 if (CurrentProcess->VdmObjects) { /* VdmRundownDpcs(CurrentProcess); */ } 00785 00786 /* Kill the process in the Object Manager */ 00787 ObKillProcess(CurrentProcess); 00788 00789 /* Check if we have a section object */ 00790 if (CurrentProcess->SectionObject) 00791 { 00792 /* Dereference and clear the Section Object */ 00793 ObDereferenceObject(CurrentProcess->SectionObject); 00794 CurrentProcess->SectionObject = NULL; 00795 } 00796 00797 /* Check if the process is part of a job */ 00798 if (CurrentProcess->Job) 00799 { 00800 /* Remove the process from the job */ 00801 PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess); 00802 } 00803 } 00804 00805 /* Disable APCs */ 00806 KeEnterCriticalRegion(); 00807 00808 /* Disable APC queueing, force a resumption */ 00809 Thread->Tcb.ApcQueueable = FALSE; 00810 KeForceResumeThread(&Thread->Tcb); 00811 00812 /* Re-enable APCs */ 00813 KeLeaveCriticalRegion(); 00814 00815 /* Flush the User APCs */ 00816 FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode); 00817 if (FirstEntry) 00818 { 00819 /* Start with the first entry */ 00820 CurrentEntry = FirstEntry; 00821 do 00822 { 00823 /* Get the APC */ 00824 Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry); 00825 00826 /* Move to the next one */ 00827 CurrentEntry = CurrentEntry->Flink; 00828 00829 /* Rundown the APC or de-allocate it */ 00830 if (Apc->RundownRoutine) 00831 { 00832 /* Call its own routine */ 00833 Apc->RundownRoutine(Apc); 00834 } 00835 else 00836 { 00837 /* Do it ourselves */ 00838 ExFreePool(Apc); 00839 } 00840 } 00841 while (CurrentEntry != FirstEntry); 00842 } 00843 00844 /* Clean address space if this was the last thread */ 00845 if (Last) MmCleanProcessAddressSpace(CurrentProcess); 00846 00847 /* Call the Lego routine */ 00848 if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb); 00849 00850 /* Flush the APC queue, which should be empty */ 00851 FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode); 00852 if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0)) 00853 { 00854 /* Bugcheck time */ 00855 KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT, 00856 (ULONG_PTR)FirstEntry, 00857 Thread->Tcb.CombinedApcDisable, 00858 KeGetCurrentIrql(), 00859 0); 00860 } 00861 00862 /* Signal the process if this was the last thread */ 00863 if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE); 00864 00865 /* Terminate the Thread from the Scheduler */ 00866 KeTerminateThread(0); 00867 } 00868 00869 VOID 00870 NTAPI 00871 PsExitSpecialApc(IN PKAPC Apc, 00872 IN OUT PKNORMAL_ROUTINE* NormalRoutine, 00873 IN OUT PVOID* NormalContext, 00874 IN OUT PVOID* SystemArgument1, 00875 IN OUT PVOID* SystemArgument2) 00876 { 00877 NTSTATUS Status; 00878 PAGED_CODE(); 00879 PSTRACE(PS_KILL_DEBUG, 00880 "Apc: %p SystemArgument2: %p \n", Apc, SystemArgument2); 00881 00882 /* Don't do anything unless we are in User-Mode */ 00883 if (Apc->SystemArgument2) 00884 { 00885 /* Free the APC */ 00886 Status = (NTSTATUS)Apc->NormalContext; 00887 PspExitApcRundown(Apc); 00888 00889 /* Terminate the Thread */ 00890 PspExitThread(Status); 00891 } 00892 } 00893 00894 VOID 00895 NTAPI 00896 PspExitNormalApc(IN PVOID NormalContext, 00897 IN PVOID SystemArgument1, 00898 IN PVOID SystemArgument2) 00899 { 00900 PKAPC Apc = (PKAPC)SystemArgument1; 00901 PETHREAD Thread = PsGetCurrentThread(); 00902 PAGED_CODE(); 00903 PSTRACE(PS_KILL_DEBUG, "SystemArgument2: %p \n", SystemArgument2); 00904 00905 /* This should never happen */ 00906 ASSERT(!(((ULONG_PTR)SystemArgument2) & 1)); 00907 00908 /* If we're here, this is not a System Thread, so kill it from User-Mode */ 00909 KeInitializeApc(Apc, 00910 &Thread->Tcb, 00911 OriginalApcEnvironment, 00912 PsExitSpecialApc, 00913 PspExitApcRundown, 00914 PspExitNormalApc, 00915 UserMode, 00916 NormalContext); 00917 00918 /* Now insert the APC with the User-Mode Flag */ 00919 if (!(KeInsertQueueApc(Apc, 00920 Apc, 00921 (PVOID)((ULONG_PTR)SystemArgument2 | 1), 00922 2))) 00923 { 00924 /* Failed to insert, free the APC */ 00925 PspExitApcRundown(Apc); 00926 } 00927 00928 /* Set the APC Pending flag */ 00929 Thread->Tcb.ApcState.UserApcPending = TRUE; 00930 } 00931 00932 /* 00933 * See "Windows Internals" - Chapter 13, Page 49 00934 */ 00935 NTSTATUS 00936 NTAPI 00937 PspTerminateThreadByPointer(IN PETHREAD Thread, 00938 IN NTSTATUS ExitStatus, 00939 IN BOOLEAN bSelf) 00940 { 00941 PKAPC Apc; 00942 NTSTATUS Status = STATUS_SUCCESS; 00943 ULONG Flags; 00944 PAGED_CODE(); 00945 PSTRACE(PS_KILL_DEBUG, "Thread: %p ExitStatus: %p\n", Thread, ExitStatus); 00946 PSREFTRACE(Thread); 00947 00948 /* Check if this is a Critical Thread, and Bugcheck */ 00949 if (Thread->BreakOnTermination) 00950 { 00951 /* Break to debugger */ 00952 PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n", 00953 Thread, 00954 Thread->ThreadsProcess->ImageFileName); 00955 } 00956 00957 /* Check if we are already inside the thread */ 00958 if ((bSelf) || (PsGetCurrentThread() == Thread)) 00959 { 00960 /* This should only happen at passive */ 00961 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 00962 00963 /* Mark it as terminated */ 00964 PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT); 00965 00966 /* Directly terminate the thread */ 00967 PspExitThread(ExitStatus); 00968 } 00969 00970 /* This shouldn't be a system thread */ 00971 if (Thread->SystemThread) return STATUS_ACCESS_DENIED; 00972 00973 /* Allocate the APC */ 00974 Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC); 00975 if (!Apc) return STATUS_INSUFFICIENT_RESOURCES; 00976 00977 /* Set the Terminated Flag */ 00978 Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT; 00979 00980 /* Set it, and check if it was already set while we were running */ 00981 if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) & 00982 CT_TERMINATED_BIT)) 00983 { 00984 /* Initialize a Kernel Mode APC to Kill the Thread */ 00985 KeInitializeApc(Apc, 00986 &Thread->Tcb, 00987 OriginalApcEnvironment, 00988 PsExitSpecialApc, 00989 PspExitApcRundown, 00990 PspExitNormalApc, 00991 KernelMode, 00992 (PVOID)ExitStatus); 00993 00994 /* Insert it into the APC Queue */ 00995 if (!KeInsertQueueApc(Apc, Apc, NULL, 2)) 00996 { 00997 /* The APC was already in the queue, fail */ 00998 Status = STATUS_UNSUCCESSFUL; 00999 } 01000 else 01001 { 01002 /* Forcefully resume the thread and return */ 01003 KeForceResumeThread(&Thread->Tcb); 01004 return Status; 01005 } 01006 } 01007 01008 /* We failed, free the APC */ 01009 ExFreePool(Apc); 01010 01011 /* Return Status */ 01012 return Status; 01013 } 01014 01015 BOOLEAN 01016 NTAPI 01017 PspIsProcessExiting(IN PEPROCESS Process) 01018 { 01019 return Process->Flags & PSF_PROCESS_EXITING_BIT; 01020 } 01021 01022 VOID 01023 NTAPI 01024 PspExitProcess(IN BOOLEAN LastThread, 01025 IN PEPROCESS Process) 01026 { 01027 ULONG Actual; 01028 PAGED_CODE(); 01029 PSTRACE(PS_KILL_DEBUG, 01030 "LastThread: %p Process: %p\n", LastThread, Process); 01031 PSREFTRACE(Process); 01032 01033 /* Set Process Exit flag */ 01034 InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_EXITING_BIT); 01035 01036 /* Check if we are the last thread */ 01037 if (LastThread) 01038 { 01039 /* Notify the WMI Process Callback */ 01040 //WmiTraceProcess(Process, FALSE); 01041 01042 /* Run the Notification Routines */ 01043 PspRunCreateProcessNotifyRoutines(Process, FALSE); 01044 } 01045 01046 /* Cleanup the power state */ 01047 PopCleanupPowerState((PPOWER_STATE)&Process->Pcb.PowerState); 01048 01049 /* Clear the security port */ 01050 if (!Process->SecurityPort) 01051 { 01052 /* So we don't double-dereference */ 01053 Process->SecurityPort = (PVOID)1; 01054 } 01055 else if (Process->SecurityPort != (PVOID)1) 01056 { 01057 /* Dereference it */ 01058 ObDereferenceObject(Process->SecurityPort); 01059 Process->SecurityPort = (PVOID)1; 01060 } 01061 01062 /* Check if we are the last thread */ 01063 if (LastThread) 01064 { 01065 /* Check if we have to set the Timer Resolution */ 01066 if (Process->SetTimerResolution) 01067 { 01068 /* Set it to default */ 01069 ZwSetTimerResolution(KeMaximumIncrement, 0, &Actual); 01070 } 01071 01072 /* Check if we are part of a Job that has a completion port */ 01073 if ((Process->Job) && (Process->Job->CompletionPort)) 01074 { 01075 /* FIXME: Check job status code and do I/O completion if needed */ 01076 } 01077 01078 /* FIXME: Notify the Prefetcher */ 01079 } 01080 else 01081 { 01082 /* Clear process' address space here */ 01083 MmCleanProcessAddressSpace(Process); 01084 } 01085 } 01086 01087 /* PUBLIC FUNCTIONS **********************************************************/ 01088 01089 /* 01090 * @implemented 01091 */ 01092 NTSTATUS 01093 NTAPI 01094 PsTerminateSystemThread(IN NTSTATUS ExitStatus) 01095 { 01096 PETHREAD Thread = PsGetCurrentThread(); 01097 01098 /* Make sure this is a system thread */ 01099 if (!Thread->SystemThread) return STATUS_INVALID_PARAMETER; 01100 01101 /* Terminate it for real */ 01102 return PspTerminateThreadByPointer(Thread, ExitStatus, TRUE); 01103 } 01104 01105 /* 01106 * @implemented 01107 */ 01108 NTSTATUS 01109 NTAPI 01110 NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, 01111 IN NTSTATUS ExitStatus) 01112 { 01113 NTSTATUS Status; 01114 PEPROCESS Process, CurrentProcess = PsGetCurrentProcess(); 01115 PETHREAD Thread, CurrentThread = PsGetCurrentThread(); 01116 BOOLEAN KillByHandle; 01117 PAGED_CODE(); 01118 PSTRACE(PS_KILL_DEBUG, 01119 "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle, ExitStatus); 01120 01121 /* Were we passed a process handle? */ 01122 if (ProcessHandle) 01123 { 01124 /* Yes we were, use it */ 01125 KillByHandle = TRUE; 01126 } 01127 else 01128 { 01129 /* We weren't... we assume this is suicide */ 01130 KillByHandle = FALSE; 01131 ProcessHandle = NtCurrentProcess(); 01132 } 01133 01134 /* Get the Process Object */ 01135 Status = ObReferenceObjectByHandle(ProcessHandle, 01136 PROCESS_TERMINATE, 01137 PsProcessType, 01138 KeGetPreviousMode(), 01139 (PVOID*)&Process, 01140 NULL); 01141 if (!NT_SUCCESS(Status)) return(Status); 01142 01143 /* Check if this is a Critical Process, and Bugcheck */ 01144 if (Process->BreakOnTermination) 01145 { 01146 /* Break to debugger */ 01147 PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n", 01148 Process, 01149 Process->ImageFileName); 01150 } 01151 01152 /* Lock the Process */ 01153 if (!ExAcquireRundownProtection(&Process->RundownProtect)) 01154 { 01155 /* Failed to lock, fail */ 01156 ObDereferenceObject (Process); 01157 return STATUS_PROCESS_IS_TERMINATING; 01158 } 01159 01160 /* Set the delete flag, unless the process is comitting suicide */ 01161 if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT); 01162 01163 /* Get the first thread */ 01164 Status = STATUS_NOTHING_TO_TERMINATE; 01165 Thread = PsGetNextProcessThread(Process, NULL); 01166 if (Thread) 01167 { 01168 /* We know we have at least a thread */ 01169 Status = STATUS_SUCCESS; 01170 01171 /* Loop and kill the others */ 01172 do 01173 { 01174 /* Ensure it's not ours*/ 01175 if (Thread != CurrentThread) 01176 { 01177 /* Kill it */ 01178 PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); 01179 } 01180 01181 /* Move to the next thread */ 01182 Thread = PsGetNextProcessThread(Process, Thread); 01183 } while (Thread); 01184 } 01185 01186 /* Unlock the process */ 01187 ExReleaseRundownProtection(&Process->RundownProtect); 01188 01189 /* Check if we are killing ourselves */ 01190 if (Process == CurrentProcess) 01191 { 01192 /* Also make sure the caller gave us our handle */ 01193 if (KillByHandle) 01194 { 01195 /* Dereference the process */ 01196 ObDereferenceObject(Process); 01197 01198 /* Terminate ourselves */ 01199 PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE); 01200 } 01201 } 01202 else if (ExitStatus == DBG_TERMINATE_PROCESS) 01203 { 01204 /* Disable debugging on this process */ 01205 DbgkClearProcessDebugObject(Process, NULL); 01206 } 01207 01208 /* Check if there was nothing to terminate, or if we have a Debug Port */ 01209 if ((Status == STATUS_NOTHING_TO_TERMINATE) || 01210 ((Process->DebugPort) && (KillByHandle))) 01211 { 01212 /* Clear the handle table */ 01213 ObClearProcessHandleTable(Process); 01214 01215 /* Return status now */ 01216 Status = STATUS_SUCCESS; 01217 } 01218 01219 /* Decrease the reference count we added */ 01220 ObDereferenceObject(Process); 01221 01222 /* Return status */ 01223 return Status; 01224 } 01225 01226 NTSTATUS 01227 NTAPI 01228 NtTerminateThread(IN HANDLE ThreadHandle, 01229 IN NTSTATUS ExitStatus) 01230 { 01231 PETHREAD Thread; 01232 PETHREAD CurrentThread = PsGetCurrentThread(); 01233 NTSTATUS Status; 01234 PAGED_CODE(); 01235 PSTRACE(PS_KILL_DEBUG, 01236 "ThreadHandle: %p ExitStatus: %p\n", ThreadHandle, ExitStatus); 01237 01238 /* Handle the special NULL case */ 01239 if (!ThreadHandle) 01240 { 01241 /* Check if we're the only thread left */ 01242 if (PsGetCurrentProcess()->ActiveThreads == 1) 01243 { 01244 /* This is invalid */ 01245 return STATUS_CANT_TERMINATE_SELF; 01246 } 01247 01248 /* Terminate us directly */ 01249 goto TerminateSelf; 01250 } 01251 else if (ThreadHandle == NtCurrentThread()) 01252 { 01253 TerminateSelf: 01254 /* Terminate this thread */ 01255 return PspTerminateThreadByPointer(CurrentThread, 01256 ExitStatus, 01257 TRUE); 01258 } 01259 01260 /* We are terminating another thread, get the Thread Object */ 01261 Status = ObReferenceObjectByHandle(ThreadHandle, 01262 THREAD_TERMINATE, 01263 PsThreadType, 01264 KeGetPreviousMode(), 01265 (PVOID*)&Thread, 01266 NULL); 01267 if (!NT_SUCCESS(Status)) return Status; 01268 01269 /* Check to see if we're running in the same thread */ 01270 if (Thread != CurrentThread) 01271 { 01272 /* Terminate it */ 01273 Status = PspTerminateThreadByPointer(Thread, ExitStatus, FALSE); 01274 01275 /* Dereference the Thread and return */ 01276 ObDereferenceObject(Thread); 01277 } 01278 else 01279 { 01280 /* Dereference the thread and terminate ourselves */ 01281 ObDereferenceObject(Thread); 01282 goto TerminateSelf; 01283 } 01284 01285 /* Return status */ 01286 return Status; 01287 } 01288 01289 NTSTATUS 01290 NTAPI 01291 NtRegisterThreadTerminatePort(IN HANDLE PortHandle) 01292 { 01293 NTSTATUS Status; 01294 PTERMINATION_PORT TerminationPort; 01295 PVOID TerminationLpcPort; 01296 PETHREAD Thread; 01297 PAGED_CODE(); 01298 PSTRACE(PS_KILL_DEBUG, "PortHandle: %p\n", PortHandle); 01299 01300 /* Get the Port */ 01301 Status = ObReferenceObjectByHandle(PortHandle, 01302 PORT_ALL_ACCESS, 01303 LpcPortObjectType, 01304 KeGetPreviousMode(), 01305 &TerminationLpcPort, 01306 NULL); 01307 if (!NT_SUCCESS(Status)) return(Status); 01308 01309 /* Allocate the Port and make sure it suceeded */ 01310 TerminationPort = ExAllocatePoolWithTag(NonPagedPool, 01311 sizeof(TERMINATION_PORT), 01312 '=TsP'); 01313 if(TerminationPort) 01314 { 01315 /* Associate the Port */ 01316 Thread = PsGetCurrentThread(); 01317 TerminationPort->Port = TerminationLpcPort; 01318 TerminationPort->Next = Thread->TerminationPort; 01319 Thread->TerminationPort = TerminationPort; 01320 01321 /* Return success */ 01322 return STATUS_SUCCESS; 01323 } 01324 01325 /* Dereference and Fail */ 01326 ObDereferenceObject(TerminationPort); 01327 return STATUS_INSUFFICIENT_RESOURCES; 01328 } Generated on Fri May 25 2012 04:36:06 for ReactOS by
1.7.6.1
|