当前位置: 首页 > news >正文

nt!KeRemoveQueue 函数分析之加入队列后进入等待状态


第一部分:

参考例子:应用程序调用kernel32!GetQueuedCompletionStatus后会调用nt!KeRemoveQueue函数进入进入等待状态
0: kd> g
Breakpoint 8 hit
nt!KiDeliverApc:
80a3c776 55              push    ebp
0: kd> kc
 #
00 nt!KiDeliverApc
01 nt!KiSwapThread
02 nt!KeRemoveQueue
03 nt!NtRemoveIoCompletion
04 nt!_KiSystemService
05 SharedUserData!SystemCallStub
06 ntdll!ZwRemoveIoCompletion
07 kernel32!GetQueuedCompletionStatus
08 RPCRT4!COMMON_ProcessCalls
09 RPCRT4!LOADABLE_TRANSPORT::ProcessIOEvents
0a RPCRT4!ProcessIOEventsWrapper
0b RPCRT4!BaseCachedThreadRoutine
0c RPCRT4!ThreadStartRoutine
0d kernel32!BaseThreadStart
PLIST_ENTRY
KeRemoveQueue (
    IN PRKQUEUE Queue,
    IN KPROCESSOR_MODE WaitMode,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )

/*++

Routine Description:

    This function removes the next entry from the Queue object entry
    list. If no list entry is available, then the calling thread is
    put in a wait state.

    N.B. The wait discipline for Queue object LIFO.

Arguments:

    Queue - Supplies a pointer to a dispatcher object of type Queue.

    WaitMode  - Supplies the processor mode in which the wait is to occur.

    Timeout - Supplies a pointer to an optional absolute of relative time over
        which the wait is to occur.

Return Value:

    The address of the entry removed from the Queue object entry list or
    STATUS_TIMEOUT.

    N.B. These values can easily be distinguished by the fact that all
         addresses in kernel mode have the high order bit set.

--*/

