mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 01:24:38 +00:00
- Disable APC Queuing & Flush APC queues during thread shutdown.
- Detect if Kernel APCs were pending during thread shutdown. - Call Lego Routine, if registered, during thread shutdown. svn path=/trunk/; revision=16705
This commit is contained in:
parent
b244520c5a
commit
7669e8fd6d
6 changed files with 164 additions and 5 deletions
|
@ -253,6 +253,10 @@ ULONG
|
|||
STDCALL
|
||||
KeForceResumeThread(IN PKTHREAD Thread);
|
||||
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
KeDisableThreadApcQueueing(IN PKTHREAD Thread);
|
||||
|
||||
BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
|
||||
|
||||
VOID inline FASTCALL KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread);
|
||||
|
@ -292,6 +296,12 @@ VOID STDCALL KiInitializeUserApc(IN PVOID Reserved,
|
|||
IN PVOID SystemArgument1,
|
||||
IN PVOID SystemArgument2);
|
||||
|
||||
PLIST_ENTRY
|
||||
STDCALL
|
||||
KeFlushQueueApc(IN PKTHREAD Thread,
|
||||
IN KPROCESSOR_MODE PreviousMode);
|
||||
|
||||
|
||||
VOID STDCALL KiAttachProcess(struct _KTHREAD *Thread, struct _KPROCESS *Process, KIRQL ApcLock, struct _KAPC_STATE *SavedApcState);
|
||||
|
||||
VOID STDCALL KiSwapProcess(struct _KPROCESS *NewProcess, struct _KPROCESS *OldProcess);
|
||||
|
|
|
@ -184,6 +184,10 @@ VOID
|
|||
STDCALL
|
||||
PspRunCreateProcessNotifyRoutines(PEPROCESS, BOOLEAN);
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
PspRunLegoRoutine(IN PKTHREAD Thread);
|
||||
|
||||
VOID INIT_FUNCTION PsInitJobManagment(VOID);
|
||||
|
||||
/* CLIENT ID */
|
||||
|
|
|
@ -270,14 +270,14 @@ KiInsertQueueApc(PKAPC Apc,
|
|||
*/
|
||||
if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) {
|
||||
|
||||
DPRINT ("Inserting the Process Exit APC into the Queue\n");
|
||||
DPRINT1("Inserting the Process Exit APC into the Queue\n");
|
||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
|
||||
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
||||
&Apc->ApcListEntry);
|
||||
|
||||
} else if (Apc->NormalRoutine == NULL) {
|
||||
|
||||
DPRINT ("Inserting Special APC %x into the Queue\n", Apc);
|
||||
DPRINT("Inserting Special APC %x into the Queue\n", Apc);
|
||||
|
||||
for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink;
|
||||
ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode];
|
||||
|
@ -293,7 +293,7 @@ KiInsertQueueApc(PKAPC Apc,
|
|||
|
||||
} else {
|
||||
|
||||
DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode);
|
||||
DPRINT("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode);
|
||||
InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
||||
&Apc->ApcListEntry);
|
||||
}
|
||||
|
@ -440,6 +440,73 @@ KeInsertQueueApc(PKAPC Apc,
|
|||
return Inserted;
|
||||
}
|
||||
|
||||
/*++
|
||||
* KeFlushQueueApc
|
||||
*
|
||||
* The KeFlushQueueApc routine flushes all APCs of the given processor mode
|
||||
* from the specified Thread's APC queue.
|
||||
*
|
||||
* Params:
|
||||
* Thread - Pointer to the thread whose APC queue will be flushed.
|
||||
*
|
||||
* PreviousMode - Specifies which APC Queue to flush.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the first entry in the flushed APC queue.
|
||||
*
|
||||
* Remarks:
|
||||
* If the routine returns NULL, it means that no APCs were to be flushed.
|
||||
*
|
||||
* Callers of KeFlushQueueApc must be running at DISPATCH_LEVEL or lower.
|
||||
*
|
||||
*--*/
|
||||
PLIST_ENTRY
|
||||
STDCALL
|
||||
KeFlushQueueApc(IN PKTHREAD Thread,
|
||||
IN KPROCESSOR_MODE PreviousMode)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PKAPC Apc;
|
||||
PLIST_ENTRY ApcEntry, CurrentEntry;
|
||||
|
||||
/* Lock the Dispatcher Database and APC Queue */
|
||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||
|
||||
/* Check if the list is empty */
|
||||
if (IsListEmpty(&Thread->ApcState.ApcListHead[PreviousMode]))
|
||||
{
|
||||
/* We'll return NULL */
|
||||
ApcEntry = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove this one */
|
||||
RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]);
|
||||
CurrentEntry = ApcEntry;
|
||||
|
||||
/* Remove all the other ones too, if present */
|
||||
do
|
||||
{
|
||||
/* Get the APC */
|
||||
Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
|
||||
|
||||
/* Move to the next one */
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
|
||||
/* Mark it as not inserted */
|
||||
Apc->Inserted = FALSE;
|
||||
} while (ApcEntry != CurrentEntry);
|
||||
}
|
||||
|
||||
/* Release the locks */
|
||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||
|
||||
/* Return the first entry */
|
||||
return ApcEntry;
|
||||
}
|
||||
|
||||
/*++
|
||||
* KeRemoveQueueApc
|
||||
*
|
||||
|
|
|
@ -387,6 +387,29 @@ KeGetPreviousMode(VOID)
|
|||
return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
STDCALL
|
||||
KeDisableThreadApcQueueing(IN PKTHREAD Thread)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
BOOLEAN PreviousState;
|
||||
|
||||
/* Lock the Dispatcher Database */
|
||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||
|
||||
/* Save old state */
|
||||
PreviousState = Thread->ApcQueueable;
|
||||
|
||||
/* Disable it now */
|
||||
Thread->ApcQueueable = FALSE;
|
||||
|
||||
/* Release the Lock */
|
||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||
|
||||
/* Return old state */
|
||||
return PreviousState;
|
||||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
KeRundownThread(VOID)
|
||||
|
|
|
@ -213,6 +213,8 @@ PspExitThread(NTSTATUS ExitStatus)
|
|||
PTERMINATION_PORT TerminationPort;
|
||||
PTEB Teb;
|
||||
KIRQL oldIrql;
|
||||
PLIST_ENTRY ApcEntry, CurrentApc;
|
||||
PKAPC Apc;
|
||||
|
||||
DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
|
||||
|
||||
|
@ -332,6 +334,50 @@ PspExitThread(NTSTATUS ExitStatus)
|
|||
/* Rundown Mutexes */
|
||||
KeRundownThread();
|
||||
|
||||
/* Disable new APC Queuing, this is as far as we'll let them go */
|
||||
KeDisableThreadApcQueueing(&CurrentThread->Tcb);
|
||||
|
||||
/* Flush the User APCs */
|
||||
if ((ApcEntry = KeFlushQueueApc(&CurrentThread->Tcb, UserMode)))
|
||||
{
|
||||
CurrentApc = ApcEntry;
|
||||
do
|
||||
{
|
||||
/* Get the APC */
|
||||
Apc = CONTAINING_RECORD(CurrentApc, KAPC, ApcListEntry);
|
||||
|
||||
/* Move to the next one */
|
||||
CurrentApc = CurrentApc->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 (CurrentApc != ApcEntry);
|
||||
}
|
||||
|
||||
/* 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)))
|
||||
{
|
||||
/* Bugcheck time */
|
||||
KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
|
||||
(ULONG_PTR)ApcEntry,
|
||||
CurrentThread->Tcb.KernelApcDisable,
|
||||
oldIrql,
|
||||
0);
|
||||
}
|
||||
|
||||
/* Terminate the Thread from the Scheduler */
|
||||
KeTerminateThread(0);
|
||||
DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
|
||||
|
|
|
@ -26,8 +26,9 @@ PspProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
|
|||
|
||||
static PLOAD_IMAGE_NOTIFY_ROUTINE
|
||||
PspLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT];
|
||||
|
||||
static PVOID PspLegoNotifyRoutine;
|
||||
|
||||
typedef VOID (STDCALL *PLEGO_NOTIFY_ROUTINE)(IN PKTHREAD Thread);
|
||||
static PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine;
|
||||
|
||||
/* FUNCTIONS ***************************************************************/
|
||||
|
||||
|
@ -231,4 +232,12 @@ PspRunLoadImageNotifyRoutines(PUNICODE_STRING FullImageName,
|
|||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
PspRunLegoRoutine(IN PKTHREAD Thread)
|
||||
{
|
||||
/* Call it */
|
||||
if (PspLegoNotifyRoutine) (PspLegoNotifyRoutine)(Thread);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue