PTERMINATION_PORT TerminationPort;
PTEB Teb;
KIRQL oldIrql;
- PLIST_ENTRY ApcEntry;
+ PLIST_ENTRY FirstEntry, CurrentEntry;
PKAPC Apc;
DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
happens when the last thread just terminates without explicitly
terminating the process. */
CurrentProcess->ExitTime = CurrentThread->ExitTime;
+ CurrentProcess->ExitStatus = ExitStatus;
}
/* Check if the process has a debug port */
/* Send the LPC Message */
LpcSendTerminationPort(TerminationPort->Port, CurrentThread->CreateTime);
+ ObDereferenceObject(TerminationPort->Port);
/* Free the Port */
ExFreePool(TerminationPort);
KeDisableThreadApcQueueing(&CurrentThread->Tcb);
/* Flush the User APCs */
- ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode);
- while(ApcEntry)
+ FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode);
+ if (FirstEntry != NULL)
{
- /* Get the APC */
- Apc = CONTAINING_RECORD(ApcEntry, KAPC, ApcListEntry);
-
- /* Move to the next one */
- ApcEntry = ApcEntry->Flink;
-
- /* Rundown the APC or de-allocate it */
- if (Apc->RundownRoutine)
- {
- /* Call its own routine */
- (Apc->RundownRoutine)(Apc);
- }
- else
- {
- /* Do it ourselves */
- ExFreePool(Apc);
- }
+ CurrentEntry = FirstEntry;
+ do
+ {
+ /* Get the APC */
+ Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
+
+ /* Move to the next one */
+ CurrentEntry = CurrentEntry->Flink;
+
+ /* Rundown the APC or de-allocate it */
+ if (Apc->RundownRoutine)
+ {
+ /* Call its own routine */
+ (Apc->RundownRoutine)(Apc);
+ }
+ else
+ {
+ /* Do it ourselves */
+ ExFreePool(Apc);
+ }
+ }
+ while (CurrentEntry != FirstEntry);
}
/* Call the Lego routine */
if (CurrentThread->Tcb.LegoData) PspRunLegoRoutine(&CurrentThread->Tcb);
/* Flush the APC queue, which should be empty */
- if ((ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode)))
+ if ((FirstEntry = KeFlushQueueApc(&CurrentThread->Tcb, KernelMode)))
{
/* Bugcheck time */
KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
- (ULONG_PTR)ApcEntry,
+ (ULONG_PTR)FirstEntry,
CurrentThread->Tcb.KernelApcDisable,
oldIrql,
0);
PVOID* SystemArgument1,
PVOID* SystemArguemnt2)
{
- DPRINT1("PsExitSpecialApc called: 0x%x (proc: 0x%x, '%.16s')\n",
- PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
+ DPRINT("PsExitSpecialApc called: 0x%x (proc: 0x%x, '%.16s')\n",
+ PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
/* Don't do anything unless we are in User-Mode */
if (Apc->SystemArgument2)
PETHREAD Thread = PsGetCurrentThread();
NTSTATUS ExitStatus;
- DPRINT1("PspExitNormalApc called: 0x%x (proc: 0x%x, '%.16s')\n",
- PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
+ DPRINT("PspExitNormalApc called: 0x%x (proc: 0x%x, '%.16s')\n",
+ PsGetCurrentThread(), PsGetCurrentProcess(), PsGetCurrentProcess()->ImageFileName);
/* This should never happen */
ASSERT(!SystemArgument2);
}
/* If we're here, this is not a System Thread, so kill it from User-Mode */
- DPRINT1("Initializing User-Mode APC\n");
+ DPRINT("Initializing User-Mode APC\n");
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
ObKillProcess(Process);
KeSetProcess(&Process->Pcb, IO_NO_INCREMENT);
+
+ /* release the keep-alive reference of the process object */
+ ObDereferenceObject(Process);
return(STATUS_SUCCESS);
}
we kill ourselves to prevent threads outside of our process trying
to kill us */
KeQuerySystemTime(&Process->ExitTime);
+ Process->ExitStatus = ExitStatus;
/* Only master thread remains... kill it off */
if (CurrentThread->ThreadsProcess == Process) {