Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

psdelete.c File Reference

#include "psp.h"

Go to the source code of this file.

Functions

ULONG PsSetLegoNotifyRoutine (PLEGO_NOTIFY_ROUTINE LegoNotifyRoutine)
VOID PspReaper (IN PVOID Context)
NTSTATUS PspTerminateThreadByPointer (IN PETHREAD Thread, IN NTSTATUS ExitStatus)
NTSTATUS NtTerminateProcess (IN HANDLE ProcessHandle OPTIONAL, IN NTSTATUS ExitStatus)
NTSTATUS PspTerminateProcess (PEPROCESS Process, NTSTATUS Status, PSLOCKPROCESSMODE LockMode)
NTSTATUS NtTerminateThread (IN HANDLE ThreadHandle OPTIONAL, IN NTSTATUS ExitStatus)
NTSTATUS PsTerminateSystemThread (IN NTSTATUS ExitStatus)
VOID PspNullSpecialApc (IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2)
VOID PsExitSpecialApc (IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2)
VOID PspExitNormalApc (IN PVOID NormalContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
BOOLEAN PspMarkCidInvalid (IN PHANDLE_TABLE_ENTRY HandleEntry, IN ULONG_PTR Parameter)
DECLSPEC_NORETURN VOID PspExitThread (IN NTSTATUS ExitStatus)
VOID PspExitProcess (IN BOOLEAN TrimAddressSpace, IN PEPROCESS Process)
VOID PspProcessDelete (IN PVOID Object)
VOID PspThreadDelete (IN PVOID Object)
NTSTATUS NtRegisterThreadTerminatePort (IN HANDLE PortHandle)
LARGE_INTEGER PsGetProcessExitTime (VOID)
BOOLEAN PsIsThreadTerminating (IN PETHREAD Thread)

Variables

PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine


Function Documentation

NTSTATUS NtRegisterThreadTerminatePort IN HANDLE  PortHandle  ) 
 

Definition at line 1472 of file psdelete.c.

References ExAllocatePoolWithQuota, EXCEPTION_EXECUTE_HANDLER, _TERMINATION_PORT::Links, LpcPortObjectType, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PagedPool, _TERMINATION_PORT::Port, PortHandle, and PsGetCurrentThread.

Referenced by CsrNewThread(), and DbgUiConnectToDbg().

