WRK源码——KeAttachProcess

周五没事可做,搞了个脚本跑一下百度可免费下载的歌曲,然后看看WRK。今天看了一下KeAttachProcess。

KeAttachProcess将当前线程加载到特定进程空间。如果进程已经在内存中,那就直接进入进程空间执行代码;否则需要把当前执行线程插入进程的ReadList链表,并进行线程切换。其中涉及到不少中断级的限制和同步操作资源获取,与线程相关的操作则大部分与APC有关。


VOID
KeAttachProcess (
    __inout PRKPROCESS Process
    )
{
    KLOCK_QUEUE_HANDLE LockHandle;
    PRKTHREAD Thread;

    ASSERT_PROCESS(Process);
    ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

    Thread = KeGetCurrentThread();
    if (Thread-> ApcState.Process != Process) {
        if ((Thread-> ApcStateIndex != 0) ||
            (KeIsExecutingDpc() != FALSE)) { 
            KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                         (ULONG_PTR)Process,
                         (ULONG_PTR)Thread-> ApcState.Process,
                         (ULONG)Thread-> ApcStateIndex,
                         (ULONG)KeIsExecutingDpc());
        }

        KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread-> ApcQueueLock,
                                                   &LockHandle);
        KiLockDispatcherDatabaseAtSynchLevel();
        KiAttachProcess(Thread, Process, &LockHandle, &Thread-> SavedApcState);
    }
    return;
}


VOID
KiAttachProcess (
    __inout PRKTHREAD Thread,
    __in PKPROCESS Process,
    __in PKLOCK_QUEUE_HANDLE LockHandle,
    __out PRKAPC_STATE SavedApcState
    )
{
    PLIST_ENTRY NextEntry;
    PRKTHREAD OutThread;

    ASSERT(Process != Thread-> ApcState.Process);
    ASSERT(Process-> StackCount != MAXULONG_PTR);

    Process-> StackCount += 1;

    KiMoveApcState(&Thread-> ApcState, SavedApcState);
    InitializeListHead(&Thread-> ApcState.ApcListHead[KernelMode]);
    InitializeListHead(&Thread-> ApcState.ApcListHead[UserMode]);
    Thread-> ApcState.KernelApcInProgress = FALSE;
    Thread-> ApcState.KernelApcPending  = FALSE;
    Thread-> ApcState.UserApcPending = FALSE;
    if (SavedApcState == &Thread-> SavedApcState) {
        Thread-> ApcStatePointer[0] = &Thread-> SavedApcState;
        Thread-> ApcStatePointer[1] = &Thread-> ApcState;
        Thread-> ApcStateIndex = 1;
    }

    if (Process-> State == ProcessInMemory) {
        Thread-> ApcState.Process = Process;

        NextEntry = Process-> ReadyListHead.Flink;
        while (NextEntry != &Process-> ReadyListHead) {
            OutThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry);
            RemoveEntryList(NextEntry);
            OutThread-> ProcessReadyQueue = FALSE;
            KiReadyThread(OutThread);
            NextEntry = Process-> ReadyListHead.Flink;
        }

        KiUnlockDispatcherDatabaseFromSynchLevel();
        KeReleaseInStackQueuedSpinLockFromDpcLevel(LockHandle);
        KiSwapProcess(Process, SavedApcState-> Process);
        KiExitDispatcher(LockHandle-> OldIrql);

    } else {
        Thread-> State = Ready;
        Thread-> ProcessReadyQueue = TRUE;
        InsertTailList(&Process-> ReadyListHead, &Thread-> WaitListEntry);
        if (Process-> State == ProcessOutOfMemory) {
            Process-> State = ProcessInTransition;
            InterlockedPushEntrySingleList(&KiProcessInSwapListHead,
                                           &Process-> SwapListEntry);
            KiSetInternalEvent(&KiSwapEvent, KiSwappingThread);
        }

        Thread-> WaitIrql = LockHandle-> OldIrql;
        KeReleaseInStackQueuedSpinLockFromDpcLevel(LockHandle);
        KiSetContextSwapBusy(Thread);
        KiUnlockDispatcherDatabaseFromSynchLevel();
        KiSwapThread(Thread, KeGetCurrentPrcb());

        KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread-> ApcQueueLock,
                                                   LockHandle);

        KiLockDispatcherDatabaseAtSynchLevel();
        Thread-> ApcState.Process = Process;
        KiUnlockDispatcherDatabaseFromSynchLevel();
        KeReleaseInStackQueuedSpinLockFromDpcLevel(LockHandle);
        KiSwapProcess(Process, SavedApcState-> Process);
        KiExitDispatcher(LockHandle-> OldIrql);
    }
    return;
}