- Fix definition of SYNCH_LEVEL.

- Implement KeAcquireInStackQueuedSpinLockRaiseToSynch for UP systems.
- Implement KiAcquireApcLock, KiAcquireApcLockAtDpcLevel, KiReleaseApcLock, KiReleaseApcLockFromDpcLevel.
- KeResumeThread, KeSuspendThread, KeAlertThread, KeForceResumeThread, KeTestAlertThread, KeAlertResumeThread are now the first to use the new APC In-Stack Queued Spinlock for sychronization.

svn path=/trunk/; revision=24028
This commit is contained in:
Alex Ionescu 2006-09-10 16:09:58 +00:00
parent bd33d79025
commit e61739c38c
9 changed files with 276 additions and 159 deletions

View file

@ -784,6 +784,15 @@ KeAcquireInStackQueuedSpinLock(
UNIMPLEMENTED; UNIMPLEMENTED;
} }
VOID
FASTCALL
KeAcquireInStackQueuedSpinLockRaiseToSynch(
IN PKSPIN_LOCK SpinLock,
IN PKLOCK_QUEUE_HANDLE LockHandle
)
{
UNIMPLEMENTED;
}
VOID VOID
FASTCALL FASTCALL

View file

@ -71,6 +71,7 @@ KdPortDisableInterrupts@0
KdPortEnableInterrupts@0 KdPortEnableInterrupts@0
KeAcquireSpinLock@8 KeAcquireSpinLock@8
@KeAcquireInStackQueuedSpinLock@8 @KeAcquireInStackQueuedSpinLock@8
@KeAcquireInStackQueuedSpinLockRaiseToSynch@8
@KeAcquireSpinLockRaiseToSynch@4 @KeAcquireSpinLockRaiseToSynch@4
@KeAcquireQueuedSpinLock@4 @KeAcquireQueuedSpinLock@4
KeGetCurrentIrql@0 KeGetCurrentIrql@0

View file

@ -134,6 +134,18 @@ KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock,
LockHandle->OldIrql = KfRaiseIrql(DISPATCH_LEVEL); LockHandle->OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
} }
/*
* @implemented
*/
VOID
FASTCALL
KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock,
IN PKLOCK_QUEUE_HANDLE LockHandle)
{
/* Simply raise to synch */
LockHandle->OldIrql = KfRaiseIrql(SYNCH_LEVEL);
}
/* /*
* @implemented * @implemented
*/ */

View file

@ -117,6 +117,19 @@ KeAcquireInStackQueuedSpinLock(
UNIMPLEMENTED; UNIMPLEMENTED;
} }
/*
* @unimplemented
*/
VOID
FASTCALL
KeAcquireInStackQueuedSpinLockRaiseToSynch(
IN PKSPIN_LOCK SpinLock,
IN PKLOCK_QUEUE_HANDLE LockHandle
)
{
UNIMPLEMENTED;
}
/* /*
* @unimplemented * @unimplemented

View file

@ -109,7 +109,7 @@ Author:
// //
// Synchronization-level IRQL // Synchronization-level IRQL
// //
#if defined(NT_UP) #ifndef CONFIG_SMP
#define SYNCH_LEVEL DISPATCH_LEVEL #define SYNCH_LEVEL DISPATCH_LEVEL
#else #else
#define SYNCH_LEVEL (IPI_LEVEL - 1) #define SYNCH_LEVEL (IPI_LEVEL - 1)

View file

@ -117,7 +117,7 @@ KeAcquireQueuedSpinLockRaiseToSynch(
IN KSPIN_LOCK_QUEUE_NUMBER LockNumber IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
); );
KIRQL VOID
FASTCALL FASTCALL
KeAcquireInStackQueuedSpinLockRaiseToSynch( KeAcquireInStackQueuedSpinLockRaiseToSynch(
IN PKSPIN_LOCK SpinLock, IN PKSPIN_LOCK SpinLock,

View file

@ -896,7 +896,7 @@ typedef struct _KTHREAD
#include <poppack.h> #include <poppack.h>
#define ASSERT_THREAD(object) \ #define ASSERT_THREAD(object) \
ASSERT((((object)->Header.Type & KOBJECT_TYPE_MASK) == ThreadObject)) ASSERT((((object)->DispatcherHeader.Type & KOBJECT_TYPE_MASK) == ThreadObject))
// //
// Kernel Process (KPROCESS) // Kernel Process (KPROCESS)

View file

@ -553,6 +553,40 @@ KiCheckDeferredReadyList(IN PKPRCB Prcb)
#endif #endif
FORCEINLINE
VOID
KiAcquireApcLock(IN PKTHREAD Thread,
IN PKLOCK_QUEUE_HANDLE Handle)
{
/* Acquire the lock and raise to synchronization level */
KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, Handle);
}
FORCEINLINE
VOID
KiAcquireApcLockAtDpcLevel(IN PKTHREAD Thread,
IN PKLOCK_QUEUE_HANDLE Handle)
{
/* Acquire the lock */
KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread->ApcQueueLock, Handle);
}
FORCEINLINE
VOID
KiReleaseApcLock(IN PKLOCK_QUEUE_HANDLE Handle)
{
/* Release the lock */
KeReleaseInStackQueuedSpinLock(Handle);
}
FORCEINLINE
VOID
KiReleaseApcLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE Handle)
{
/* Release the lock */
KeReleaseInStackQueuedSpinLockFromDpcLevel(Handle);
}
// //
// This routine queues a thread that is ready on the PRCB's ready lists. // This routine queues a thread that is ready on the PRCB's ready lists.
// If this thread cannot currently run on this CPU, then the thread is // If this thread cannot currently run on this CPU, then the thread is

