mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:23:03 +00:00
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:
parent
fe8ad2a13b
commit
a642687b55
4 changed files with 102 additions and 55 deletions
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue