fixed thread/process termination bugs that might have caused crashes. due to a apc bug gui threads terminating gui threads doesn't work. Alex is going to take care of it.

svn path=/trunk/; revision=14261
This commit is contained in:
Thomas Bluemel 2005-03-22 02:32:14 +00:00
parent fe8ad2a13b
commit a642687b55
4 changed files with 102 additions and 55 deletions

View file

@ -658,7 +658,7 @@ NTSTATUS PsCreateCidHandle(PVOID Object, POBJECT_TYPE ObjectType, PHANDLE Handle
NTSTATUS PsDeleteCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType); NTSTATUS PsDeleteCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType);
PHANDLE_TABLE_ENTRY PsLookupCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType, PVOID *Object); PHANDLE_TABLE_ENTRY PsLookupCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType, PVOID *Object);
VOID PsUnlockCidHandle(PHANDLE_TABLE_ENTRY CidEntry); VOID PsUnlockCidHandle(PHANDLE_TABLE_ENTRY CidEntry);
NTSTATUS PsLockProcess(PEPROCESS Process, BOOL Timeout); NTSTATUS PsLockProcess(PEPROCESS Process, BOOLEAN Timeout);
VOID PsUnlockProcess(PEPROCESS Process); VOID PsUnlockProcess(PEPROCESS Process);
#define ETHREAD_TO_KTHREAD(pEThread) (&(pEThread)->Tcb) #define ETHREAD_TO_KTHREAD(pEThread) (&(pEThread)->Tcb)

View file