01478 : 01479 01480 This API allows a thread to register a port to be notified upon 01481 thread termination. 01482 01483 Arguments: 01484 01485 PortHandle - Supplies an open handle to a port object that will be 01486 sent a termination message when the thread terminates. 01487 01488 Return Value: 01489 01490 TBD 01491 01492 --*/ 01493 01494 { 01495 01496 PVOID Port; 01497 PTERMINATION_PORT TerminationPort; 01498 NTSTATUS st; 01499 01500 PAGED_CODE(); 01501 01502 st = ObReferenceObjectByHandle ( 01503 PortHandle, 01504 0, 01505 LpcPortObjectType, 01506 KeGetPreviousMode(), 01507 (PVOID *)&Port, 01508 NULL 01509 ); 01510 01511 if ( !NT_SUCCESS(st) ) { 01512 return st; 01513 01514 } 01515 01516 // 01517 // Catch exception and dereference port... 01518 // 01519 01520 try { 01521 01522 TerminationPort = NULL; 01523 TerminationPort = ExAllocatePoolWithQuota(PagedPool,sizeof(TERMINATION_PORT)); 01524 01525 TerminationPort->Port = Port; 01526 InsertTailList(&PsGetCurrentThread()->TerminationPortList,&TerminationPort->Links); 01527 01528 } except(EXCEPTION_EXECUTE_HANDLER) { 01529 01530 ObDereferenceObject(Port); 01531 01532 return GetExceptionCode(); 01533 } 01534 01535 return STATUS_SUCCESS; 01536 }

NTSTATUS NtTerminateProcess IN HANDLE ProcessHandle  OPTIONAL,
IN NTSTATUS  ExitStatus
 

Definition at line 227 of file psdelete.c.

References FALSE, _ETHREAD::HasTerminated, IS_SYSTEM_THREAD, KeForceResumeThread(), KeQuerySystemTime(), KernelMode, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PsGetCurrentProcess, PsGetCurrentThread, PsLockPollOnTimeout, PsLockProcess(), PspExitThread(), PsProcessType, PspTerminateThreadByPointer(), PsUnlockProcess(), _ETHREAD::Tcb, and TRUE.

Referenced by _EndTask(), KillProcess(), main(), TestParent(), UdbgTest1(), UdbgTest2(), UserClientShutdown(), and WowExitTask().

00234 : 00235 00236 This function causes the specified process and all of 00237 its threads to terminate. 00238 00239 Arguments: 00240 00241 ProcessHandle - Supplies a handle to the process to terminate. 00242 00243 ExitStatus - Supplies the exit status associated with the process. 00244 00245 Return Value: 00246 00247 TBD 00248 00249 --*/ 00250 00251 { 00252 00253 PETHREAD Thread,Self; 00254 PEPROCESS Process; 00255 PLIST_ENTRY Next; 00256 NTSTATUS st,xst; 00257 BOOLEAN ProcessHandleSpecified; 00258 PAGED_CODE(); 00259 00260 Self = PsGetCurrentThread(); 00261 00262 if ( ARGUMENT_PRESENT(ProcessHandle) ) { 00263 ProcessHandleSpecified = TRUE; 00264 } else { 00265 ProcessHandleSpecified = FALSE; 00266 ProcessHandle = NtCurrentProcess(); 00267 } 00268 00269 st = ObReferenceObjectByHandle( 00270 ProcessHandle, 00271 PROCESS_TERMINATE, 00272 PsProcessType, 00273 KeGetPreviousMode(), 00274 (PVOID *)&Process, 00275 NULL 00276 ); 00277 00278 if ( !NT_SUCCESS(st) ) { 00279 return(st); 00280 } 00281 00282 // 00283 // If the exit status is DBG_TERMINATE_PROCESS, then fail the terminate 00284 // if the process is being debugged. This is for shutdown so that we can 00285 // kill debuggers and not debuggees reliably 00286 // 00287 00288 if ( ExitStatus == DBG_TERMINATE_PROCESS && Process != PsGetCurrentProcess() ) { 00289 if ( Process->DebugPort ) { 00290 ObDereferenceObject( Process ); 00291 return STATUS_ACCESS_DENIED; 00292 } 00293 else { 00294 ExitStatus = STATUS_SUCCESS; 00295 } 00296 } 00297 00298 st = STATUS_SUCCESS; 00299 00300 // 00301 // the following allows NtTerminateProcess to fail properly if 00302 // called while the exiting process is blocked holding the 00303 // createdeletelock. This can happen during debugger/server 00304 // lpc transactions that occur in pspexitthread 00305 // 00306 00307 xst = PsLockProcess(Process,KernelMode,PsLockPollOnTimeout); 00308 00309 if ( xst != STATUS_SUCCESS ) { 00310 ObDereferenceObject( Process ); 00311 return STATUS_PROCESS_IS_TERMINATING; 00312 } 00313 00314 Next = Process->ThreadListHead.Flink; 00315 00316 while ( Next != &Process->ThreadListHead) { 00317 00318 Thread = (PETHREAD)(CONTAINING_RECORD(Next,ETHREAD,ThreadListEntry)); 00319 00320 if ( Thread != Self ) { 00321 00322 if ( IS_SYSTEM_THREAD(Thread) ) { 00323 ObDereferenceObject(Process); 00324 PsUnlockProcess(Process); 00325 return STATUS_INVALID_PARAMETER; 00326 } 00327 00328 if ( !Thread->HasTerminated ) { 00329 Thread->HasTerminated = TRUE; 00330 00331 PspTerminateThreadByPointer(Thread, ExitStatus); 00332 KeForceResumeThread(&Thread->Tcb); 00333 } 00334 } 00335 Next = Next->Flink; 00336 } 00337 00338 00339 00340 if ( Process == PsGetCurrentProcess() && ProcessHandleSpecified ) { 00341 00342 Self->HasTerminated = TRUE; 00343 00344 // 00345 // early set of process exit time will eliminate the deadlocks 00346 // that occur when csrss tries to create a remote thread in a 00347 // process that is in the process of exiting, and that has an 00348 // unhandled exit call outstanding to its debugger 00349 // 00350 KeQuerySystemTime(&Process->ExitTime); 00351 00352 PsUnlockProcess(Process); 00353 00354 ObDereferenceObject(Process); 00355 00356 PspExitThread(ExitStatus); 00357 00358 // 00359 // Never Returns 00360 // 00361 00362 } 00363 00364 // 00365 // early set of process exit time will eliminate the deadlocks 00366 // that occur when csrss tries to create a remote thread in a 00367 // process that is in the process of exiting, and that has an 00368 // unhandled exit call outstanding to its debugger 00369 // 00370 if ( ProcessHandleSpecified ) { 00371 00372 KeQuerySystemTime(&Process->ExitTime); 00373 00374 } 00375 00376 PsUnlockProcess(Process); 00377 00378 ObDereferenceObject(Process); 00379 00380 return st; 00381 }

NTSTATUS NtTerminateThread IN HANDLE ThreadHandle  OPTIONAL,
IN NTSTATUS  ExitStatus
 

Definition at line 461 of file psdelete.c.

References IS_SYSTEM_THREAD, KeForceResumeThread(), KernelMode, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PsGetCurrentProcess, PsGetCurrentThread, PsLockProcess(), PsLockWaitForever, PspTerminateThreadByPointer(), PsThreadType, PsUnlockProcess(), THREAD_TO_PROCESS, ThreadHandle, and TRUE.

Referenced by CtLnpQos(), CtLpcQos(), MemPrintWriteThread(), RtlpExitThread(), RtlpQueryProcessDebugInformationRemote(), RtlpThreadCleanup(), RtlQueryProcessDebugInformation(), TestTokenImpersonation(), ThreadThatExcepts(), ThreadThatExits(), ThreadThatSpins(), and UnlockConsole().

00468 : 00469 00470 This function causes the specified thread to terminate. 00471 00472 Arguments: 00473 00474 ThreadHandle - Supplies a handle to the thread to terminate. 00475 00476 ExitStatus - Supplies the exit status associated with the thread. 00477 00478 Return Value: 00479 00480 TBD 00481 00482 --*/ 00483 00484 { 00485 00486 PETHREAD Thread; 00487 NTSTATUS st; 00488 00489 PAGED_CODE(); 00490 00491 if ( !ARGUMENT_PRESENT(ThreadHandle) ) { 00492 if ( (PsGetCurrentProcess()->ThreadListHead.Flink == 00493 PsGetCurrentProcess()->ThreadListHead.Blink 00494 ) 00495 && 00496 (PsGetCurrentProcess()->ThreadListHead.Flink == 00497 &PsGetCurrentThread()->ThreadListEntry 00498 ) 00499 ) { 00500 return( STATUS_CANT_TERMINATE_SELF ); 00501 } else { 00502 ThreadHandle = NtCurrentThread(); 00503 } 00504 } 00505 00506 st = ObReferenceObjectByHandle( 00507 ThreadHandle, 00508 THREAD_TERMINATE, 00509 PsThreadType, 00510 KeGetPreviousMode(), 00511 (PVOID *)&Thread, 00512 NULL 00513 ); 00514 00515 if ( !NT_SUCCESS(st) ) { 00516 return(st); 00517 } 00518 00519 if ( IS_SYSTEM_THREAD(Thread) ) { 00520 ObDereferenceObject(Thread); 00521 return STATUS_INVALID_PARAMETER; 00522 } 00523 00524 if ( Thread != PsGetCurrentThread() ) { 00525 00526 if (!Thread->HasTerminated) { 00527 PsLockProcess(THREAD_TO_PROCESS(Thread),KernelMode,PsLockWaitForever); 00528 00529 Thread->HasTerminated = TRUE; 00530 st = PspTerminateThreadByPointer(Thread,ExitStatus); 00531 if ( NT_SUCCESS(st) ) { 00532 KeForceResumeThread(&Thread->Tcb); 00533 } 00534 PsUnlockProcess(THREAD_TO_PROCESS(Thread)); 00535 } 00536 } else { 00537 Thread->HasTerminated = TRUE; 00538 PspTerminateThreadByPointer(Thread,ExitStatus); 00539 } 00540 ObDereferenceObject(Thread); 00541 00542 return st; 00543 }

VOID PsExitSpecialApc IN PKAPC  Apc,
IN PKNORMAL_ROUTINE NormalRoutine,
IN PVOID *  NormalContext,
IN PVOID *  SystemArgument1,
IN PVOID *  SystemArgument2
 

Definition at line 603 of file psdelete.c.

References ExFreePool(), NTSTATUS(), PAGED_CODE, and PspExitThread().

Referenced by KiInsertQueueApc(), KiSuspendThread(), PspExitNormalApc(), and PspTerminateThreadByPointer().

00611 { 00612 NTSTATUS ExitStatus; 00613 00614 PAGED_CODE(); 00615 00616 UNREFERENCED_PARAMETER(NormalRoutine); 00617 UNREFERENCED_PARAMETER(NormalContext); 00618 UNREFERENCED_PARAMETER(SystemArgument1); 00619 UNREFERENCED_PARAMETER(SystemArgument2); 00620 00621 if ( Apc->SystemArgument2 ) { 00622 ExitStatus = (NTSTATUS)((LONG_PTR)Apc->NormalContext); 00623 ExFreePool(Apc); 00624 PspExitThread(ExitStatus); 00625 } 00626 00627 }

LARGE_INTEGER PsGetProcessExitTime VOID   ) 
 

Definition at line 1539 of file psdelete.c.

References PAGED_CODE, and PsGetCurrentProcess.

01545 : 01546 01547 This routine returns the exit time for the current process. 01548 01549 Arguments: 01550 01551 None. 01552 01553 Return Value: 01554 01555 The function value is the exit time for the current process. 01556 01557 Note: 01558 01559 This routine assumes that the caller wants an error log entry within the 01560 bounds of the maximum size. 01561 01562 --*/ 01563 01564 { 01565 PAGED_CODE(); 01566 01567 // 01568 // Simply return the exit time for this process. 01569 // 01570 01571 return PsGetCurrentProcess()->ExitTime; 01572 }

BOOLEAN PsIsThreadTerminating IN PETHREAD  Thread  ) 
 

Definition at line 1578 of file psdelete.c.

References FALSE, and TRUE.

01584 : 01585 01586 This routine returns TRUE if the specified thread is in the process of 01587 terminating. 01588 01589 Arguments: 01590 01591 Thread - Supplies a pointer to the thread to be checked for termination. 01592 01593 Return Value: 01594 01595 TRUE is returned if the thread is terminating, else FALSE is returned. 01596 01597 --*/ 01598 01599 { 01600 // 01601 // Simply return whether or not the thread is in the process of terminating. 01602 // 01603 01604 if ( Thread->HasTerminated ) { 01605 return TRUE; 01606 } 01607 else { 01608 return FALSE; 01609 } 01610 } }

VOID PspExitNormalApc IN PVOID  NormalContext,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2
 

Definition at line 631 of file psdelete.c.

References ExFreePool(), IS_SYSTEM_THREAD, KeBugCheck(), KeForceResumeThread(), KeInitializeApc(), KeInsertQueueApc(), _KAPC::NormalContext, NTSTATUS(), NULL, OriginalApcEnvironment, PAGED_CODE, PsExitSpecialApc(), PsGetCurrentThread, PspExitNormalApc(), PspExitThread(), _ETHREAD::Tcb, and UserMode.

Referenced by PspExitNormalApc(), and PspTerminateThreadByPointer().

00637 { 00638 PETHREAD Thread; 00639 PKAPC ExitApc; 00640 NTSTATUS ExitStatus; 00641 00642 PAGED_CODE(); 00643 00644 Thread = PsGetCurrentThread(); 00645 00646 if ( SystemArgument2 ) { 00647 KeBugCheck(0x12345678); 00648 } 00649 00650 ExitApc = (PKAPC) SystemArgument1; 00651 00652 if ( IS_SYSTEM_THREAD(Thread) ) { 00653 ExitStatus = (NTSTATUS)((LONG_PTR)ExitApc->NormalContext); 00654 ExFreePool(ExitApc); 00655 PspExitThread(ExitStatus); 00656 } else { 00657 00658 KeInitializeApc( 00659 ExitApc, 00660 &Thread->Tcb, 00661 OriginalApcEnvironment, 00662 PsExitSpecialApc, 00663 NULL, 00664 PspExitNormalApc, 00665 UserMode, 00666 NormalContext 00667 ); 00668 00669 if ( !KeInsertQueueApc(ExitApc,ExitApc,(PVOID) 1, 2) ) { 00670 ExFreePool(ExitApc); 00671 } 00672 00673 KeForceResumeThread(&Thread->Tcb); 00674 } 00675 }

VOID PspExitProcess IN BOOLEAN  TrimAddressSpace,
IN PEPROCESS  Process
 

Definition at line 1232 of file psdelete.c.

References FALSE, IoSetIoCompletion(), KeMaximumIncrement, KeSetProcess(), MmCleanProcessAddressSpace(), NULL, ObDereferenceObject, ObKillProcess(), PAGED_CODE, PoRundownProcess, PS_JOB_STATUS_EXIT_PROCESS_REPORTED, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_CLEAR_BITS, PSP_MAX_CREATE_PROCESS_NOTIFY, PspActiveProcessMutex, PspCreateProcessNotifyRoutine, PspCreateProcessNotifyRoutineCount, and TRUE.

Referenced by PspExitThread(), and PspProcessDelete().

01236 { 01237 01238 ULONG ActualTime; 01239 01240 PAGED_CODE(); 01241 01242 if (!Process->ExitProcessCalled && PspCreateProcessNotifyRoutineCount != 0) { 01243 ULONG i; 01244 01245 for (i=0; i<PSP_MAX_CREATE_PROCESS_NOTIFY; i++) { 01246 if (PspCreateProcessNotifyRoutine[i] != NULL) { 01247 (*PspCreateProcessNotifyRoutine[i])( Process->InheritedFromUniqueProcessId, 01248 Process->UniqueProcessId, 01249 FALSE 01250 ); 01251 } 01252 } 01253 } 01254 01255 Process->ExitProcessCalled = TRUE; 01256 01257 PoRundownProcess(Process); 01258 01259 // 01260 // If the process is on the active list, remove it now. Must be done before ObKill 01261 // due to code in ex\sysinfo that references the process through the handle table 01262 // 01263 01264 if ( Process->ActiveProcessLinks.Flink != NULL && 01265 Process->ActiveProcessLinks.Blink != NULL ) { 01266 01267 ExAcquireFastMutex(&PspActiveProcessMutex); 01268 RemoveEntryList(&Process->ActiveProcessLinks); 01269 Process->ActiveProcessLinks.Flink = NULL; 01270 Process->ActiveProcessLinks.Blink = NULL; 01271 ExReleaseFastMutex(&PspActiveProcessMutex); 01272 01273 } 01274 01275 if (Process->SecurityPort) { 01276 01277 ObDereferenceObject(Process->SecurityPort); 01278 01279 Process->SecurityPort = NULL ; 01280 } 01281 01282 01283 if ( TrimAddressSpace ) { 01284 01285 01286 // 01287 // If the current process has previously set the timer resolution, 01288 // then reset it. 01289 // 01290 01291 if (Process->SetTimerResolution != FALSE) { 01292 ZwSetTimerResolution(KeMaximumIncrement, FALSE, &ActualTime); 01293 } 01294 01295 if ( Process->Job 01296 && Process->Job->CompletionPort 01297 && !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) 01298 && !(Process->JobStatus & PS_JOB_STATUS_EXIT_PROCESS_REPORTED)) { 01299 01300 ULONG_PTR ExitMessageId; 01301 01302 switch (Process->ExitStatus) { 01303 case STATUS_GUARD_PAGE_VIOLATION : 01304 case STATUS_DATATYPE_MISALIGNMENT : 01305 case STATUS_BREAKPOINT : 01306 case STATUS_SINGLE_STEP : 01307 case STATUS_ACCESS_VIOLATION : 01308 case STATUS_IN_PAGE_ERROR : 01309 case STATUS_ILLEGAL_INSTRUCTION : 01310 case STATUS_NONCONTINUABLE_EXCEPTION : 01311 case STATUS_INVALID_DISPOSITION : 01312 case STATUS_ARRAY_BOUNDS_EXCEEDED : 01313 case STATUS_FLOAT_DENORMAL_OPERAND : 01314 case STATUS_FLOAT_DIVIDE_BY_ZERO : 01315 case STATUS_FLOAT_INEXACT_RESULT : 01316 case STATUS_FLOAT_INVALID_OPERATION : 01317 case STATUS_FLOAT_OVERFLOW : 01318 case STATUS_FLOAT_STACK_CHECK : 01319 case STATUS_FLOAT_UNDERFLOW : 01320 case STATUS_INTEGER_DIVIDE_BY_ZERO : 01321 case STATUS_INTEGER_OVERFLOW : 01322 case STATUS_PRIVILEGED_INSTRUCTION : 01323 case STATUS_STACK_OVERFLOW : 01324 case STATUS_CONTROL_C_EXIT : 01325 case STATUS_FLOAT_MULTIPLE_FAULTS : 01326 case STATUS_FLOAT_MULTIPLE_TRAPS : 01327 case STATUS_REG_NAT_CONSUMPTION : 01328 ExitMessageId = JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS; 01329 break; 01330 default: 01331 ExitMessageId = JOB_OBJECT_MSG_EXIT_PROCESS; 01332 break; 01333 } 01334 01335 PS_SET_CLEAR_BITS (&Process->JobStatus, 01336 PS_JOB_STATUS_EXIT_PROCESS_REPORTED, 01337 PS_JOB_STATUS_LAST_REPORT_MEMORY); 01338 01339 ExAcquireFastMutex(&Process->Job->MemoryLimitsLock); 01340 01341 if (Process->Job->CompletionPort != NULL) { 01342 IoSetIoCompletion( 01343 Process->Job->CompletionPort, 01344 Process->Job->CompletionKey, 01345 (PVOID)Process->UniqueProcessId, 01346 STATUS_SUCCESS, 01347 ExitMessageId, 01348 FALSE 01349 ); 01350 } 01351 ExReleaseFastMutex(&Process->Job->MemoryLimitsLock); 01352 } 01353 01354 } else { 01355 KeSetProcess(&Process->Pcb,0,FALSE); 01356 ObKillProcess(FALSE, Process); 01357 MmCleanProcessAddressSpace(); 01358 } 01359 01360 }

DECLSPEC_NORETURN VOID PspExitThread IN NTSTATUS  ExitStatus  ) 
 

Definition at line 690 of file psdelete.c.

References _KTHREAD::ApcState, _KTHREAD::ApcStateIndex, ASSERT, _ETHREAD::Cid, CmNotifyRunDown(), DbgkExitProcess(), DbgkExitThread(), _ETHREAD::DeadThread, _KTHREAD::EnableStackSwap, EXCEPTION_EXECUTE_HANDLER, ExChangeHandle(), ExFreePool(), _EPROCESS::ExitStatus, _ETHREAD::ExitStatus, _EPROCESS::ExitTime, _ETHREAD::ExitTime, ExTimerRundown(), FALSE, IoCancelThreadIo(), IS_SYSTEM_THREAD, _EPROCESS::Job, KeBugCheck(), KeBugCheckEx(), KeDisableApcQueuingThread(), KeEnterCriticalRegion, KeFlushQueueApc(), KeForceResumeThread(), KeIsAttachedProcess, KeLeaveCriticalRegion, KeLowerIrql(), KeQuerySystemTime(), _KTHREAD::KernelApcDisable, KernelMode, KeRundownThread(), KeSetPriorityThread(), KeSetProcess(), KeTerminateThread(), L, _EPROCESS::LastThreadExitStatus, _KTHREAD::LegoData, LpcExitThread(), LpcRequestPort(), MmCleanProcessAddressSpace(), MmDeleteTeb(), NtSetEvent(), NULL, ObDereferenceObject, ObKillProcess(), PAGE_SIZE, PAGED_CODE, PASSIVE_LEVEL, _EPROCESS::Pcb, _EPROCESS::Peb, _TERMINATION_PORT::Port, PoRundownThread, _KTHREAD::Priority, ProbeForRead, _KAPC_STATE::Process, PS_GET_THREAD_CREATE_TIME, PsGetCurrentProcess, PsGetCurrentThread, PsLockIAmExiting, PsLockProcess(), PSP_INVALID_ID, PSP_MAX_CREATE_THREAD_NOTIFY, PspCidTable, PspCreateThreadNotifyRoutine, PspCreateThreadNotifyRoutineCount, PspExitProcess(), PspExitProcessFromJob(), PspLegoNotifyRoutine, PspMarkCidInvalid(), PspW32ProcessCallout, PspW32ThreadCallout, PsUnlockProcess(), PsW32ThreadCalloutExit, PTERMINATION_PORT, _KAPC::RundownRoutine, _ETHREAD::Tcb, _KTHREAD::Teb, TERMINATION_PORT, _ETHREAD::TerminationPortList, THREAD_TO_PROCESS, _ETHREAD::ThreadListEntry, _EPROCESS::ThreadListHead, TRUE, _EPROCESS::UniqueProcessId, UserMode, VOID(), _EPROCESS::Win32Process, _KTHREAD::Win32Thread, _WOW64_PROCESS::Wow64, and _EPROCESS::Wow64Process.

Referenced by NtTerminateProcess(), PsExitSpecialApc(), PspExitNormalApc(), PspSystemThreadStartup(), PspTerminateThreadByPointer(), PspUserThreadStartup(), and PsTerminateSystemThread().

00696 : 00697 00698 This function causes the currently executing thread to terminate. This 00699 function is only called from within the process structure. It is called 00700 either from mainline exit code to exit the current thread, or from 00701 PsExitSpecialApc (as a piggyback to user-mode PspExitNormalApc). 00702 00703 Arguments: 00704 00705 ExitStatus - Supplies the exit status associated with the current thread. 00706 00707 Return Value: 00708 00709 None. 00710 00711 --*/ 00712 00713 00714 { 00715 00716 PETHREAD Thread; 00717 PEPROCESS Process; 00718 PKAPC Apc; 00719 PLIST_ENTRY FirstEntry; 00720 PLIST_ENTRY NextEntry; 00721 PTERMINATION_PORT TerminationPort; 00722 LPC_CLIENT_DIED_MSG CdMsg; 00723 BOOLEAN LastThread; 00724 00725 PAGED_CODE(); 00726 00727 Thread = PsGetCurrentThread(); 00728 Process = THREAD_TO_PROCESS(Thread); 00729 00730 if ( KeIsAttachedProcess() ) { 00731 KeBugCheckEx( 00732 INVALID_PROCESS_ATTACH_ATTEMPT, 00733 (ULONG_PTR)Process, 00734 (ULONG_PTR)Thread->Tcb.ApcState.Process, 00735 (ULONG)Thread->Tcb.ApcStateIndex, 00736 (ULONG_PTR)Thread 00737 ); 00738 } 00739 00740 KeLowerIrql(PASSIVE_LEVEL); 00741 00742 if (Thread->Tcb.Priority < LOW_REALTIME_PRIORITY) { 00743 KeSetPriorityThread (&Thread->Tcb, LOW_REALTIME_PRIORITY); 00744 } 00745 00746 // 00747 // Clear any execution state associated with the thread 00748 // 00749 00750 PoRundownThread(Thread); 00751 00752 // 00753 // Account for a miss where we try to freeze a thread and bump the 00754 // freeze count, but in the freeze APC we bail from the APC due to the 00755 // pending exit APC. This results in an active thread running with a biased 00756 // freeze count and no pending APC. When this sort of thread tries to grab the 00757 // process lock, it ends of spinning since it things a freeze is pending and 00758 // an APC should occur. 00759 // 00760 // Wait mode of UserMode allows the kernel stack to page out if necessary 00761 // 00762 00763 PsLockProcess(Process,UserMode,PsLockIAmExiting); 00764 KeForceResumeThread (&Thread->Tcb); 00765 00766 // 00767 // Notify registered callout routines of thread deletion. 00768 // 00769 00770 if (PspCreateThreadNotifyRoutineCount != 0) { 00771 ULONG i; 00772 00773 for (i=0; i<PSP_MAX_CREATE_THREAD_NOTIFY; i++) { 00774 if (PspCreateThreadNotifyRoutine[i] != NULL) { 00775 (*PspCreateThreadNotifyRoutine[i])(Process->UniqueProcessId, 00776 Thread->Cid.UniqueThread, 00777 FALSE 00778 ); 00779 } 00780 } 00781 } 00782 00783 LastThread = FALSE; 00784 00785 if ( (Process->ThreadListHead.Flink == Process->ThreadListHead.Blink) 00786 && (Process->ThreadListHead.Flink == &Thread->ThreadListEntry) ) { 00787 LastThread = TRUE; 00788 if ( ExitStatus == STATUS_THREAD_IS_TERMINATING ) { 00789 if ( Process->ExitStatus == STATUS_PENDING ) { 00790 Process->ExitStatus = Process->LastThreadExitStatus; 00791 } 00792 } else { 00793 Process->ExitStatus = ExitStatus; 00794 } 00795 00796 DbgkExitProcess(ExitStatus); 00797 00798 } else { 00799 if ( ExitStatus != STATUS_THREAD_IS_TERMINATING ) { 00800 Process->LastThreadExitStatus = ExitStatus; 00801 } 00802 00803 DbgkExitThread(ExitStatus); 00804 } 00805 00806 KeLeaveCriticalRegion(); 00807 ASSERT(Thread->Tcb.KernelApcDisable == 0); 00808 00809 Thread->Tcb.KernelApcDisable = 0; 00810 00811 // 00812 // Process the TerminationPortList 00813 // 00814 if ( !IsListEmpty(&Thread->TerminationPortList) ) { 00815 00816 CdMsg.PortMsg.u1.s1.DataLength = sizeof(LARGE_INTEGER); 00817 CdMsg.PortMsg.u1.s1.TotalLength = sizeof(LPC_CLIENT_DIED_MSG); 00818 CdMsg.PortMsg.u2.s2.Type = LPC_CLIENT_DIED; 00819 CdMsg.PortMsg.u2.s2.DataInfoOffset = 0; 00820 00821 while ( !IsListEmpty(&Thread->TerminationPortList) ) { 00822 00823 NextEntry = RemoveHeadList(&Thread->TerminationPortList); 00824 TerminationPort = CONTAINING_RECORD(NextEntry,TERMINATION_PORT,Links); 00825 CdMsg.CreateTime.QuadPart = PS_GET_THREAD_CREATE_TIME(Thread); 00826 LpcRequestPort(TerminationPort->Port, (PPORT_MESSAGE)&CdMsg); 00827 ObDereferenceObject(TerminationPort->Port); 00828 ExFreePool(TerminationPort); 00829 } 00830 } else { 00831 00832 // 00833 // If there are no ports to send notifications to, 00834 // but there is an exception port, then we have to 00835 // send a client died message through the exception 00836 // port. This will allow a server a chance to get notification 00837 // if an app/thread dies before it even starts 00838 // 00839 // 00840 // We only send the exception if the thread creation really worked. 00841 // DeadThread is set when an NtCreateThread returns an error, but 00842 // the thread will actually execute this path. If DeadThread is not 00843 // set than the thread creation succeeded. The other place DeadThread 00844 // is set is when we were terminated without having any chance to move. 00845 // in this case, DeadThread is set and the exit status is set to 00846 // STATUS_THREAD_IS_TERMINATING 00847 // 00848 00849 if ( (ExitStatus == STATUS_THREAD_IS_TERMINATING && Thread->DeadThread) || 00850 !Thread->DeadThread ) { 00851 00852 CdMsg.PortMsg.u1.s1.DataLength = sizeof(LARGE_INTEGER); 00853 CdMsg.PortMsg.u1.s1.TotalLength = sizeof(LPC_CLIENT_DIED_MSG); 00854 CdMsg.PortMsg.u2.s2.Type = LPC_CLIENT_DIED; 00855 CdMsg.PortMsg.u2.s2.DataInfoOffset = 0; 00856 if ( PsGetCurrentProcess()->ExceptionPort ) { 00857 CdMsg.CreateTime.QuadPart = PS_GET_THREAD_CREATE_TIME(Thread); 00858 LpcRequestPort(PsGetCurrentProcess()->ExceptionPort, (PPORT_MESSAGE)&CdMsg); 00859 } 00860 } 00861 } 00862 00863 // 00864 // rundown the Win32 structures 00865 // 00866 00867 if ( Thread->Tcb.Win32Thread ) { 00868 (PspW32ThreadCallout)(Thread,PsW32ThreadCalloutExit); 00869 } 00870 00871 if ( LastThread && Process->Win32Process ) { 00872 (PspW32ProcessCallout)(Process,FALSE); 00873 } 00874 00875 // 00876 // User/Gdi has been given a chance to clean up. Now make sure they didn't 00877 // leave the kernel stack locked which would happen if data was still live on 00878 // this stack, but was being used by another thread 00879 // 00880 00881 if ( !Thread->Tcb.EnableStackSwap ) { 00882 KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT,0,0,0,0); 00883 } 00884 00885 // 00886 // Delete the thread's TEB. If the address of the TEB is in user 00887 // space, then this is a real user mode TEB. If the address is in 00888 // system space, then this is a special system thread TEB allocated 00889 // from paged or nonpaged pool. 00890 // 00891 00892 00893 if (Thread->Tcb.Teb) { 00894 if ( IS_SYSTEM_THREAD(Thread) ) { 00895 ExFreePool( Thread->Tcb.Teb ); 00896 } else { 00897 00898 // 00899 // The thread is a user-mode thread. Look to see if the thread 00900 // owns the loader lock (and any other key peb-based critical 00901 // sections. If so, do our best to release the locks. 00902 // 00903 // Since the LoaderLock used to be a mutant, releasing the lock 00904 // like this is very similar to mutant abandonment and the loader 00905 // never did anything with abandoned status anyway 00906 // 00907 00908 try { 00909 PTEB Teb; 00910 PPEB Peb; 00911 PRTL_CRITICAL_SECTION Cs; 00912 int DecrementCount; 00913 00914 Teb = Thread->Tcb.Teb; 00915 Peb = Process->Peb; 00916 00917 Cs = Peb->LoaderLock; 00918 if ( Cs ) { 00919 ProbeForRead(Cs,sizeof(*Cs),4); 00920 if ( Cs->OwningThread == Thread->Cid.UniqueThread ) { 00921 00922 // 00923 // x86 uses a 1 based recursion count 00924 // 00925 00926 #if defined(_X86_) 00927 DecrementCount = Cs->RecursionCount; 00928 #else 00929 DecrementCount = Cs->RecursionCount + 1; 00930 #endif 00931 Cs->RecursionCount = 0; 00932 Cs->OwningThread = 0; 00933 00934 // 00935 // undo lock count increments for recursion cases 00936 // 00937 00938 while(DecrementCount > 1){ 00939 InterlockedDecrement(&Cs->LockCount); 00940 DecrementCount--; 00941 } 00942 00943 // 00944 // undo final lock count 00945 // 00946 00947 if ( InterlockedDecrement(&Cs->LockCount) >= 0 ){ 00948 NtSetEvent(Cs->LockSemaphore,NULL); 00949 } 00950 } 00951 00952 // 00953 // if the thread exited while waiting on the loader 00954 // lock clean it up. There is still a potential race 00955 // here since we can not safely know what happens to 00956 // a thread after it interlocked increments the lock count 00957 // but before it sets the waiting on loader lock flag. On the 00958 // release side, it it safe since we mark ownership of the lock 00959 // before clearing the flag. This triggers the first part of this 00960 // test. The only thing out of whack is the recursion count, but this 00961 // is also safe since in this state, recursion count is 0. 00962 // 00963 00964 else if ( Teb->WaitingOnLoaderLock ) { 00965 00966 // 00967 // This code isn't right. We need to bump down our lock count 00968 // increment. 00969 // 00970 // A few cases to consider: 00971 // 00972 // Another thread releases the lock signals the event. 00973 // We take the wait and then die before setting our ID. 00974 // I doubt very much that this can happen because right 00975 // after we come out of the wait, we set the owner Id 00976 // (meaning that we would go through the other part of the if). 00977 // Bottom line is that we should just decrement our lock count 00978 // and get out of the way. There is no need to set the event. 00979 // In the RAS stress failure, I saw us setting the event 00980 // just because the lock count was >= 0. The lock was already held 00981 // by another thread so setting the event let yet another thread 00982 // also own the lock. Last one to release would get a 00983 // not owner critical section failure 00984 // 00985 // 00986 // if ( InterlockedDecrement(&Cs->LockCount) >= 0 ){ 00987 // NtSetEvent(Cs->LockSemaphore,NULL); 00988 // } 00989 // 00990 00991 InterlockedDecrement(&Cs->LockCount); 00992 } 00993 } 00994 #if defined(_WIN64) 00995 if (Process->Wow64Process) { 00996 // Do the same thing for the 32-bit PEB->Ldr 00997 PRTL_CRITICAL_SECTION32 Cs32; 00998 PPEB32 Peb32; 00999 01000 Peb32 = Process->Wow64Process->Wow64; 01001 Cs32 = (PRTL_CRITICAL_SECTION32)ULongToPtr(Peb32->LoaderLock); 01002 if (Cs32) { 01003 ProbeForRead(Cs32,sizeof(*Cs32),4); 01004 if ( Cs32->OwningThread == PtrToUlong(Thread->Cid.UniqueThread) ) { 01005 // 01006 // x86 uses a 1 based recursion count, so the 01007 // IA64 kernel needs to do the same, since 01008 // the critsect is really implemented by IA32 01009 // usermode. 01010 // 01011 DecrementCount = Cs32->RecursionCount; 01012 Cs32->RecursionCount = 0; 01013 Cs32->OwningThread = 0; 01014 01015 // 01016 // undo lock count increments for recursion cases 01017 // 01018 while(DecrementCount > 1) { 01019 InterlockedDecrement(&Cs32->LockCount); 01020 DecrementCount--; 01021 } 01022 01023 // 01024 // undo final lock count 01025 // 01026 if ( InterlockedDecrement(&Cs32->LockCount) >= 0 ){ 01027 NtSetEvent(LongToHandle(Cs32->LockSemaphore),NULL); 01028 } 01029 } else { 01030 PTEB32 Teb32 = WOW64_GET_TEB32(Teb); 01031 01032 ProbeForRead(Teb32,sizeof(*Teb32),4); 01033 if ( Teb32->WaitingOnLoaderLock ) { 01034 InterlockedDecrement(&Cs32->LockCount); 01035 } 01036 } 01037 } 01038 } 01039 #endif 01040 } 01041 except (EXCEPTION_EXECUTE_HANDLER) { 01042 ; 01043 } 01044 01045 #if defined(_WIN64) 01046 if (Process->Wow64Process) { 01047 // 01048 // Free the 32 bit Teb 01049 // 01050 try { 01051 PVOID BaseAddress; 01052 SIZE_T RegionSize; 01053 01054 // Get the TEB32 pointer 01055 BaseAddress = *(PVOID *)WOW64_TEB32_POINTER_ADDRESS(((PTEB)Thread->Tcb.Teb)); 01056 01057 // Free it. ZwFreeVirtualMemory will probe the address 01058 // for us, ensuring that it is in usermode memory. 01059 RegionSize = PAGE_SIZE; 01060 ZwFreeVirtualMemory( NtCurrentProcess(), 01061 &BaseAddress, 01062 &RegionSize, 01063 MEM_RELEASE 01064 ); 01065 01066 } 01067 except (EXCEPTION_EXECUTE_HANDLER) { 01068 ; 01069 } 01070 } 01071 #endif 01072 01073 MmDeleteTeb(Process, Thread->Tcb.Teb); 01074 Thread->Tcb.Teb = NULL; 01075 } 01076 } 01077 01078 // 01079 // Rundown The Lists: 01080 // 01081 // - Cancel Io By Thread 01082 // - Cancel Timers 01083 // - Cancel Registry Notify Requests pending against this thread 01084 // - Perform kernel thread rundown 01085 // 01086 01087 IoCancelThreadIo(Thread); 01088 ExTimerRundown(); 01089 CmNotifyRunDown(Thread); 01090 KeRundownThread(); 01091 01092 // 01093 // delete the Client Id and decrement the reference count for it. 01094 // 01095 01096 if (!(ExChangeHandle(PspCidTable, Thread->Cid.UniqueThread, PspMarkCidInvalid, PSP_INVALID_ID))) { 01097 KeBugCheck(CID_HANDLE_DELETION); 01098 } 01099 ObDereferenceObject(Thread); 01100 01101 // 01102 // Let LPC component deal with message stack in Thread->LpcReplyMessage 01103 // but do it after the client ID becomes invalid. 01104 // 01105 01106 LpcExitThread(Thread); 01107 01108 // 01109 // If this is the last thread in the process, then clean the address space 01110 // 01111 01112 if ( LastThread ) { 01113 if (!(ExChangeHandle(PspCidTable,Process->UniqueProcessId, PspMarkCidInvalid, PSP_INVALID_ID))) { 01114 KeBugCheck(CID_HANDLE_DELETION); 01115 } 01116 KeQuerySystemTime(&Process->ExitTime); 01117 PspExitProcess(TRUE,Process); 01118 } 01119 01120 01121 Thread->ExitStatus = ExitStatus; 01122 KeQuerySystemTime(&Thread->ExitTime); 01123 01124 01125 RemoveEntryList(&Thread->ThreadListEntry); 01126 KeEnterCriticalRegion(); 01127 01128 Thread->ThreadListEntry.Flink = NULL; 01129 Thread->ThreadListEntry.Blink = NULL; 01130 01131 PsUnlockProcess(Process); 01132 ASSERT(Thread->Tcb.KernelApcDisable == 0); 01133 01134 if ( LastThread ) { 01135 01136 // 01137 // can not hold the process lock while running down the object table 01138 // since this can lead to a delete routine, which will need the job 01139 // lock, BUT our lock ordering is always joblock -> processlock 01140 // 01141 01142 ObKillProcess(TRUE, Process); 01143 01144 if ( Process->Job) { 01145 01146 // 01147 // Now we can fold the process accounting into the job. Don't need to wait for 01148 // the delete routine. 01149 // 01150 01151 PspExitProcessFromJob(Process->Job,Process); 01152 01153 } 01154 01155 KeSetProcess(&Process->Pcb,0,FALSE); 01156 01157 } 01158 01159 // 01160 // Rundown pending APCs 01161 // 01162 01163 (VOID) KeDisableApcQueuingThread(&Thread->Tcb); 01164 01165 // 01166 // flush user-mode APC queue 01167 // 01168 01169 FirstEntry = KeFlushQueueApc(&Thread->Tcb,UserMode); 01170 01171 if ( FirstEntry ) { 01172 01173 NextEntry = FirstEntry; 01174 do { 01175 Apc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry); 01176 NextEntry = NextEntry->Flink; 01177 01178 // 01179 // If the APC has a rundown routine then call it. Otherwise 01180 // deallocate the APC 01181 // 01182 01183 if ( Apc->RundownRoutine ) { 01184 (Apc->RundownRoutine)(Apc); 01185 } else { 01186 ExFreePool(Apc); 01187 } 01188 01189 } while (NextEntry != FirstEntry); 01190 } 01191 01192 if ( LastThread ) { 01193 MmCleanProcessAddressSpace(); 01194 } 01195 01196 if ( Thread->Tcb.LegoData && PspLegoNotifyRoutine ) { 01197 (PspLegoNotifyRoutine)(&Thread->Tcb); 01198 } 01199 01200 // 01201 // flush kernel-mode APC queue 01202 // There should never be any kernel mode APCs found this far 01203 // into thread termination. Since we go to PASSIVE_LEVEL upon 01204 // entering exit. 01205 // 01206 01207 FirstEntry = KeFlushQueueApc(&Thread->Tcb,KernelMode); 01208 01209 if ( FirstEntry ) { 01210 KeBugCheckEx( 01211 KERNEL_APC_PENDING_DURING_EXIT, 01212 (ULONG_PTR)FirstEntry, 01213 (ULONG_PTR)Thread->Tcb.KernelApcDisable, 01214 (ULONG_PTR)KeGetCurrentIrql(), 01215 0 01216 ); 01217 } 01218 01219 // 01220 // Terminate the thread. 01221 // 01222 // N.B. There is no return from this call. 01223 // 01224 // N.B. The kernel inserts the current thread in the reaper list and 01225 // activates a thread, if necessary, to reap the terminating thread. 01226 // 01227 01228 KeTerminateThread(0L); 01229 }

BOOLEAN PspMarkCidInvalid IN PHANDLE_TABLE_ENTRY  HandleEntry,
IN ULONG_PTR  Parameter
 

Definition at line 679 of file psdelete.c.

References TRUE.

Referenced by PspExitThread().

00683 { 00684 HandleEntry->Object = (PVOID)Parameter; 00685 return TRUE; 00686 }

VOID PspNullSpecialApc IN PKAPC  Apc,
IN PKNORMAL_ROUTINE NormalRoutine,
IN PVOID *  NormalContext,
IN PVOID *  SystemArgument1,
IN PVOID *  SystemArgument2
 

Definition at line 580 of file psdelete.c.

References ExFreePool(), NULL, PAGED_CODE, and PsGetCurrentThread.

Referenced by PspUserThreadStartup().

00588 { 00589 00590 PAGED_CODE(); 00591 00592 UNREFERENCED_PARAMETER(NormalContext); 00593 UNREFERENCED_PARAMETER(SystemArgument1); 00594 UNREFERENCED_PARAMETER(SystemArgument2); 00595 00596 if ( PsGetCurrentThread()->HasTerminated ) { 00597 *NormalRoutine = NULL; 00598 } 00599 ExFreePool(Apc); 00600 }

VOID PspProcessDelete IN PVOID  Object  ) 
 

Definition at line 1363 of file psdelete.c.

References _KPROCESS::DirectoryTableBase, ExDestroyHandle(), ExFreePool(), FALSE, _EPROCESS::Job, KeBugCheck(), KeStackAttachProcess(), KeTerminateProcess, KeUnstackDetachProcess(), MmDeleteProcessAddressSpace(), NULL, ObDereferenceDeviceMap(), ObDereferenceObject, PAGED_CODE, PERFINFO_PROCESS_DELETE, PspCidTable, PspDeleteLdt(), PspDeleteProcessSecurity(), PspDeleteVdmObjects(), PspDereferenceQuota(), PspExitProcess(), PspRemoveProcessFromJob(), SeAuditProcessExit(), SeDetailedAuditing, and _EPROCESS::Token.

Referenced by PspInitPhase0().

01366 { 01367 PEPROCESS Process; 01368 ULONG AddressSpace; 01369 KAPC_STATE ApcState; 01370 01371 PAGED_CODE(); 01372 01373 Process = (PEPROCESS)Object; 01374 01375 if ( SeDetailedAuditing && Process->Token != NULL ) { 01376 SeAuditProcessExit( 01377 Process 01378 ); 01379 } 01380 01381 if ( Process->Job ) { 01382 PspRemoveProcessFromJob(Process->Job,Process); 01383 ObDereferenceObject(Process->Job); 01384 } 01385 01386 KeTerminateProcess((PKPROCESS)Process); 01387 AddressSpace = (ULONG) 01388 ((PHARDWARE_PTE)(&(Process->Pcb.DirectoryTableBase[0])))->PageFrameNumber; 01389 01390 01391 if (Process->DebugPort) { 01392 ObDereferenceObject(Process->DebugPort); 01393 } 01394 if (Process->ExceptionPort) { 01395 ObDereferenceObject(Process->ExceptionPort); 01396 } 01397 if ( Process->UniqueProcessId ) { 01398 if ( !(ExDestroyHandle(PspCidTable,Process->UniqueProcessId,NULL))) { 01399 KeBugCheck(CID_HANDLE_DELETION); 01400 } 01401 } 01402 01403 PspDeleteLdt( Process ); 01404 PspDeleteVdmObjects( Process ); 01405 01406 if ( AddressSpace ) { 01407 01408 // 01409 // Clean address space of the process 01410 // 01411 01412 KeStackAttachProcess(&Process->Pcb, &ApcState); 01413 01414 PspExitProcess(FALSE,Process); 01415 01416 KeUnstackDetachProcess(&ApcState); 01417 } 01418 01419 PspDeleteProcessSecurity( Process ); 01420 01421 if (AddressSpace) { 01422 MmDeleteProcessAddressSpace(Process); 01423 } 01424 01425 #if DEVL 01426 if ( Process->WorkingSetWatch ) { 01427 ExFreePool(Process->WorkingSetWatch); 01428 } 01429 #endif // DEVL 01430 01431 PERFINFO_PROCESS_DELETE(Process); 01432 01433 ObDereferenceDeviceMap(Process); 01434 PspDereferenceQuota(Process); 01435 }

VOID PspReaper IN PVOID  Context  ) 
 

Definition at line 57 of file psdelete.c.

References FALSE, _KTHREAD::InitialStack, KiLockContextSwap, KiLockDispatcherDatabase, KiUnlockContextSwap, KiUnlockDispatcherDatabase(), _KTHREAD::LargeStack, MmDeleteKernelStack(), NULL, ObDereferenceObject, PsReaperActive, PsReaperListHead, _KTHREAD::StackBase, _ETHREAD::Tcb, and THREAD_TO_PROCESS.

Referenced by PspInitPhase0().

00063 : 00064 00065 This routine implements the thread reaper. The reaper is responsible 00066 for processing terminated threads. This includes: 00067 00068 - deallocating their kernel stacks 00069 00070 - releasing their process' CreateDelete lock 00071 00072 - dereferencing their process 00073 00074 - dereferencing themselves 00075 00076 Arguments: 00077 00078 Context - NOT USED 00079 00080 Return Value: 00081 00082 None. 00083 00084 --*/ 00085 00086 { 00087 00088 PLIST_ENTRY NextEntry; 00089 KIRQL OldIrql, OldIrql2; 00090 PETHREAD Thread; 00091 PEPROCESS Process; 00092 00093 00094 // 00095 // Lock the dispatcher data and continually remove entries from the 00096 // reaper list until no more entries exist. 00097 // 00098 // N.B. The dispatcher database lock is used to synchronize access to 00099 // the reaper list. This is done to avoid a race condition with 00100 // the thread termination code. 00101 // 00102 00103 KiLockDispatcherDatabase(&OldIrql); 00104 NextEntry = PsReaperListHead.Flink; 00105 while (NextEntry != &PsReaperListHead) { 00106 00107 // 00108 // Remove the next thread from the reaper list, get the address of 00109 // the executive thread object, acquire the context swap lock, and 00110 // then release the both the context swap dispatcher database locks. 00111 // 00112 // N.B. The context swap lock is acquired and immediately released. 00113 // This is necessary to ensure that the respective thread has 00114 // completely passed through the context switch code before it 00115 // is terminated. 00116 // 00117 00118 RemoveEntryList(NextEntry); 00119 Thread = CONTAINING_RECORD(NextEntry, ETHREAD, TerminationPortList); 00120 00121 KiLockContextSwap(&OldIrql2); 00122 KiUnlockContextSwap(OldIrql2); 00123 00124 KiUnlockDispatcherDatabase(OldIrql); 00125 00126 // 00127 // Get the address of the executive process object, release the 00128 // process' CreateDelete lock and then dereference the process 00129 // object. 00130 // 00131 00132 Process = THREAD_TO_PROCESS(Thread); 00133 // 00134 // Delete the kernel stack and dereference the thread. 00135 // 00136 00137 MmDeleteKernelStack(Thread->Tcb.StackBase,(BOOLEAN)Thread->Tcb.LargeStack); 00138 Thread->Tcb.InitialStack = NULL; 00139 ObDereferenceObject(Thread); 00140 00141 // 00142 // Lock the dispatcher database and get the address of the next 00143 // entry in the list. 00144 // 00145 00146 KiLockDispatcherDatabase(&OldIrql); 00147 NextEntry = PsReaperListHead.Flink; 00148 } 00149 00150 // 00151 // Set the reaper not active and unlock the dispatcher database. 00152 // 00153 00154 PsReaperActive = FALSE; 00155 KiUnlockDispatcherDatabase(OldIrql); 00156 return; 00157 }

NTSTATUS PspTerminateProcess PEPROCESS  Process,
NTSTATUS  Status,
PSLOCKPROCESSMODE  LockMode
 

Definition at line 384 of file psdelete.c.

References _ETHREAD::HasTerminated, IS_SYSTEM_THREAD, KeForceResumeThread(), KernelMode, NTSTATUS(), ObDereferenceObject, PAGED_CODE, PsGetCurrentProcess, PsLockProcess(), PspTerminateThreadByPointer(), PsUnlockProcess(), Status, _ETHREAD::Tcb, _EPROCESS::ThreadListHead, and TRUE.

Referenced by NtAssignProcessToJobObject(), PsEnforceExecutionTimeLimits(), and PspTerminateAllProcessesInJob().

00392 : 00393 00394 This function causes the specified process and all of 00395 its threads to terminate. 00396 00397 Arguments: 00398 00399 ProcessHandle - Supplies a handle to the process to terminate. 00400 00401 ExitStatus - Supplies the exit status associated with the process. 00402 00403 Return Value: 00404 00405 TBD 00406 00407 --*/ 00408 00409 { 00410 00411 PETHREAD Thread; 00412 PLIST_ENTRY Next; 00413 NTSTATUS st; 00414 00415 PAGED_CODE(); 00416 00417 if ( Process == PsGetCurrentProcess() ) { 00418 return STATUS_INVALID_PARAMETER; 00419 } 00420 00421 // 00422 // the following allows NtTerminateProcess to fail properly if 00423 // called while the exiting process is blocked holding the 00424 // createdeletelock. This can happen during debugger/server 00425 // lpc transactions that occur in pspexitthread 00426 // 00427 00428 st = PsLockProcess(Process,KernelMode,LockMode); 00429 00430 if ( st != STATUS_SUCCESS ) { 00431 return st; 00432 } 00433 00434 Next = Process->ThreadListHead.Flink; 00435 00436 while ( Next != &Process->ThreadListHead) { 00437 00438 Thread = (PETHREAD)(CONTAINING_RECORD(Next,ETHREAD,ThreadListEntry)); 00439 00440 if ( IS_SYSTEM_THREAD(Thread) ) { 00441 ObDereferenceObject(Process); 00442 PsUnlockProcess(Process); 00443 return STATUS_INVALID_PARAMETER; 00444 } 00445 00446 if ( !Thread->HasTerminated ) { 00447 Thread->HasTerminated = TRUE; 00448 PspTerminateThreadByPointer(Thread, Status); 00449 KeForceResumeThread(&Thread->Tcb); 00450 } 00451 Next = Next->Flink; 00452 } 00453 00454 PsUnlockProcess(Process); 00455 00456 return STATUS_SUCCESS; 00457 }

NTSTATUS PspTerminateThreadByPointer IN PETHREAD  Thread,
IN NTSTATUS  ExitStatus
 

Definition at line 160 of file psdelete.c.

References ExAllocatePool, ExFreePool(), KeInitializeApc(), KeInsertQueueApc(), KernelMode, NonPagedPool, NULL, ObDereferenceObject, OriginalApcEnvironment, PAGED_CODE, PsExitSpecialApc(), PsGetCurrentThread, PspExitNormalApc(), and PspExitThread().

Referenced by NtTerminateProcess(), NtTerminateThread(), and PspTerminateProcess().

00167 : 00168 00169 This function causes the specified thread to terminate. 00170 00171 Arguments: 00172 00173 ThreadHandle - Supplies a referenced pointer to the thread to terminate. 00174 00175 ExitStatus - Supplies the exit status associated with the thread. 00176 00177 Return Value: 00178 00179 TBD 00180 00181 --*/ 00182 00183 { 00184 00185 PKAPC ExitApc; 00186 00187 PAGED_CODE(); 00188 00189 if ( Thread == PsGetCurrentThread() ) { 00190 ObDereferenceObject(Thread); 00191 PspExitThread(ExitStatus); 00192 00193 // 00194 // Never Returns 00195 // 00196 00197 } else { 00198 ExitApc = ExAllocatePool(NonPagedPool,(ULONG)sizeof(KAPC)); 00199 00200 if ( !ExitApc ) { 00201 return STATUS_INSUFFICIENT_RESOURCES; 00202 } 00203 00204 KeInitializeApc( 00205 ExitApc, 00206 &Thread->Tcb, 00207 OriginalApcEnvironment, 00208 PsExitSpecialApc, 00209 NULL, 00210 PspExitNormalApc, 00211 KernelMode, 00212 ULongToPtr(ExitStatus) // Sundown: ExitStatus is zero-extended. 00213 ); 00214 00215 00216 if ( !KeInsertQueueApc(ExitApc,ExitApc,NULL, 2) ) { 00217 ExFreePool(ExitApc); 00218 00219 return STATUS_UNSUCCESSFUL; 00220 } 00221 } 00222 00223 return STATUS_SUCCESS; 00224 }

VOID PspThreadDelete IN PVOID  Object  ) 
 

Definition at line 1438 of file psdelete.c.

References ASSERT, _ETHREAD::Cid, ExDestroyHandle(), _KTHREAD::InitialStack, KeBugCheck(), _KTHREAD::LargeStack, MmDeleteKernelStack(), NULL, ObDereferenceObject, PAGED_CODE, PERFINFO_THREAD_DELETE, PspCidTable, PspDeleteThreadSecurity(), _ETHREAD::Tcb, THREAD_TO_PROCESS, and _KTHREAD::Win32Thread.

Referenced by PspInitPhase0().

01441 { 01442 PETHREAD Thread; 01443 PEPROCESS Process; 01444 01445 PAGED_CODE(); 01446 01447 Thread = (PETHREAD) Object; 01448 01449 PERFINFO_THREAD_DELETE(Thread); 01450 01451 ASSERT(Thread->Tcb.Win32Thread == NULL); 01452 01453 if ( Thread->Tcb.InitialStack ) { 01454 MmDeleteKernelStack(Thread->Tcb.InitialStack,(BOOLEAN)Thread->Tcb.LargeStack); 01455 } 01456 01457 if ( Thread->Cid.UniqueThread ) { 01458 if (!(ExDestroyHandle(PspCidTable,Thread->Cid.UniqueThread,NULL))) { 01459 KeBugCheck(CID_HANDLE_DELETION); 01460 } 01461 } 01462 01463 PspDeleteThreadSecurity( Thread ); 01464 01465 Process = THREAD_TO_PROCESS(Thread); 01466 if (Process) { 01467 ObDereferenceObject(Process); 01468 } 01469 }

ULONG PsSetLegoNotifyRoutine PLEGO_NOTIFY_ROUTINE  LegoNotifyRoutine  ) 
 

Definition at line 45 of file psdelete.c.

References PAGED_CODE, and PspLegoNotifyRoutine.

00048 { 00049 PAGED_CODE(); 00050 00051 PspLegoNotifyRoutine = LegoNotifyRoutine; 00052 00053 return FIELD_OFFSET(KTHREAD,LegoData); 00054 }

NTSTATUS PsTerminateSystemThread IN NTSTATUS  ExitStatus  ) 
 

Definition at line 546 of file psdelete.c.

References _ETHREAD::HasTerminated, IS_SYSTEM_THREAD, PsGetCurrentThread, PspExitThread(), and TRUE.

Referenced by SmbTraceThreadEntry(), and xxxDesktopThread().

00552 : 00553 00554 This function causes the current thread, which must be a system 00555 thread, to terminate. 00556 00557 Arguments: 00558 00559 ExitStatus - Supplies the exit status associated with the thread. 00560 00561 Return Value: 00562 00563 None. 00564 00565 --*/ 00566 00567 { 00568 PETHREAD Thread = PsGetCurrentThread(); 00569 00570 if ( !IS_SYSTEM_THREAD(Thread) ) { 00571 return STATUS_INVALID_PARAMETER; 00572 } 00573 00574 Thread->HasTerminated = TRUE; 00575 PspExitThread(ExitStatus); 00576 }


Variable Documentation

PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine
 

Definition at line 42 of file psdelete.c.

Referenced by PspExitThread(), and PsSetLegoNotifyRoutine().


Generated on Sat May 15 19:45:23 2004 for test by doxygen 1.3.7