02179 //
02180 // Don't suspend the thread if APC queuing is disabled. In this case the
02181 // thread is being deleted.
02182 //
02183
02184 if (Thread->ApcQueueable == TRUE) {
02185
02186 //
02187 // Increment the suspend count. If the thread was not previously
02188 // suspended, then queue the thread's suspend APC.
02189 //
02190 // N.B. The APC MUST be queued using the internal interface so
02191 // the system argument fields of the APC do not get written.
02192 //
02193
02194 Thread->SuspendCount += 1;
02195 if ((OldCount == 0) && (Thread->FreezeCount == 0)) {
02196 if (Thread->SuspendApc.Inserted == TRUE) {
02197 KiLockDispatcherDatabaseAtSynchLevel();
02198 Thread->SuspendSemaphore.Header.SignalState -= 1;
02199 KiUnlockDispatcherDatabaseFromSynchLevel();
02200
02201 } else {
02202 Thread->SuspendApc.Inserted = TRUE;
02203 KiInsertQueueApc(&Thread->SuspendApc, RESUME_INCREMENT);
02204 }
02205 }
02206 }
00489 // If the APC index from the APC object matches the APC Index of
00490 // the thread, then check to determine if the APC should interrupt
00491 // thread execution or sequence the thread out of a wait state.
00492 //
00493
00494 if (Apc->ApcStateIndex == Thread->ApcStateIndex) {
什么是“APC state index”(APC状态索引),它的值到底是多少?我并不真的知道;对于APC,它应该是OriginalApcEnvironment。这也应该是目标线程的ApcStateIndex的值(所以这种情况通常是对的),但我并没有搞懂APC环境的概念(也找不到任何能说得过去的解释)。
任何情况,假定条件为True,它就会去检测我们是否给当前线程安排了APC,如果有这个APC,它就立即执行一个APC_LEVEL软中断。否则(比如给别的线程安排APC),我们就锁定调度数据库,从RequestInterrupt=FALSE开始,执行下面的这一段复杂的代码:
00531 if (ApcMode == KernelMode) {
00532
00533 //
00534 // Thread transitions from the standby state to the running
00535 // state can occur from the idle thread without holding the
00536 // dispatcher lock. Reading the thread state after setting
00537 // the kernel APC pending flag prevents the code from not
00538 // delivering the APC interrupt in this case.
00539 //
00540 // N.B. Transitions from gate wait to running are synchronized
00541 // using the thread lock. Transitions from running to gate
00542 // wait are synchronized using the APC queue lock.
00543 //
00544 // N.B. If the target thread is found to be in the running state,
00545 // then the APC interrupt request can be safely deferred to
00546 // after the dispatcher lock is released even if the thread
00547 // were to be switched to another processor, i.e., the APC
00548 // would be delivered by the context switch code.
00549 //
00550
00551 Thread->ApcState.KernelApcPending = TRUE;
00552 KeMemoryBarrier();
00553 ThreadState = Thread->State;
00554 if (ThreadState == Running) {
00555 RequestInterrupt = TRUE;
00556
00557 } else if ((ThreadState == Waiting) &&
00558 (Thread->WaitIrql == 0) &&
00559 (Thread->SpecialApcDisable == 0) &&
00560 ((Apc->NormalRoutine == NULL) ||
00561 ((Thread->KernelApcDisable == 0) &&
00562 (Thread->ApcState.KernelApcInProgress == FALSE)))) {
00563
00564 KiUnwaitThread(Thread, STATUS_KERNEL_APC, Increment);
00565
00566 } else if (Thread->State == GateWait) {
00567 KiAcquireThreadLock(Thread);
00568 if ((Thread->State == GateWait) &&
00569 (Thread->WaitIrql == 0) &&
00570 (Thread->SpecialApcDisable == 0) &&
00571 ((Apc->NormalRoutine == NULL) ||
00572 ((Thread->KernelApcDisable == 0) &&
00573 (Thread->ApcState.KernelApcInProgress == FALSE)))) {
00574
00575 GateObject = Thread->GateObject;
00576 KiAcquireKobjectLock(GateObject);
00577 RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry);
00578 KiReleaseKobjectLock(GateObject);
00579 if ((Queue = Thread->Queue) != NULL) {
00580 Queue->CurrentCount += 1;
00581 }
00582
00583 Thread->WaitStatus = STATUS_KERNEL_APC;
00584 KiInsertDeferredReadyList(Thread);
00585 }
00586
00587 KiReleaseThreadLock(Thread);
00588 }
00589
00590 } else if ((Thread->State == Waiting) &&
00591 (Thread->WaitMode == UserMode) &&
00592 (Thread->Alertable || Thread->ApcState.UserApcPending)) {
00593
00594 Thread->ApcState.UserApcPending = TRUE;
00595 KiUnwaitThread(Thread, STATUS_USER_APC, Increment);
00596 }
MSDN上的内容:
This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.