mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
- Fix several flaws in APC logic.
- Properly support Special APC Disabling. - Allow Guarded Mutex and Guarded Regions to function properly. - Optimize some code and add some additional checks. - Fix several bugs in KeFreezeAllThreads svn path=/trunk/; revision=18117
This commit is contained in:
parent
bfcd1fab3c
commit
29322a96bc
3 changed files with 328 additions and 190 deletions
|
@ -55,7 +55,8 @@ extern ULONG_PTR KERNEL_BASE;
|
||||||
PKTHREAD _Thread = KeGetCurrentThread(); \
|
PKTHREAD _Thread = KeGetCurrentThread(); \
|
||||||
if((_Thread) && (++_Thread->KernelApcDisable == 0)) \
|
if((_Thread) && (++_Thread->KernelApcDisable == 0)) \
|
||||||
{ \
|
{ \
|
||||||
if (!IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode])) \
|
if (!IsListEmpty(&_Thread->ApcState.ApcListHead[KernelMode]) && \
|
||||||
|
(_Thread->SpecialApcDisable == 0)) \
|
||||||
{ \
|
{ \
|
||||||
KiKernelApcDeliveryCheck(); \
|
KiKernelApcDeliveryCheck(); \
|
||||||
} \
|
} \
|
||||||
|
|
|
@ -123,7 +123,8 @@ KeLeaveCriticalRegion (VOID)
|
||||||
if((Thread) && (++Thread->KernelApcDisable == 0))
|
if((Thread) && (++Thread->KernelApcDisable == 0))
|
||||||
{
|
{
|
||||||
/* Check if we need to request an APC Delivery */
|
/* Check if we need to request an APC Delivery */
|
||||||
if (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
|
if ((!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) &&
|
||||||
|
(Thread->SpecialApcDisable == 0))
|
||||||
{
|
{
|
||||||
/* Check for the right environment */
|
/* Check for the right environment */
|
||||||
KiKernelApcDeliveryCheck();
|
KiKernelApcDeliveryCheck();
|
||||||
|
@ -225,6 +226,32 @@ KeInitializeApc(IN PKAPC Apc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
__inline
|
||||||
|
VOID
|
||||||
|
KiRequestApcInterrupt(IN PKTHREAD Thread)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
PKPRCB Prcb, CurrentPrcb;
|
||||||
|
LONG i;
|
||||||
|
|
||||||
|
CurrentPrcb = KeGetCurrentPrcb();
|
||||||
|
for (i = 0; i < KeNumberProcessors; i++)
|
||||||
|
{
|
||||||
|
Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
|
||||||
|
if (Prcb->CurrentThread == Thread)
|
||||||
|
{
|
||||||
|
ASSERT (CurrentPrcb != Prcb);
|
||||||
|
KiIpiSendRequest(Prcb->SetMember, IPI_APC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT (i < KeNumberProcessors);
|
||||||
|
#else
|
||||||
|
HalRequestSoftwareInterrupt(APC_LEVEL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
* KiInsertQueueApc
|
* KiInsertQueueApc
|
||||||
*
|
*
|
||||||
|
@ -238,8 +265,7 @@ KeInitializeApc(IN PKAPC Apc,
|
||||||
* PriorityBoost - Priority Boost to apply to the Thread.
|
* PriorityBoost - Priority Boost to apply to the Thread.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* If the APC is already inserted or APC queueing is disabled, FALSE.
|
* None
|
||||||
* Otherwise, TRUE.
|
|
||||||
*
|
*
|
||||||
* Remarks:
|
* Remarks:
|
||||||
* The APC will execute at APC_LEVEL for the KernelRoutine registered, and
|
* The APC will execute at APC_LEVEL for the KernelRoutine registered, and
|
||||||
|
@ -248,122 +274,175 @@ KeInitializeApc(IN PKAPC Apc,
|
||||||
* Callers of this routine must have locked the dipatcher database.
|
* Callers of this routine must have locked the dipatcher database.
|
||||||
*
|
*
|
||||||
*--*/
|
*--*/
|
||||||
BOOLEAN
|
VOID
|
||||||
STDCALL
|
FASTCALL
|
||||||
KiInsertQueueApc(PKAPC Apc,
|
KiInsertQueueApc(PKAPC Apc,
|
||||||
KPRIORITY PriorityBoost)
|
KPRIORITY PriorityBoost)
|
||||||
{
|
{
|
||||||
PKTHREAD Thread = Apc->Thread;
|
PKTHREAD Thread = Apc->Thread;
|
||||||
|
PKAPC_STATE ApcState;
|
||||||
|
KPROCESSOR_MODE ApcMode;
|
||||||
|
PLIST_ENTRY ListHead, NextEntry;
|
||||||
|
PKAPC QueuedApc;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Acquire the lock (only needed on MP) */
|
||||||
KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
|
KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
|
||||||
|
|
||||||
/* Don't do anything if the APC is already inserted */
|
/* Little undocumented feature: Special Apc State Index */
|
||||||
if (Apc->Inserted) {
|
if (Apc->ApcStateIndex == 3)
|
||||||
|
{
|
||||||
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
/* This tells us to use the thread's */
|
||||||
return FALSE;
|
Apc->ApcStateIndex = Thread->ApcStateIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the APC State for this Index, and the mode too */
|
||||||
|
ApcState = Thread->ApcStatePointer[(int)Apc->ApcStateIndex];
|
||||||
|
ApcMode = Apc->ApcMode;
|
||||||
|
|
||||||
/* Three scenarios:
|
/* Three scenarios:
|
||||||
1) Kernel APC with Normal Routine or User APC = Put it at the end of the List
|
* 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List
|
||||||
2) User APC which is PsExitSpecialApc = Put it at the front of the List
|
* 2) User APC which is PsExitSpecialApc = Put it at the front of the List
|
||||||
3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list
|
* 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list
|
||||||
*/
|
*/
|
||||||
if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) {
|
if (Apc->NormalRoutine)
|
||||||
|
{
|
||||||
|
/* Normal APC; is it the Thread Termination APC? */
|
||||||
|
if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc))
|
||||||
|
{
|
||||||
|
/* Set User APC pending to true */
|
||||||
|
Thread->ApcState.UserApcPending = TRUE;
|
||||||
|
|
||||||
DPRINT("Inserting the Thread Exit APC for '%.16s' into the Queue\n", ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
|
/* Insert it at the top of the list */
|
||||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE;
|
InsertHeadList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry);
|
||||||
InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
|
||||||
&Apc->ApcListEntry);
|
|
||||||
|
|
||||||
} else if (Apc->NormalRoutine == NULL) {
|
/* Display debug message */
|
||||||
|
DPRINT1("Inserted the Thread Exit APC for '%.16s' into the Queue\n",
|
||||||
|
((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Regular user or kernel Normal APC */
|
||||||
|
InsertTailList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry);
|
||||||
|
|
||||||
DPRINT("Inserting Special APC %x for '%.16s' into the Queue\n", Apc, ((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
|
/* Display debug message */
|
||||||
|
DPRINT("Inserted Normal APC for '%.16s' into the Queue\n",
|
||||||
|
((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Special APC, find the first Normal APC in the list */
|
||||||
|
ListHead = &ApcState->ApcListHead[ApcMode];
|
||||||
|
NextEntry = ListHead->Flink;
|
||||||
|
while(NextEntry != ListHead)
|
||||||
|
{
|
||||||
|
/* Get the APC */
|
||||||
|
QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
|
||||||
|
|
||||||
/* insert special apc before normal apcs (if any) but after the last special apc (fifo) */
|
/* Is this a Normal APC? If so, break */
|
||||||
InsertAscendingListFIFO(
|
if (QueuedApc->NormalRoutine) break;
|
||||||
&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
|
||||||
Apc,
|
|
||||||
KAPC,
|
|
||||||
ApcListEntry,
|
|
||||||
NormalRoutine /* sort field */
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
/* Move to the next APC in the Queue */
|
||||||
|
NextEntry = NextEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINT("Inserting Normal APC %x for '%.16s' into the %x Queue\n", Apc, ((PETHREAD)Thread)->ThreadsProcess->ImageFileName, Apc->ApcMode);
|
/* Move to the APC before this one (ie: the last Special APC) */
|
||||||
InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode],
|
NextEntry = NextEntry->Blink;
|
||||||
&Apc->ApcListEntry);
|
|
||||||
|
/* Insert us here */
|
||||||
|
InsertHeadList(NextEntry, &Apc->ApcListEntry);
|
||||||
|
DPRINT("Inserted Special APC for '%.16s' into the Queue\n",
|
||||||
|
((PETHREAD)Thread)->ThreadsProcess->ImageFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Confirm Insertion */
|
/* Now check if the Apc State Indexes match */
|
||||||
Apc->Inserted = TRUE;
|
if (Thread->ApcStateIndex == Apc->ApcStateIndex)
|
||||||
|
{
|
||||||
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
/* Check that if the thread matches */
|
||||||
|
if (Thread == KeGetCurrentThread())
|
||||||
/*
|
{
|
||||||
* Three possibilites here again:
|
/* Check if this is kernel mode */
|
||||||
* 1) Kernel APC, The thread is Running: Request an Interrupt
|
if (ApcMode == KernelMode)
|
||||||
* 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread
|
|
||||||
* 3) User APC, Unwait the Thread if it is alertable
|
|
||||||
*/
|
|
||||||
if (Apc->ApcMode == KernelMode) {
|
|
||||||
|
|
||||||
/* Set Kernel APC pending */
|
|
||||||
Thread->ApcState.KernelApcPending = TRUE;
|
|
||||||
|
|
||||||
/* Check the Thread State */
|
|
||||||
if (Thread->State == Running) {
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
PKPRCB Prcb, CurrentPrcb;
|
|
||||||
LONG i;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DPRINT ("Requesting APC Interrupt for Running Thread \n");
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
CurrentPrcb = KeGetCurrentPrcb();
|
|
||||||
if (CurrentPrcb->CurrentThread == Thread)
|
|
||||||
{
|
{
|
||||||
HalRequestSoftwareInterrupt(APC_LEVEL);
|
/* All valid, a Kernel APC is pending now */
|
||||||
|
Thread->ApcState.KernelApcPending = TRUE;
|
||||||
|
|
||||||
|
/* Check if Special APCs are disabled */
|
||||||
|
if (Thread->SpecialApcDisable == 0)
|
||||||
|
{
|
||||||
|
/* They're not, so request the interrupt */
|
||||||
|
HalRequestSoftwareInterrupt(APC_LEVEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check if this is a non-kernel mode APC */
|
||||||
|
if (ApcMode != KernelMode)
|
||||||
|
{
|
||||||
|
/* Not a Kernel-Mode APC. Are we waiting in user-mode? */
|
||||||
|
if ((Thread->State == Waiting) && (Thread->WaitMode == UserMode))
|
||||||
|
{
|
||||||
|
/* The thread is waiting. Are we alertable, or is an APC pending */
|
||||||
|
if ((Thread->Alertable) || (Thread->ApcState.UserApcPending))
|
||||||
|
{
|
||||||
|
/* Set user-mode APC pending */
|
||||||
|
Thread->ApcState.UserApcPending = TRUE;
|
||||||
|
Status = STATUS_USER_APC;
|
||||||
|
goto Unwait;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < KeNumberProcessors; i++)
|
/* Kernel-mode APC, set us pending */
|
||||||
{
|
Thread->ApcState.KernelApcPending = TRUE;
|
||||||
Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
|
|
||||||
if (Prcb->CurrentThread == Thread)
|
/* Are we currently running? */
|
||||||
{
|
if (Thread->State == Running)
|
||||||
ASSERT (CurrentPrcb != Prcb);
|
{
|
||||||
KiIpiSendRequest(Prcb->SetMember, IPI_APC);
|
/* The thread is running, so send an APC request */
|
||||||
break;
|
KiRequestApcInterrupt(Thread);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
ASSERT (i < KeNumberProcessors);
|
{
|
||||||
|
/*
|
||||||
|
* If the thread is Waiting at PASSIVE_LEVEL AND
|
||||||
|
* Special APCs are not disabled AND
|
||||||
|
* He is a Normal APC AND
|
||||||
|
* Kernel APCs are not disabled AND
|
||||||
|
* Kernel APC is not pending OR
|
||||||
|
* He is a Special APC THEN
|
||||||
|
* Unwait thread with STATUS_KERNEL_APC
|
||||||
|
*/
|
||||||
|
if ((Thread->State == Waiting) &&
|
||||||
|
(Thread->WaitIrql == PASSIVE_LEVEL) &&
|
||||||
|
(!Thread->SpecialApcDisable) &&
|
||||||
|
((!Apc->NormalRoutine) ||
|
||||||
|
((!Thread->KernelApcDisable) &&
|
||||||
|
(!Thread->ApcState.KernelApcInProgress))))
|
||||||
|
{
|
||||||
|
/* We'll unwait with this status */
|
||||||
|
Status = STATUS_KERNEL_APC;
|
||||||
|
|
||||||
|
/* Wake up the thread */
|
||||||
|
Unwait:
|
||||||
|
DPRINT("Waking up Thread for %lx Delivery \n", Status);
|
||||||
|
KiAbortWaitThread(Thread, Status, PriorityBoost);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* FIXME: Handle deferred ready sometime far far in the future */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
HalRequestSoftwareInterrupt(APC_LEVEL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else if ((Thread->State == Waiting) && (Thread->WaitIrql == PASSIVE_LEVEL) &&
|
|
||||||
((Apc->NormalRoutine == NULL) ||
|
|
||||||
((!Thread->KernelApcDisable) && (!Thread->ApcState.KernelApcInProgress)))) {
|
|
||||||
|
|
||||||
DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n");
|
|
||||||
KiAbortWaitThread(Thread, STATUS_KERNEL_APC, PriorityBoost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ((Thread->State == Waiting) &&
|
|
||||||
(Thread->WaitMode != KernelMode) &&
|
|
||||||
(Thread->Alertable)) {
|
|
||||||
|
|
||||||
DPRINT("Waking up Thread for User-Mode APC Delivery \n");
|
|
||||||
Thread->ApcState.UserApcPending = TRUE;
|
|
||||||
KiAbortWaitThread(Thread, STATUS_USER_APC, PriorityBoost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
/* Return to caller */
|
||||||
|
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
|
@ -399,11 +478,9 @@ KeInsertQueueApc(PKAPC Apc,
|
||||||
PVOID SystemArgument1,
|
PVOID SystemArgument1,
|
||||||
PVOID SystemArgument2,
|
PVOID SystemArgument2,
|
||||||
KPRIORITY PriorityBoost)
|
KPRIORITY PriorityBoost)
|
||||||
|
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
PKTHREAD Thread;
|
PKTHREAD Thread;
|
||||||
BOOLEAN Inserted;
|
|
||||||
|
|
||||||
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
||||||
DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
|
DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
|
||||||
|
@ -416,25 +493,25 @@ KeInsertQueueApc(PKAPC Apc,
|
||||||
/* Get the Thread specified in the APC */
|
/* Get the Thread specified in the APC */
|
||||||
Thread = Apc->Thread;
|
Thread = Apc->Thread;
|
||||||
|
|
||||||
/* Make sure the thread allows APC Queues.
|
/* Make sure we can Queue APCs and that this one isn't already inserted */
|
||||||
* The thread is not apc queueable, for instance, when it's (about to be) terminated.
|
if ((Thread->ApcQueueable == FALSE) && (Apc->Inserted == TRUE))
|
||||||
*/
|
{
|
||||||
if (Thread->ApcQueueable == FALSE) {
|
DPRINT("Can't queue the APC\n");
|
||||||
DPRINT("Thread doesn't allow APC Queues\n");
|
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the System Arguments */
|
/* Set the System Arguments and set it as inserted */
|
||||||
Apc->SystemArgument1 = SystemArgument1;
|
Apc->SystemArgument1 = SystemArgument1;
|
||||||
Apc->SystemArgument2 = SystemArgument2;
|
Apc->SystemArgument2 = SystemArgument2;
|
||||||
|
Apc->Inserted = TRUE;
|
||||||
|
|
||||||
/* Call the Internal Function */
|
/* Call the Internal Function */
|
||||||
Inserted = KiInsertQueueApc(Apc, PriorityBoost);
|
KiInsertQueueApc(Apc, PriorityBoost);
|
||||||
|
|
||||||
/* Return Sucess if we are here */
|
/* Return Sucess if we are here */
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
return Inserted;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
|
@ -464,23 +541,25 @@ KeFlushQueueApc(IN PKTHREAD Thread,
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
PKAPC Apc;
|
PKAPC Apc;
|
||||||
PLIST_ENTRY FirstEntry = NULL;
|
PLIST_ENTRY FirstEntry, CurrentEntry;
|
||||||
|
|
||||||
/* Lock the Dispatcher Database and APC Queue */
|
/* Lock the Dispatcher Database and APC Queue */
|
||||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
|
KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
|
||||||
|
|
||||||
/* mark all apcs as not-inserted */
|
if (IsListEmpty(&Thread->ApcState.ApcListHead[PreviousMode])) {
|
||||||
LIST_FOR_EACH(Apc, &Thread->ApcState.ApcListHead[PreviousMode], KAPC, ApcListEntry) {
|
FirstEntry = NULL;
|
||||||
Apc->Inserted = FALSE;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsListEmpty(&Thread->ApcState.ApcListHead[PreviousMode])) {
|
|
||||||
FirstEntry = Thread->ApcState.ApcListHead[PreviousMode].Flink;
|
FirstEntry = Thread->ApcState.ApcListHead[PreviousMode].Flink;
|
||||||
/* unlink list head from the rest of the list */
|
|
||||||
RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]);
|
RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]);
|
||||||
|
CurrentEntry = FirstEntry;
|
||||||
|
do {
|
||||||
|
Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);
|
||||||
|
Apc->Inserted = FALSE;
|
||||||
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
|
} while (CurrentEntry != FirstEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the locks */
|
/* Release the locks */
|
||||||
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
|
@ -516,46 +595,42 @@ KeRemoveQueueApc(PKAPC Apc)
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
PKTHREAD Thread = Apc->Thread;
|
PKTHREAD Thread = Apc->Thread;
|
||||||
|
PKAPC_STATE ApcState;
|
||||||
|
BOOLEAN Inserted;
|
||||||
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
|
||||||
DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
|
DPRINT("KeRemoveQueueApc called for APC: %x \n", Apc);
|
||||||
|
|
||||||
|
/* Acquire locks */
|
||||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
|
KeAcquireSpinLockAtDpcLevel(&Thread->ApcQueueLock);
|
||||||
|
|
||||||
/* Check if it's inserted */
|
/* Check if it's inserted */
|
||||||
if (Apc->Inserted) {
|
if ((Inserted = Apc->Inserted))
|
||||||
|
{
|
||||||
/* Remove it from the Queue*/
|
/* Remove it from the Queue*/
|
||||||
RemoveEntryList(&Apc->ApcListEntry);
|
|
||||||
Apc->Inserted = FALSE;
|
Apc->Inserted = FALSE;
|
||||||
|
ApcState = Thread->ApcStatePointer[(int)Apc->ApcStateIndex];
|
||||||
|
RemoveEntryList(&Apc->ApcListEntry);
|
||||||
|
|
||||||
/* If the Queue is completely empty, then no more APCs are pending */
|
/* If the Queue is completely empty, then no more APCs are pending */
|
||||||
if (IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode])) {
|
if (IsListEmpty(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode]))
|
||||||
|
{
|
||||||
/* Set the correct State based on the Apc Mode */
|
/* Set the correct State based on the Apc Mode */
|
||||||
if (Apc->ApcMode == KernelMode) {
|
if (Apc->ApcMode == KernelMode)
|
||||||
|
{
|
||||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->KernelApcPending = FALSE;
|
ApcState->KernelApcPending = FALSE;
|
||||||
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = FALSE;
|
ApcState->UserApcPending = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* It's not inserted, fail */
|
|
||||||
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
|
||||||
return(FALSE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore IRQL and Return */
|
/* Restore IRQL and Return */
|
||||||
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
KeReleaseSpinLockFromDpcLevel(&Thread->ApcQueueLock);
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
return(TRUE);
|
return Inserted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
|
@ -591,6 +666,8 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
PKTRAP_FRAME TrapFrame)
|
PKTRAP_FRAME TrapFrame)
|
||||||
{
|
{
|
||||||
PKTHREAD Thread = KeGetCurrentThread();
|
PKTHREAD Thread = KeGetCurrentThread();
|
||||||
|
PKPROCESS Process = KeGetCurrentProcess();
|
||||||
|
PKTRAP_FRAME OldTrapFrame;
|
||||||
PLIST_ENTRY ApcListEntry;
|
PLIST_ENTRY ApcListEntry;
|
||||||
PKAPC Apc;
|
PKAPC Apc;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
|
@ -599,17 +676,22 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
PKNORMAL_ROUTINE NormalRoutine;
|
PKNORMAL_ROUTINE NormalRoutine;
|
||||||
PVOID SystemArgument1;
|
PVOID SystemArgument1;
|
||||||
PVOID SystemArgument2;
|
PVOID SystemArgument2;
|
||||||
|
|
||||||
ASSERT_IRQL_EQUAL(APC_LEVEL);
|
ASSERT_IRQL_EQUAL(APC_LEVEL);
|
||||||
|
|
||||||
/* Lock the APC Queue and Raise IRQL to Synch */
|
/* Save the old trap frame */
|
||||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
OldTrapFrame = Thread->TrapFrame;
|
||||||
|
|
||||||
/* Clear APC Pending */
|
/* Clear Kernel APC Pending */
|
||||||
Thread->ApcState.KernelApcPending = FALSE;
|
Thread->ApcState.KernelApcPending = FALSE;
|
||||||
|
|
||||||
|
/* Check if Special APCs are disabled */
|
||||||
|
if (Thread->SpecialApcDisable != 0) goto Quickie;
|
||||||
|
|
||||||
/* Do the Kernel APCs first */
|
/* Do the Kernel APCs first */
|
||||||
while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) {
|
while (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]))
|
||||||
|
{
|
||||||
|
/* Lock the APC Queue and Raise IRQL to Synch */
|
||||||
|
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||||
|
|
||||||
/* Get the next Entry */
|
/* Get the next Entry */
|
||||||
ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
|
ApcListEntry = Thread->ApcState.ApcListHead[KernelMode].Flink;
|
||||||
|
@ -623,8 +705,8 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
SystemArgument2 = Apc->SystemArgument2;
|
SystemArgument2 = Apc->SystemArgument2;
|
||||||
|
|
||||||
/* Special APC */
|
/* Special APC */
|
||||||
if (NormalRoutine == NULL) {
|
if (!NormalRoutine)
|
||||||
|
{
|
||||||
/* Remove the APC from the list */
|
/* Remove the APC from the list */
|
||||||
RemoveEntryList(ApcListEntry);
|
RemoveEntryList(ApcListEntry);
|
||||||
Apc->Inserted = FALSE;
|
Apc->Inserted = FALSE;
|
||||||
|
@ -639,15 +721,13 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
&NormalContext,
|
&NormalContext,
|
||||||
&SystemArgument1,
|
&SystemArgument1,
|
||||||
&SystemArgument2);
|
&SystemArgument2);
|
||||||
|
}
|
||||||
/* Raise IRQL and Lock again */
|
else
|
||||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
{
|
||||||
|
/* Normal Kernel APC, make sur APCs aren't disabled or in progress*/
|
||||||
} else {
|
if ((Thread->ApcState.KernelApcInProgress) ||
|
||||||
|
(Thread->KernelApcDisable))
|
||||||
/* Normal Kernel APC */
|
{
|
||||||
if (Thread->ApcState.KernelApcInProgress || Thread->KernelApcDisable) {
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DeliveryMode must be KernelMode in this case, since one may not
|
* DeliveryMode must be KernelMode in this case, since one may not
|
||||||
* return to umode while being inside a critical section or while
|
* return to umode while being inside a critical section or while
|
||||||
|
@ -656,8 +736,9 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
*/
|
*/
|
||||||
ASSERT(DeliveryMode == KernelMode);
|
ASSERT(DeliveryMode == KernelMode);
|
||||||
|
|
||||||
|
/* Release lock and return */
|
||||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||||
return;
|
goto Quickie;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dequeue the APC */
|
/* Dequeue the APC */
|
||||||
|
@ -676,8 +757,8 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
&SystemArgument2);
|
&SystemArgument2);
|
||||||
|
|
||||||
/* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */
|
/* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */
|
||||||
if (NormalRoutine != NULL) {
|
if (NormalRoutine)
|
||||||
|
{
|
||||||
/* At Passive Level, this APC can be prempted by a Special APC */
|
/* At Passive Level, this APC can be prempted by a Special APC */
|
||||||
Thread->ApcState.KernelApcInProgress = TRUE;
|
Thread->ApcState.KernelApcInProgress = TRUE;
|
||||||
KeLowerIrql(PASSIVE_LEVEL);
|
KeLowerIrql(PASSIVE_LEVEL);
|
||||||
|
@ -688,21 +769,34 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Raise IRQL and Lock again */
|
/* Set Kernel APC in progress to false and loop again */
|
||||||
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
|
||||||
Thread->ApcState.KernelApcInProgress = FALSE;
|
Thread->ApcState.KernelApcInProgress = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we do the User APCs */
|
/* Now we do the User APCs */
|
||||||
if ((!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
|
if ((DeliveryMode == UserMode) &&
|
||||||
(DeliveryMode != KernelMode) && (Thread->ApcState.UserApcPending == TRUE)) {
|
(!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) &&
|
||||||
|
(Thread->ApcState.UserApcPending == TRUE))
|
||||||
|
{
|
||||||
|
/* Lock the APC Queue and Raise IRQL to Synch */
|
||||||
|
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
|
||||||
|
|
||||||
/* It's not pending anymore */
|
/* It's not pending anymore */
|
||||||
Thread->ApcState.UserApcPending = FALSE;
|
Thread->ApcState.UserApcPending = FALSE;
|
||||||
|
|
||||||
/* Get the APC Object */
|
/* Get the APC Entry */
|
||||||
ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
|
ApcListEntry = Thread->ApcState.ApcListHead[UserMode].Flink;
|
||||||
|
|
||||||
|
/* Is it empty now? */
|
||||||
|
if (!ApcListEntry)
|
||||||
|
{
|
||||||
|
/* Release the lock and return */
|
||||||
|
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
||||||
|
goto Quickie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the actual APC object */
|
||||||
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
|
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
|
||||||
|
|
||||||
/* Save Parameters so that it's safe to free the Object in Kernel Routine*/
|
/* Save Parameters so that it's safe to free the Object in Kernel Routine*/
|
||||||
|
@ -724,13 +818,13 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
&SystemArgument1,
|
&SystemArgument1,
|
||||||
&SystemArgument2);
|
&SystemArgument2);
|
||||||
|
|
||||||
if (NormalRoutine == NULL) {
|
if (!NormalRoutine)
|
||||||
|
{
|
||||||
/* Check if more User APCs are Pending */
|
/* Check if more User APCs are Pending */
|
||||||
KeTestAlertThread(UserMode);
|
KeTestAlertThread(UserMode);
|
||||||
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
/* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
|
/* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
|
||||||
DPRINT("Delivering a User APC: %x\n", Apc);
|
DPRINT("Delivering a User APC: %x\n", Apc);
|
||||||
KiInitializeUserApc(Reserved,
|
KiInitializeUserApc(Reserved,
|
||||||
|
@ -740,12 +834,23 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
|
||||||
SystemArgument1,
|
SystemArgument1,
|
||||||
SystemArgument2);
|
SystemArgument2);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* Go back to APC_LEVEL */
|
|
||||||
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Quickie:
|
||||||
|
/* Make sure we're still in the same process */
|
||||||
|
if (Process != Thread->ApcState.Process)
|
||||||
|
{
|
||||||
|
/* Erm, we got attached or something! BAD! */
|
||||||
|
KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT,
|
||||||
|
(ULONG_PTR)Process,
|
||||||
|
(ULONG_PTR)Thread->ApcState.Process,
|
||||||
|
Thread->ApcStateIndex,
|
||||||
|
KeGetCurrentPrcb()->DpcRoutineActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the trap frame */
|
||||||
|
Thread->TrapFrame = OldTrapFrame;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
@ -865,7 +970,7 @@ STDCALL
|
||||||
KeAreApcsDisabled(VOID)
|
KeAreApcsDisabled(VOID)
|
||||||
{
|
{
|
||||||
/* Return the Kernel APC State */
|
/* Return the Kernel APC State */
|
||||||
return KeGetCurrentThread()->KernelApcDisable ? TRUE : FALSE;
|
return KeGetCurrentThread()->CombinedApcDisable ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
|
|
|
@ -527,8 +527,8 @@ KeResumeThread(PKTHREAD Thread)
|
||||||
return PreviousCount;
|
return PreviousCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN
|
VOID
|
||||||
STDCALL
|
FASTCALL
|
||||||
KiInsertQueueApc(PKAPC Apc,
|
KiInsertQueueApc(PKAPC Apc,
|
||||||
KPRIORITY PriorityBoost);
|
KPRIORITY PriorityBoost);
|
||||||
|
|
||||||
|
@ -547,20 +547,42 @@ KeFreezeAllThreads(PKPROCESS Process)
|
||||||
/* Acquire Lock */
|
/* Acquire Lock */
|
||||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
|
|
||||||
|
/* If someone is already trying to free us, try again */
|
||||||
|
while (CurrentThread->FreezeCount)
|
||||||
|
{
|
||||||
|
/* Release and re-acquire the lock so the APC will go through */
|
||||||
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enter a critical region */
|
||||||
|
KeEnterCriticalRegion();
|
||||||
|
|
||||||
/* Loop the Process's Threads */
|
/* Loop the Process's Threads */
|
||||||
LIST_FOR_EACH(Current, &Process->ThreadListHead, KTHREAD, ThreadListEntry)
|
LIST_FOR_EACH(Current, &Process->ThreadListHead, KTHREAD, ThreadListEntry)
|
||||||
{
|
{
|
||||||
/* Make sure it's not ours */
|
/* Make sure it's not ours */
|
||||||
if (Current == CurrentThread) continue;
|
if (Current != CurrentThread)
|
||||||
|
|
||||||
/* Make sure it wasn't already frozen, and that it's not suspended */
|
|
||||||
if (!(++Current->FreezeCount) && !(Current->SuspendCount))
|
|
||||||
{
|
{
|
||||||
/* Insert the APC */
|
/* Should be bother inserting the APC? */
|
||||||
if (!KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT))
|
if (Current->ApcQueueable)
|
||||||
{
|
{
|
||||||
/* Unsignal the Semaphore, the APC already got inserted */
|
/* Make sure it wasn't already frozen, and that it's not suspended */
|
||||||
Current->SuspendSemaphore.Header.SignalState--;
|
if (!(++Current->FreezeCount) && !(Current->SuspendCount))
|
||||||
|
{
|
||||||
|
/* Did we already insert it? */
|
||||||
|
if (!Current->SuspendApc.Inserted)
|
||||||
|
{
|
||||||
|
/* Insert the APC */
|
||||||
|
Current->SuspendApc.Inserted = TRUE;
|
||||||
|
KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Unsignal the Semaphore, the APC already got inserted */
|
||||||
|
Current->SuspendSemaphore.Header.SignalState--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,20 +611,30 @@ KeSuspendThread(PKTHREAD Thread)
|
||||||
{
|
{
|
||||||
/* Raise an exception */
|
/* Raise an exception */
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
|
RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Increment it */
|
/* Should we bother to queue at all? */
|
||||||
Thread->SuspendCount++;
|
if (Thread->ApcQueueable)
|
||||||
|
{
|
||||||
|
/* Increment the suspend count */
|
||||||
|
Thread->SuspendCount++;
|
||||||
|
|
||||||
/* Check if we should suspend it */
|
/* Check if we should suspend it */
|
||||||
if (!PreviousCount && !Thread->FreezeCount) {
|
if (!PreviousCount && !Thread->FreezeCount)
|
||||||
|
{
|
||||||
/* Insert the APC */
|
/* Is the APC already inserted? */
|
||||||
if (!KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT)) {
|
if (!Thread->SuspendApc.Inserted)
|
||||||
|
{
|
||||||
/* Unsignal the Semaphore, the APC already got inserted */
|
/* Not inserted, insert it */
|
||||||
Thread->SuspendSemaphore.Header.SignalState--;
|
Thread->SuspendApc.Inserted = TRUE;
|
||||||
|
KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Unsignal the Semaphore, the APC already got inserted */
|
||||||
|
Thread->SuspendSemaphore.Header.SignalState--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue