VOID
KeFreezeAllThreads (
VOID
)
/*++
Routine Description:
This function suspends the execution of all thread in the current
process except the current thread. If the freeze count overflows
the maximum suspend count, then a condition is raised.
Arguments:
None.
Return Value:
None.
--*/
{
PKTHREAD CurrentThread;
PLIST_ENTRY ListHead;
PLIST_ENTRY NextEntry;
PKPROCESS Process;
KLOCK_QUEUE_HANDLE ProcessHandle;
PKTHREAD Thread;
KLOCK_QUEUE_HANDLE ThreadHandle;
ULONG OldCount;
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
//
// Set the address of the current thread object and the current process
// object.
//
CurrentThread = KeGetCurrentThread();
Process = CurrentThread->ApcState.Process;
//
// Raise IRQL to SYNCH_LEVEL and acquire the process lock.
//
KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock,
&ProcessHandle);
//
// If the freeze count of the current thread is not zero, then there
// is another thread that is trying to freeze this thread. Unlock the
// the process lock and lower IRQL to its previous value, allow the
// suspend APC to occur, then raise IRQL to SYNCH_LEVEL and lock the
// process lock.
//
while (CurrentThread->FreezeCount != 0) {
KeReleaseInStackQueuedSpinLock(&ProcessHandle);
KeAcquireInStackQueuedSpinLockRaiseToSynch(&Process->ProcessLock,
&ProcessHandle);
}
KeEnterCriticalRegion();
//
// Freeze all threads except the current thread.
//
ListHead = &Process->ThreadListHead;
NextEntry = ListHead->Flink;
do {
//
// Get the address of the next thread.
//
Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
//
// Acquire the thread APC queue lock.
//
KeAcquireInStackQueuedSpinLockAtDpcLevel(&Thread->ApcQueueLock,
&ThreadHandle);
//
// If the thread is not the current thread and APCs are queueable,
// then attempt to suspend the thread.
//
if ((Thread != CurrentThread) && (Thread->ApcQueueable == TRUE)) {
//
// Increment the freeze count. If the thread was not previously
// suspended, then queue the thread's suspend APC.
//
// N.B. The APC MUST be queued using the internal interface so
// the system argument fields of the APC do not get written.
//
OldCount = Thread->FreezeCount;
ASSERT(OldCount != MAXIMUM_SUSPEND_COUNT);
Thread->FreezeCount += 1;
if ((OldCount == 0) && (Thread->SuspendCount == 0)) {
if (Thread->SuspendApc.Inserted == TRUE) {
KiLockDispatcherDatabaseAtSynchLevel();
Thread->SuspendSemaphore.Header.SignalState -= 1;
KiUnlockDispatcherDatabaseFromSynchLevel();
} else {
Thread->SuspendApc.Inserted = TRUE;
KiInsertQueueApc(&Thread->SuspendApc, RESUME_INCREMENT);
}
}
}
//
// Release the thread APC queue lock.
//
KeReleaseInStackQueuedSpinLockFromDpcLevel(&ThreadHandle);
NextEntry = NextEntry->Flink;
} while (NextEntry != ListHead);
//
// Release the process lock and exit the scheduler.
//
KeReleaseInStackQueuedSpinLockFromDpcLevel(&ProcessHandle);
KiExitDispatcher(ProcessHandle.OldIrql);
return;
}