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
|
STDCALL
|
||||||
KeForceResumeThread(IN PKTHREAD Thread);
|
KeForceResumeThread(IN PKTHREAD Thread);
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
STDCALL
|
||||||
|
KeDisableThreadApcQueueing(IN PKTHREAD Thread);
|
||||||
|
|
||||||
BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
|
BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime);
|
||||||
|
|
||||||
VOID inline FASTCALL KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread);
|
VOID inline FASTCALL KiSatisfyObjectWait(PDISPATCHER_HEADER Object, PKTHREAD Thread);
|
||||||
|
@ -292,6 +296,12 @@ VOID STDCALL KiInitializeUserApc(IN PVOID Reserved,
|
||||||
IN PVOID SystemArgument1,
|
IN PVOID SystemArgument1,
|
||||||
IN PVOID SystemArgument2);
|
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 KiAttachProcess(struct _KTHREAD *Thread, struct _KPROCESS *Process, KIRQL ApcLock, struct _KAPC_STATE *SavedApcState);
|
||||||
|
|
||||||
VOID STDCALL KiSwapProcess(struct _KPROCESS *NewProcess, struct _KPROCESS *OldProcess);
|
VOID STDCALL KiSwapProcess(struct _KPROCESS *NewProcess, struct _KPROCESS *OldProcess);
|
||||||
|
|
|
@ -184,6 +184,10 @@ VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
PspRunCreateProcessNotifyRoutines(PEPROCESS, BOOLEAN);
|
PspRunCreateProcessNotifyRoutines(PEPROCESS, BOOLEAN);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
PspRunLegoRoutine(IN PKTHREAD Thread);
|
||||||
|
|
||||||
VOID INIT_FUNCTION PsInitJobManagment(VOID);
|
VOID INIT_FUNCTION PsInitJobManagment(VOID);
|
||||||
|
|
||||||
/* CLIENT ID */
|
/* CLIENT ID */
|
||||||
|
|
|
@ -270,14 +270,14 @@ KiInsertQueueApc(PKAPC Apc,
|
||||||
*/
|
*/
|
||||||
if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) {
|
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;
|
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
|
||||||
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
||||||
&Apc->ApcListEntry);
|
&Apc->ApcListEntry);
|
||||||
|
|
||||||
} else if (Apc->NormalRoutine == NULL) {
|
} 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;
|
for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink;
|
||||||
ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode];
|
ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode];
|
||||||
|
@ -293,7 +293,7 @@ KiInsertQueueApc(PKAPC Apc,
|
||||||
|
|
||||||
} else {
|
} 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],
|
InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
||||||
&Apc->ApcListEntry);
|
&Apc->ApcListEntry);
|
||||||
}
|
}
|
||||||
|
@ -440,6 +440,73 @@ KeInsertQueueApc(PKAPC Apc,
|
||||||
return Inserted;
|
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
|
* KeRemoveQueueApc
|
||||||
*
|
*
|
||||||
|
|
|
@ -387,6 +387,29 @@ KeGetPreviousMode(VOID)
|
||||||
return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode;
|
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
|
VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
KeRundownThread(VOID)
|
KeRundownThread(VOID)
|
||||||
|
|
|
@ -213,6 +213,8 @@ PspExitThread(NTSTATUS ExitStatus)
|
||||||
PTERMINATION_PORT TerminationPort;
|
PTERMINATION_PORT TerminationPort;
|
||||||
PTEB Teb;
|
PTEB Teb;
|
||||||
KIRQL oldIrql;
|
KIRQL oldIrql;
|
||||||
|
PLIST_ENTRY ApcEntry, CurrentApc;
|
||||||
|
PKAPC Apc;
|
||||||
|
|
||||||
DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
|
DPRINT("PspExitThread(ExitStatus %x), Current: 0x%x\n", ExitStatus, PsGetCurrentThread());
|
||||||
|
|
||||||
|
@ -332,6 +334,50 @@ PspExitThread(NTSTATUS ExitStatus)
|
||||||
/* Rundown Mutexes */
|
/* Rundown Mutexes */
|
||||||
KeRundownThread();
|
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 */
|
/* Terminate the Thread from the Scheduler */
|
||||||
KeTerminateThread(0);
|
KeTerminateThread(0);
|
||||||
DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread());
|
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
|
static PLOAD_IMAGE_NOTIFY_ROUTINE
|
||||||
PspLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT];
|
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 ***************************************************************/
|
/* FUNCTIONS ***************************************************************/
|
||||||
|
|
||||||
|
@ -231,4 +232,12 @@ PspRunLoadImageNotifyRoutines(PUNICODE_STRING FullImageName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
PspRunLegoRoutine(IN PKTHREAD Thread)
|
||||||
|
{
|
||||||
|
/* Call it */
|
||||||
|
if (PspLegoNotifyRoutine) (PspLegoNotifyRoutine)(Thread);
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in a new issue