{

    PKPRCB CurrentPrcb;
    LARGE_INTEGER DueTime;
    PLIST_ENTRY Entry;
    LARGE_INTEGER NewTime;
    PRKQUEUE OldQueue;
    PLARGE_INTEGER OriginalTime;
    LOGICAL StackSwappable;
    PRKTHREAD Thread;
    PRKTIMER Timer;
    PRKWAIT_BLOCK WaitBlock;
    LONG_PTR WaitStatus;
    PRKWAIT_BLOCK WaitTimer;

    ASSERT_QUEUE(Queue);

    //
    // Set constant variables.
    //

    OriginalTime = Timeout;
    Thread = KeGetCurrentThread();
    Timer = &Thread->Timer;
    WaitBlock = &Thread->WaitBlock[0];
    WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK];

    //
    // If the dispatcher database lock is already held, then initialize the
    // local variables. Otherwise, raise IRQL to SYNCH_LEVEL, initialize the
    // thread local variables, and lock the dispatcher database.
    //

    if (Thread->WaitNext) {
        Thread->WaitNext = FALSE;
        InitializeRemoveQueue();

    } else {
        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
        InitializeRemoveQueue();
        KiLockDispatcherDatabaseAtSynchLevel();
    }

    //
    // Check if the thread is currently processing a queue entry and whether
    // the new queue is the same as the old queue.
    //

    OldQueue = Thread->Queue;
    Thread->Queue = Queue;
    if (Queue != OldQueue) {

        //
        // If the thread was previously associated with a queue, then remove
        // the thread from the old queue object thread list and attempt to
        // activate another thread.
        //

        Entry = &Thread->QueueListEntry;
        if (OldQueue != NULL) {
            RemoveEntryList(Entry);
            KiActivateWaiterQueue(OldQueue);
        }

        //
        // Insert thread in the thread list of the new queue that the thread
        // will be associate with.
        //

        InsertTailList(&Queue->ThreadListHead, Entry);

    } else {

        //
        // The previous and current queue are the same queue - decrement the
        // current number of threads.
        //

        Queue->CurrentCount -= 1;
    }

    //
    // Start of wait loop.
    //
    // Note this loop is repeated if a kernel APC is delivered in the
    // middle of the wait or a kernel APC is pending on the first attempt
    // through the loop.
    //
    // If the Queue object entry list is not empty, then remove the next
    // entry from the Queue object entry list. Otherwise, wait for an entry
    // to be inserted in the queue.
    //

    do {

        //
        // Check if there is a queue entry available and the current
        // number of active threads is less than target maximum number
        // of threads.
        //

        Entry = Queue->EntryListHead.Flink;
        if ((Entry != &Queue->EntryListHead) &&
            (Queue->CurrentCount < Queue->MaximumCount)) {

            //
            // Decrement the number of entires in the Queue object entry list,
            // increment the number of active threads, remove the next entry
            // from the list, and set the forward link to NULL.
            //

            Queue->Header.SignalState -= 1;
            Queue->CurrentCount += 1;
            if ((Entry->Flink == NULL) || (Entry->Blink == NULL)) {
                KeBugCheckEx(INVALID_WORK_QUEUE_ITEM,
                             (ULONG_PTR)Entry,
                             (ULONG_PTR)Queue,
                             (ULONG_PTR)&ExWorkerQueue[0],
                             (ULONG_PTR)((PWORK_QUEUE_ITEM)Entry)->WorkerRoutine);
            }

            RemoveEntryList(Entry);
            Entry->Flink = NULL;
            break;

        } else {

            //
            // Test to determine if a kernel APC is pending.
            //
            // If a kernel APC is pending, the special APC disable count is
            // zero, and the previous IRQL was less than APC_LEVEL, then a
            // kernel APC was queued by another processor just after IRQL was
            // raised to DISPATCH_LEVEL, but before the dispatcher database
            // was locked.
            //
            // N.B. that this can only happen in a multiprocessor system.
            //

            if (Thread->ApcState.KernelApcPending &&
                (Thread->SpecialApcDisable == 0) &&
                (Thread->WaitIrql < APC_LEVEL)) {

                //
                // Increment the current thread count, unlock the dispatcher
                // database, and exit the dispatcher. An APC interrupt will
                // immediately occur which will result in the delivery of the
                // kernel APC, if possible.
                //

                Queue->CurrentCount += 1;
                KiRequestSoftwareInterrupt(APC_LEVEL);
                KiUnlockDispatcherDatabaseFromSynchLevel();
                KiExitDispatcher(Thread->WaitIrql);

            } else {

                //
                // Test if a user APC is pending.
                //

                if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) {
                    Entry = (PLIST_ENTRY)ULongToPtr(STATUS_USER_APC);
                    Queue->CurrentCount += 1;
                    break;
                }

                //
                // Check to determine if a timeout value is specified.
                //

                if (ARGUMENT_PRESENT(Timeout)) {

                    //
                    // If the timeout value is zero, then return immediately
                    // without waiting.
                    //

                    if (!(Timeout->LowPart | Timeout->HighPart)) {
                        Entry = (PLIST_ENTRY)ULongToPtr(STATUS_TIMEOUT);
                        Queue->CurrentCount += 1;
                        break;
                    }

                    //
                    // Insert the timer in the timer tree.
                    //
                    // N.B. The constant fields of the timer wait block are
                    //      initialized when the thread is initialized. The
                    //      constant fields include the wait object, wait key,
                    //      wait type, and the wait list entry link pointers.
                    //

                    if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
                        Entry = (PLIST_ENTRY)ULongToPtr(STATUS_TIMEOUT);
                        Queue->CurrentCount += 1;
                        break;
                    }

                    DueTime.QuadPart = Timer->DueTime.QuadPart;
                }

                //
                // Insert wait block in object wait list.
                //

                InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry);

                //
                // Set the thread wait parameters, set the thread dispatcher
                // state to Waiting, and insert the thread in the wait list.
                //

                CurrentPrcb = KeGetCurrentPrcb();
                Thread->State = Waiting;
                if (StackSwappable != FALSE) {
                    InsertTailList(&CurrentPrcb->WaitListHead, &Thread->WaitListEntry);
                }

                //
                // Set swap busy for the current thread, unlock the dispatcher
                // database, and switch to a new thread.
                //
                // Control is returned at the original IRQL.
                //

                ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);

                KiSetContextSwapBusy(Thread);
                KiUnlockDispatcherDatabaseFromSynchLevel();
                WaitStatus = KiSwapThread(Thread, CurrentPrcb);

                //
                // If the thread was not awakened to deliver a kernel mode APC,
                // then return wait status.
                //

                Thread->WaitReason = 0;
                if (WaitStatus != STATUS_KERNEL_APC) {
                    return (PLIST_ENTRY)WaitStatus;
                }

                if (ARGUMENT_PRESENT(Timeout)) {

                    //
                    // Reduce the amount of time remaining before timeout occurs.
                    //

                    Timeout = KiComputeWaitInterval(OriginalTime,
                                                    &DueTime,
                                                    &NewTime);
                }
            }

            //
            // Raise IRQL to SYNCH level, initialize the local variables,
            // lock the dispatcher database, and decrement the count of
            // active threads.
            //

            Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
            InitializeRemoveQueue();
            KiLockDispatcherDatabaseAtSynchLevel();
            Queue->CurrentCount -= 1;
        }

    } while (TRUE);

    //
    // Unlock the dispatcher database, exit the dispatcher, and return the
    // list entry address or a status of timeout.
    //

    KiUnlockDispatcherDatabaseFromSynchLevel();
    KiExitDispatcher(Thread->WaitIrql);
    return Entry;
}