@ -372,6 +372,21 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
{ {
return(Status); return(Status);
} }
Status = PsLockProcess(Process, FALSE);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Process);
return(Status);
}
if(Process->ExitTime.QuadPart != 0)
{
PsUnlockProcess(Process);
return STATUS_PROCESS_IS_TERMINATING;
}
PsUnlockProcess(Process);
Status = PsInitializeThread(Process, Status = PsInitializeThread(Process,
&Thread, &Thread,

View file

@ -103,11 +103,9 @@ PspTerminateProcessThreads(PEPROCESS Process,
if (!Thread->HasTerminated) { if (!Thread->HasTerminated) {
Thread->HasTerminated = TRUE; Thread->HasTerminated = TRUE;
/* Terminate it by APC */ /* Terminate it by APC */
PspTerminateThreadByPointer(Thread, ExitStatus); PspTerminateThreadByPointer(Thread, ExitStatus);
/* Unsuspend it */
KeForceResumeThread(&Thread->Tcb);
} }
} }
} }
@ -181,7 +179,7 @@ PspExitThread(NTSTATUS ExitStatus)
PVOID TebBlock; PVOID TebBlock;
PTERMINATION_PORT TerminationPort; PTERMINATION_PORT TerminationPort;
DPRINT("PsTerminateCurrentThread(ExitStatus %x)\n", ExitStatus); DPRINT("PsTerminateCurrentThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
/* Get the Current Thread and Process */ /* Get the Current Thread and Process */
CurrentThread = PsGetCurrentThread(); CurrentThread = PsGetCurrentThread();
@ -202,6 +200,10 @@ PspExitThread(NTSTATUS ExitStatus)
/* Run Thread Notify Routines before we desintegrate the thread */ /* Run Thread Notify Routines before we desintegrate the thread */
PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE); PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE);
/* Set the Exit Status and Exit Time */
CurrentThread->ExitStatus = ExitStatus;
KeQuerySystemTime(&CurrentThread->ExitTime);
/* Lock the Process before we modify its thread entries */ /* Lock the Process before we modify its thread entries */
PsLockProcess(CurrentProcess, FALSE); PsLockProcess(CurrentProcess, FALSE);
@ -213,8 +215,13 @@ PspExitThread(NTSTATUS ExitStatus)
/* Set the last Thread Exit Status */ /* Set the last Thread Exit Status */
CurrentProcess->LastThreadExitStatus = ExitStatus; CurrentProcess->LastThreadExitStatus = ExitStatus;
/* Unlock the Process */ if (Last) {
PsUnlockProcess(CurrentProcess);
/* Save the Exit Time if not already done by NtTerminateProcess. This
happens when the last thread just terminates without explicitly
terminating the process. */
CurrentProcess->ExitTime = CurrentThread->ExitTime;
}
/* Check if the process has a debug port */ /* Check if the process has a debug port */
if (CurrentProcess->DebugPort) { if (CurrentProcess->DebugPort) {
@ -239,22 +246,15 @@ PspExitThread(NTSTATUS ExitStatus)
DPRINT("TerminationPort: %p\n", TerminationPort); DPRINT("TerminationPort: %p\n", TerminationPort);
} }
/* Rundown Win32 Structures */ /* Rundown Win32 Structures */DPRINT1("Terminating win32 thread 0x%x (proc 0x%x)\n", CurrentThread, CurrentThread->ThreadsProcess);
PsTerminateWin32Thread(CurrentThread); PsTerminateWin32Thread(CurrentThread);if (Last) {DPRINT1("Terminating win32 process 0x%x (thread 0x%x)\n", CurrentProcess, CurrentThread); }
if (Last) PsTerminateWin32Process(CurrentProcess); if (Last) PsTerminateWin32Process(CurrentProcess);
/* Cancel I/O for the thread. */ /* Cancel I/O for the thread. */
IoCancelThreadIo(CurrentThread); IoCancelThreadIo(CurrentThread);
/* Rundown Timers */
ExTimerRundown();
KeCancelTimer(&CurrentThread->Tcb.Timer);
/* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */ /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */
//CmNotifyRunDown(CurrentThread); //CmNotifyRunDown(CurrentThread);
/* Rundown Mutexes */
KeRundownThread();
/* Free the TEB */ /* Free the TEB */
if(CurrentThread->Tcb.Teb) { if(CurrentThread->Tcb.Teb) {
@ -282,19 +282,25 @@ PspExitThread(NTSTATUS ExitStatus)
ExReleaseFastMutex(&CurrentProcess->TebLock); ExReleaseFastMutex(&CurrentProcess->TebLock);
} }
/* Set the Exit Status and Exit Time */ /* The last Thread shuts down the Process */if (Last) {DPRINT1("calling PspExitProcess\n");}
CurrentThread->ExitStatus = ExitStatus; if (Last) PspExitProcess(CurrentProcess);
KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime);
/* Unlock the Process */DPRINT1("Released process 0x%x lock by 0x%x\n", CurrentProcess, PsGetCurrentThread());
PsUnlockProcess(CurrentProcess);
/* Rundown Timers */
ExTimerRundown();
KeCancelTimer(&CurrentThread->Tcb.Timer);
/* If the Processor Control Block's NpxThread points to the current thread /* If the Processor Control Block's NpxThread points to the current thread
* unset it. * unset it.
*/ */
InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread,
NULL, NULL,
(PKPROCESS)CurrentThread); (PKPROCESS)CurrentThread);
/* The last Thread shuts down the Process */ /* Rundown Mutexes */
if (Last) PspExitProcess(CurrentProcess); KeRundownThread();
/* Terminate the Thread from the Scheduler */ /* Terminate the Thread from the Scheduler */
KeTerminateThread(0); KeTerminateThread(0);
@ -312,11 +318,16 @@ PsExitSpecialApc(PKAPC Apc,
{ {
NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext; NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
DPRINT("PsExitSpecialApc called: 0x%x\n", PsGetCurrentThread());
/* Free the APC */ /* Free the APC */
ExFreePool(Apc); ExFreePool(Apc);
/* Terminate the Thread */ /* Terminate the Thread */
PspExitThread(ExitStatus); PspExitThread(ExitStatus);
/* we should never reach this point! */
KEBUGCHECK(0);
} }
VOID VOID
@ -330,6 +341,9 @@ PspExitNormalApc(PVOID NormalContext,
*/ */
DPRINT1("APC2\n"); DPRINT1("APC2\n");
PspExitThread((NTSTATUS)NormalContext); PspExitThread((NTSTATUS)NormalContext);
/* we should never reach this point! */
KEBUGCHECK(0);
} }
/* /*
@ -347,9 +361,12 @@ PspTerminateThreadByPointer(PETHREAD Thread,
/* Check if we are already in the right context */ /* Check if we are already in the right context */
if (PsGetCurrentThread() == Thread) { if (PsGetCurrentThread() == Thread) {
/* Directly terminate the thread */ /* Directly terminate the thread */
PspExitThread(ExitStatus); PspExitThread(ExitStatus);
/* we should never reach this point! */
KEBUGCHECK(0);
} }
/* Allocate the APC */ /* Allocate the APC */
@ -388,12 +405,12 @@ PspExitProcess(PEPROCESS Process)
RemoveEntryList(&Process->ProcessListEntry); RemoveEntryList(&Process->ProcessListEntry);
ExReleaseFastMutex(&PspActiveProcessMutex); ExReleaseFastMutex(&PspActiveProcessMutex);
/* close all handles associated with our process, this needs to be done
when the last thread still runs */
ObKillProcess(Process); ObKillProcess(Process);
KeSetProcess(&Process->Pcb, IO_NO_INCREMENT); KeSetProcess(&Process->Pcb, IO_NO_INCREMENT);
/* NOTE: This dereference corresponds to reference in NtTerminateProcess. */
ObDereferenceObject(Process);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -424,38 +441,47 @@ NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
} }
PsLockProcess(Process, FALSE); PsLockProcess(Process, FALSE);
if(Process->ExitTime.QuadPart) { if(Process->ExitTime.QuadPart != 0)
{
DPRINT1("Process has an exit time!\n"); PsUnlockProcess(Process);
KeLeaveCriticalRegion(); return STATUS_PROCESS_IS_TERMINATING;
return STATUS_PROCESS_IS_TERMINATING;
} }
/* Terminate all the Process's Threads */ /* Terminate all the Process's Threads */
PspTerminateProcessThreads(Process, ExitStatus); PspTerminateProcessThreads(Process, ExitStatus);
/* Save the Exit Time */
KeQuerySystemTime(&Process->ExitTime);
PsUnlockProcess(Process);
/* Only master thread remains... kill it off */ /* Only master thread remains... kill it off */
if (PsGetCurrentThread()->ThreadsProcess == Process) { if (PsGetCurrentThread()->ThreadsProcess == Process) {
/* /* set the exit time as we're about to release the process lock before
* NOTE: Dereferencing of the Process structure takes place in we kill ourselves to prevent threads outside of our process trying
* PspExitProcess. If we would do it here the Win32 Process to kill us */
* information would be destroyed before the Win32 Destroy KeQuerySystemTime(&Process->ExitTime);
* thread/process callback is called.
*/
PsUnlockProcess(Process);
/* we can safely dereference the process because the current thread
holds a reference to it until it gets reaped */
ObDereferenceObject(Process);
/* now the other threads get a chance to terminate, we don't wait but
just kill ourselves right now. The process will be run down when the
last thread terminates */
PspExitThread(ExitStatus); PspExitThread(ExitStatus);
return(STATUS_SUCCESS);
/* we should never reach this point! */
KEBUGCHECK(0);
}
else
{
/* unlock and dereference the process so the threads can kill themselves */
PsUnlockProcess(Process);
ObDereferenceObject(Process);
DPRINT1("Terminated foreign process 0x%x\n", Process);
} }
/* If we took this path instead, then do the same as above */
ObDereferenceObject(Process);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
@ -498,17 +524,20 @@ NtTerminateThread(IN HANDLE ThreadHandle,
/* Terminate it */ /* Terminate it */
PspTerminateThreadByPointer(Thread, ExitStatus); PspTerminateThreadByPointer(Thread, ExitStatus);
/* Resume it */
KeForceResumeThread(&Thread->Tcb);
} }
} else { } else {
/* it's safe to dereference thread, there's at least the keep-alive
reference which will be removed by the thread reaper causing the
thread to be finally destroyed */
ObDereferenceObject(Thread); ObDereferenceObject(Thread);
/* Terminate him, he's ours */ /* Terminate him, he's ours */
PspExitThread(ExitStatus); PspExitThread(ExitStatus);
/* We do never reach this point */
/* We do never reach this point */
KEBUGCHECK(0);
} }
/* Dereference the Thread and return */ /* Dereference the Thread and return */
@ -534,6 +563,10 @@ PsTerminateSystemThread(NTSTATUS ExitStatus)
/* Terminate it for real */ /* Terminate it for real */
PspExitThread(ExitStatus); PspExitThread(ExitStatus);
/* we should never reach this point! */
KEBUGCHECK(0);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }

View file

@ -1645,7 +1645,7 @@ PsReturnProcessPagedPoolQuota(
} }
NTSTATUS NTSTATUS
PsLockProcess(PEPROCESS Process, BOOL Timeout) PsLockProcess(PEPROCESS Process, BOOLEAN Timeout)
{ {
ULONG Attempts = 0; ULONG Attempts = 0;
PKTHREAD PrevLockOwner; PKTHREAD PrevLockOwner;
@ -1689,9 +1689,8 @@ PsLockProcess(PEPROCESS Process, BOOL Timeout)
} }
#endif #endif
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
break;
} }
break;
} }
else else
{ {