View file

@ -46,33 +46,6 @@ KeFindNextRightSetAffinity(IN UCHAR Number,
return (UCHAR)Result; return (UCHAR)Result;
} }
VOID
STDCALL
KiSuspendThreadKernelRoutine(PKAPC Apc,
PKNORMAL_ROUTINE* NormalRoutine,
PVOID* NormalContext,
PVOID* SystemArgument1,
PVOID* SystemArguemnt2)
{
}
VOID
STDCALL
KiSuspendThreadNormalRoutine(PVOID NormalContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PKTHREAD CurrentThread = KeGetCurrentThread();
/* Non-alertable kernel-mode suspended wait */
DPRINT("Waiting...\n");
KeWaitForSingleObject(&CurrentThread->SuspendSemaphore,
Suspended,
KernelMode,
FALSE,
NULL);
DPRINT("Done Waiting\n");
}
#ifdef KeGetCurrentThread #ifdef KeGetCurrentThread
#undef KeGetCurrentThread #undef KeGetCurrentThread
@ -202,41 +175,6 @@ KeRundownThread(VOID)
KeReleaseDispatcherDatabaseLock(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
} }
ULONG
NTAPI
KeResumeThread(IN PKTHREAD Thread)
{
ULONG PreviousCount;
KIRQL OldIrql;
DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread,
Thread->SuspendCount, Thread->FreezeCount);
/* Lock the Dispatcher */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save the Old Count */
PreviousCount = Thread->SuspendCount;
/* Check if it existed */
if (PreviousCount) {
Thread->SuspendCount--;
/* Decrease the current Suspend Count and Check Freeze Count */
if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) {
/* Signal the Suspend Semaphore */
Thread->SuspendSemaphore.Header.SignalState++;
KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
}
}
/* Release Lock and return the Old State */
KeReleaseDispatcherDatabaseLock(OldIrql);
return PreviousCount;
}
/* /*
* Used by the debugging code to freeze all the process's threads * Used by the debugging code to freeze all the process's threads
* while the debugger is examining their state. * while the debugger is examining their state.
@ -296,17 +234,99 @@ KeFreezeAllThreads(PKPROCESS Process)
KeReleaseDispatcherDatabaseLock(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);
} }
ULONG
NTAPI
KeResumeThread(IN PKTHREAD Thread)
{
KLOCK_QUEUE_HANDLE ApcLock;
ULONG PreviousCount;
ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
DPRINT1("Resuming Thread: %p\n", Thread);
/* Lock the APC Queue */
KiAcquireApcLock(Thread, &ApcLock);
/* Save the Old Count */
PreviousCount = Thread->SuspendCount;
/* Check if it existed */
if (PreviousCount)
{
/* Decrease the suspend count */
Thread->SuspendCount--;
/* Check if the thrad is still suspended or not */
if ((!Thread->SuspendCount) && (!Thread->FreezeCount))
{
/* Acquire the dispatcher lock */
KiAcquireDispatcherLockAtDpcLevel();
/* Signal the Suspend Semaphore */
Thread->SuspendSemaphore.Header.SignalState++;
KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
/* Release the dispatcher lock */
KiReleaseDispatcherLockFromDpcLevel();
}
}
/* Release APC Queue lock and return the Old State */
KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return PreviousCount;
}
VOID
NTAPI
KiSuspendRundown(IN PKAPC Apc)
{
/* Does nothing */
UNREFERENCED_PARAMETER(Apc);
}
VOID
NTAPI
KiSuspendNop(IN PKAPC Apc,
IN PKNORMAL_ROUTINE *NormalRoutine,
IN PVOID *NormalContext,
IN PVOID *SystemArgument1,
IN PVOID *SystemArgument2)
{
/* Does nothing */
UNREFERENCED_PARAMETER(Apc);
UNREFERENCED_PARAMETER(NormalRoutine);
UNREFERENCED_PARAMETER(NormalContext);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
}
VOID
NTAPI
KiSuspendThread(IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
/* Non-alertable kernel-mode suspended wait */
KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore,
Suspended,
KernelMode,
FALSE,
NULL);
}
NTSTATUS NTSTATUS
STDCALL NTAPI
KeSuspendThread(PKTHREAD Thread) KeSuspendThread(PKTHREAD Thread)
{ {
KLOCK_QUEUE_HANDLE ApcLock;
ULONG PreviousCount; ULONG PreviousCount;
KIRQL OldIrql; ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
DPRINT1("Suspending Thread: %p\n", Thread);
DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread, Thread->SuspendCount, Thread->FreezeCount); /* Lock the APC Queue */
KiAcquireApcLock(Thread, &ApcLock);
/* Lock the Dispatcher */
OldIrql = KeAcquireDispatcherDatabaseLock();
/* Save the Old Count */ /* Save the Old Count */
PreviousCount = Thread->SuspendCount; PreviousCount = Thread->SuspendCount;
@ -315,7 +335,7 @@ KeSuspendThread(PKTHREAD Thread)
if (PreviousCount == MAXIMUM_SUSPEND_COUNT) if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
{ {
/* Raise an exception */ /* Raise an exception */
KeReleaseDispatcherDatabaseLock(OldIrql); KiReleaseApcLock(&ApcLock);
RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED); RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
} }
@ -326,7 +346,7 @@ KeSuspendThread(PKTHREAD Thread)
Thread->SuspendCount++; Thread->SuspendCount++;
/* Check if we should suspend it */ /* Check if we should suspend it */
if (!PreviousCount && !Thread->FreezeCount) if (!(PreviousCount) && !(Thread->FreezeCount))
{ {
/* Is the APC already inserted? */ /* Is the APC already inserted? */
if (!Thread->SuspendApc.Inserted) if (!Thread->SuspendApc.Inserted)
@ -337,44 +357,61 @@ KeSuspendThread(PKTHREAD Thread)
} }
else else
{ {
/* Unsignal the Semaphore, the APC already got inserted */ /* Lock the dispatcher */
KiAcquireDispatcherLockAtDpcLevel();
/* Unsignal the semaphore, the APC was already inserted */
Thread->SuspendSemaphore.Header.SignalState--; Thread->SuspendSemaphore.Header.SignalState--;
/* Release the dispatcher */
KiReleaseDispatcherLockFromDpcLevel();
} }
} }
} }
/* Release Lock and return the Old State */ /* Release Lock and return the Old State */
KeReleaseDispatcherDatabaseLock(OldIrql); KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return PreviousCount; return PreviousCount;
} }
ULONG ULONG
STDCALL NTAPI
KeForceResumeThread(IN PKTHREAD Thread) KeForceResumeThread(IN PKTHREAD Thread)
{ {
KIRQL OldIrql; KLOCK_QUEUE_HANDLE ApcLock;
ULONG PreviousCount; ULONG PreviousCount;
ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
DPRINT1("Force-Resuming Thread: %p\n", Thread);
/* Lock the Dispatcher Database and the APC Queue */ /* Lock the APC Queue */
OldIrql = KeAcquireDispatcherDatabaseLock(); KiAcquireApcLock(Thread, &ApcLock);
/* Save the old Suspend Count */ /* Save the old Suspend Count */
PreviousCount = Thread->SuspendCount + Thread->FreezeCount; PreviousCount = Thread->SuspendCount + Thread->FreezeCount;
/* If the thread is suspended, wake it up!!! */ /* If the thread is suspended, wake it up!!! */
if (PreviousCount) { if (PreviousCount)
{
/* Unwait it completely */ /* Unwait it completely */
Thread->SuspendCount = 0; Thread->SuspendCount = 0;
Thread->FreezeCount = 0; Thread->FreezeCount = 0;
/* Lock the dispatcher */
KiAcquireDispatcherLockAtDpcLevel();
/* Signal and satisfy */ /* Signal and satisfy */
Thread->SuspendSemaphore.Header.SignalState++; Thread->SuspendSemaphore.Header.SignalState++;
KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
/* Release the dispatcher */
KiReleaseDispatcherLockFromDpcLevel();
} }
/* Release Lock and return the Old State */ /* Release Lock and return the Old State */
KeReleaseDispatcherDatabaseLock(OldIrql); KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return PreviousCount; return PreviousCount;
} }
@ -383,25 +420,26 @@ NTAPI
KeAlertResumeThread(IN PKTHREAD Thread) KeAlertResumeThread(IN PKTHREAD Thread)
{ {
ULONG PreviousCount; ULONG PreviousCount;
KIRQL OldIrql; KLOCK_QUEUE_HANDLE ApcLock;
ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
DPRINT1("Alert-Resuming Thread: %p\n", Thread);
/* Lock the Dispatcher Database and the APC Queue */ /* Lock the Dispatcher Database and the APC Queue */
OldIrql = KeAcquireDispatcherDatabaseLock(); KiAcquireApcLock(Thread, &ApcLock);
KiAcquireSpinLock(&Thread->ApcQueueLock); KiAcquireDispatcherLockAtDpcLevel();
/* Return if Thread is already alerted. */ /* Return if Thread is already alerted. */
if (Thread->Alerted[KernelMode] == FALSE) { if (!Thread->Alerted[KernelMode])
{
/* If it's Blocked, unblock if it we should */ /* If it's Blocked, unblock if it we should */
if (Thread->State == Waiting && Thread->Alertable) { if ((Thread->State == Waiting) && (Thread->Alertable))
{
DPRINT("Aborting Wait\n"); /* Abort the wait */
KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
}
} else { else
{
/* If not, simply Alert it */ /* If not, simply Alert it */
Thread->Alerted[KernelMode] = TRUE; Thread->Alerted[KernelMode] = TRUE;
} }
@ -411,11 +449,11 @@ KeAlertResumeThread(IN PKTHREAD Thread)
PreviousCount = Thread->SuspendCount; PreviousCount = Thread->SuspendCount;
/* If the thread is suspended, decrease one of the suspend counts */ /* If the thread is suspended, decrease one of the suspend counts */
if (PreviousCount) { if (PreviousCount)
{
/* Decrease count. If we are now zero, unwait it completely */ /* Decrease count. If we are now zero, unwait it completely */
if (--Thread->SuspendCount) { if (--Thread->SuspendCount)
{
/* Signal and satisfy */ /* Signal and satisfy */
Thread->SuspendSemaphore.Header.SignalState++; Thread->SuspendSemaphore.Header.SignalState++;
KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
@ -423,8 +461,9 @@ KeAlertResumeThread(IN PKTHREAD Thread)
} }
/* Release Locks and return the Old State */ /* Release Locks and return the Old State */
KiReleaseSpinLock(&Thread->ApcQueueLock); KiReleaseDispatcherLockFromDpcLevel();
KeReleaseDispatcherDatabaseLock(OldIrql); KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return PreviousCount; return PreviousCount;
} }
@ -433,40 +472,88 @@ NTAPI
KeAlertThread(IN PKTHREAD Thread, KeAlertThread(IN PKTHREAD Thread,
IN KPROCESSOR_MODE AlertMode) IN KPROCESSOR_MODE AlertMode)
{ {
KIRQL OldIrql;
BOOLEAN PreviousState; BOOLEAN PreviousState;
KLOCK_QUEUE_HANDLE ApcLock;
ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
DPRINT1("Alerting Thread: %p\n", Thread);
/* Acquire the Dispatcher Database Lock */ /* Lock the Dispatcher Database and the APC Queue */
OldIrql = KeAcquireDispatcherDatabaseLock(); KiAcquireApcLock(Thread, &ApcLock);
KiAcquireDispatcherLockAtDpcLevel();
/* Save the Previous State */ /* Save the Previous State */
PreviousState = Thread->Alerted[AlertMode]; PreviousState = Thread->Alerted[AlertMode];
/* Return if Thread is already alerted. */ /* Check if it's already alerted */
if (PreviousState == FALSE) { if (!PreviousState)
{
/* If it's Blocked, unblock if it we should */ /* Check if the thread is alertable, and blocked in the given mode */
if (Thread->State == Waiting && if ((Thread->State == Waiting) &&
(AlertMode == KernelMode || Thread->WaitMode == AlertMode) && ((AlertMode == KernelMode) || (Thread->WaitMode == AlertMode)) &&
Thread->Alertable) { (Thread->Alertable))
{
DPRINT("Aborting Wait\n"); /* Abort the wait to alert the thread */
KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); KiAbortWaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT);
}
} else { else
{
/* If not, simply Alert it */ /* Otherwise, merely set the alerted state */
Thread->Alerted[AlertMode] = TRUE; Thread->Alerted[AlertMode] = TRUE;
} }
} }
/* Release the Dispatcher Lock */ /* Release the Dispatcher Lock */
KeReleaseDispatcherDatabaseLock(OldIrql); KiReleaseDispatcherLockFromDpcLevel();
KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
/* Return the old state */ /* Return the old state */
return PreviousState; return PreviousState;
} }
/*
* FUNCTION: Tests whether there are any pending APCs for the current thread
* and if so the APCs will be delivered on exit from kernel mode
*/
BOOLEAN
STDCALL
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
{
PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN OldState;
KLOCK_QUEUE_HANDLE ApcLock;
ASSERT_THREAD(Thread);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
DPRINT1("Test-Alerting Thread: %p\n", Thread);
/* Lock the Dispatcher Database and the APC Queue */
KiAcquireApcLock(Thread, &ApcLock);
KiAcquireDispatcherLockAtDpcLevel();
/* Save the old State */
OldState = Thread->Alerted[AlertMode];
/* Check the Thread is alerted */
if (OldState)
{
/* Disable alert for this mode */
Thread->Alerted[AlertMode] = FALSE;
}
else if ((AlertMode != KernelMode) &&
(!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
{
/* If the mode is User and the Queue isn't empty, set Pending */
Thread->ApcState.UserApcPending = TRUE;
}
/* Release Locks and return the Old State */
KiReleaseDispatcherLockFromDpcLevel();
KiReleaseApcLockFromDpcLevel(&ApcLock);
KiExitDispatcher(ApcLock.OldIrql);
return OldState;
}
/* /*
* @unimplemented * @unimplemented
*/ */
@ -551,9 +638,9 @@ KeInitThread(IN OUT PKTHREAD Thread,
KeInitializeApc(&Thread->SuspendApc, KeInitializeApc(&Thread->SuspendApc,
Thread, Thread,
OriginalApcEnvironment, OriginalApcEnvironment,
KiSuspendThreadKernelRoutine, KiSuspendNop,
NULL, KiSuspendRundown,
KiSuspendThreadNormalRoutine, KiSuspendThread,
KernelMode, KernelMode,
NULL); NULL);
@ -1157,42 +1244,3 @@ KeTerminateThread(IN KPRIORITY Increment)
/* Find a new Thread */ /* Find a new Thread */
KiDispatchThreadNoLock(Terminated); KiDispatchThreadNoLock(Terminated);
} }
/*
* FUNCTION: Tests whether there are any pending APCs for the current thread
* and if so the APCs will be delivered on exit from kernel mode
*/
BOOLEAN
STDCALL
KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
{
KIRQL OldIrql;
PKTHREAD Thread = KeGetCurrentThread();
BOOLEAN OldState;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Lock the Dispatcher Database and the APC Queue */
OldIrql = KeAcquireDispatcherDatabaseLock();
KiAcquireSpinLock(&Thread->ApcQueueLock);
/* Save the old State */
OldState = Thread->Alerted[AlertMode];
/* If the Thread is Alerted, Clear it */
if (OldState) {
Thread->Alerted[AlertMode] = FALSE;
} else if ((AlertMode != KernelMode) && (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) {
/* If the mode is User and the Queue isn't empty, set Pending */
Thread->ApcState.UserApcPending = TRUE;
}
/* Release Locks and return the Old State */
KiReleaseSpinLock(&Thread->ApcQueueLock);
KeReleaseDispatcherDatabaseLock(OldIrql);
return OldState;
}