第二部分:

    OldQueue = Thread->Queue;
    Thread->Queue = Queue;
    if (Queue != OldQueue) {

        //
        // If the thread was previously associated with a queue, then remove
        // the thread from the old queue object thread list and attempt to
        // activate another thread.
        //

        Entry = &Thread->QueueListEntry;
        if (OldQueue != NULL) {
            RemoveEntryList(Entry);
            KiActivateWaiterQueue(OldQueue);
        }

        //
        // Insert thread in the thread list of the new queue that the thread
        // will be associate with.
        //

        InsertTailList(&Queue->ThreadListHead, Entry);

1: kd> dt kthread 0x89848268
ntdll!KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY [ 0x89848278 - 0x89848278 ]
   +0x018 InitialStack     : 0xbaac8000 Void
   +0x01c StackLimit       : 0xbaac5000 Void
   +0x020 KernelStack      : 0xbaac7c38 Void
   +0x024 ThreadLock       : 0
   +0x028 ContextSwitches  : 2
   +0x02c State            : 0x5 ''
 
   +0x100 QueueListEntry   : _LIST_ENTRY [ 0x895f3b28 - 0x895f3b28 ]
1: kd> dx -id 0,0,898d9250 -r1 (*((ntdll!_LIST_ENTRY *)0x89848368))
(*((ntdll!_LIST_ENTRY *)0x89848368))                 [Type: _LIST_ENTRY]
    [+0x000] Flink            : 0x895f3b28 [Type: _LIST_ENTRY *]
    [+0x004] Blink            : 0x895f3b28 [Type: _LIST_ENTRY *]

第三部分:

PLIST_ENTRY
KeRemoveQueue (
    IN PRKQUEUE Queue,
    IN KPROCESSOR_MODE WaitMode,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )
{

 
            if (Thread->ApcState.KernelApcPending &&
                (Thread->SpecialApcDisable == 0) &&
                (Thread->WaitIrql < APC_LEVEL)) {
        
        。。。。。。
            } else {

                //
                // Insert wait block in object wait list.
                //

                InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry);

1: kd> dx -id 0,0,898d9250 -r1 (*((GDI32!_DISPATCHER_HEADER *)0x895f3b08))
(*((GDI32!_DISPATCHER_HEADER *)0x895f3b08))                 [Type: _DISPATCHER_HEADER]
    [+0x000] Type             : 0x4 [Type: unsigned char]
    [+0x001] Absolute         : 0x0 [Type: unsigned char]
    [+0x002] Size             : 0xa [Type: unsigned char]
    [+0x003] Inserted         : 0x0 [Type: unsigned char]
    [+0x003] DebugActive      : 0x0 [Type: unsigned char]
    [+0x000] Lock             : 655364 [Type: long]
    [+0x004] SignalState      : 0 [Type: long]
    [+0x008] WaitListHead     [Type: _LIST_ENTRY]
1: kd> dx -id 0,0,898d9250 -r1 (*((GDI32!_LIST_ENTRY *)0x895f3b10))
(*((GDI32!_LIST_ENTRY *)0x895f3b10))                 [Type: _LIST_ENTRY]
    [+0x000] Flink            : 0x89848308 [Type: _LIST_ENTRY *]
    [+0x004] Blink            : 0x89848308 [Type: _LIST_ENTRY *]

1: kd> dt kthread 0x89848308-a0
ntdll!KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY [ 0x89848278 - 0x89848278 ]
   +0x018 InitialStack     : 0xbaac8000 Void
   +0x01c StackLimit       : 0xbaac5000 Void
   +0x020 KernelStack      : 0xbaac7c38 Void
   +0x024 ThreadLock       : 0
   +0x028 ContextSwitches  : 2
   +0x02c State            : 0x5 ''

   +0x0a0 WaitBlock        : [4] _KWAIT_BLOCK

相关文章:

  • Verilog学习-1.模块的结构
  • 图灵逆向——题六-倚天剑
  • 费马小定理
  • FRP调用本地摄像头完成远程拍照
  • 2台8卡L20服务器集群推理方案
  • FlashDB 在嵌入式系统中占用硬件资源
  • 2025 跨平台技术如何选:KMP 与 Flutter 的核心差异
  • 【ISP】ISP pipeline(AI)
  • 创建采购申请报错不可能为销售订单或项目库存确定科目 消息号 ME558
  • dubbo配置中心
  • 内核态切换到用户态
  • ①(PROFINET 转 EtherNet/IP)EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关
  • 【Nodebb系列】Nodebb笔记写入方案
  • DDPM理论基础解析
  • 使用chainlit出现【无法访问服务器】或【Could not reach the server.】解决方案
  • Redis的主从复制
  • 解码AI大脑:Claude的思维显微镜与语言炼金术
  • 数学知识——矩阵乘法
  • 牛客KY222 打印日期
  • Spring Boot 3.5新特性解析:自动配置再升级,微服务开发更高效
  • 百度网站的主要盈利来源不包括/百度地图导航2022最新版下载
  • 网站备案是给什么进行备案/免费网站流量统计工具
  • 上海网站建设公司网/抖音搜索引擎优化
  • 用jsp做的网站框架/百度产品大全首页
  • 营销型 网站开发/网络营销费用预算
  • 做好的网站如何上线/seo的含义是什么意思