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
相关文章:
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…...
OpenCV 风格迁移
一、引言 在计算机视觉和图像处理领域,风格迁移是一项令人着迷的技术。它能够将一幅图像(风格图像)的艺术风格,如梵高画作的笔触风格、莫奈的色彩风格等,迁移到另一幅图像(内容图像)上&#x…...
35.Java线程池(线程池概述、线程池的架构、线程池的种类与创建、线程池的底层原理、线程池的工作流程、线程池的拒绝策略、自定义线程池)
一、线程池概述 1、线程池的优势 线程池是一种线程使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能,而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这避免了在处理短时间任务时创建与…...
Kubernetes nodeName Manual Scheduling practice (K8S节点名称绑定以及手工调度)
Manual Scheduling 在 Kubernetes 中,手动调度框架允许您将 Pod 分配到特定节点,而无需依赖默认调度器。这对于测试、调试或处理特定工作负载非常有用。您可以通过在 Pod 的规范中设置 nodeName 字段来实现手动调度。以下是一个示例: apiVe…...
QML中访问c++数据,并实现类似C#中mvvm模式详细方法
1. 背景需求2. 实现步骤 2.1. 定义 Model(数据模型) 2.1.1. DataModel.h2.1.2. DataModel.cpp 2.2. 定义 ViewModel(视图模型) 2.2.1. PersonViewModel.h2.2.2. PersonViewModel.cpp 2.3. 在 QML 中使用 ViewModel 2.3.1. main.cp…...
React 获得dom节点和组件通信
通过REF 实例对象的.current属性获得绑定的DOM节点 组件通信 组件通信 1 父传子 父组件传递数据 子组件接受数据 通过pros对象接受 子组件的形参列表props只读 props中数据不可修改 特殊情况 在子传父的过程中没有直接给子组件添加属性,而是向父组件中添加其他…...
代码,Java Maven项目打包遇到的环境问题
这几天在写一些Java版本的Langchain4J的 AI 测试case,有一段时间不运行的Java环境,反复出现环境问题,记录下 1、Java编译版本的问题 修改编译版本: 2、在IDE中运行遇到Maven中JDK版本问题 在ide中执行maven命令,遇到下…...
fisco-bcos 关于服务bash status.sh启动runing 中但是5002端口监听不到,出错的问题
bash status.sh Server com.webank.webase.front.Application Port 5002 is running PID(4587) yjmyjm-VMware-Virtual-Platform:~/webase-front$ sudo netstat -anlp | grep 5002 没有端口信息输出 此时可以查看log文件夹下的WeBASE-front.log,找到报错信息如下…...
C++ 数据结构之图:从理论到实践
一、图的基本概念 1.1 图的定义与组成 图(Graph)由顶点(Vertex)和边(Edge)组成,形式化定义为: G (V, E) 顶点集合 V:表示实体(如城市、用户) …...
linux多线(进)程编程——(5)虚拟内存与内存映射
前言(前情回顾) 进程君开发了管道这门技术后,修真界的各种沟通越来越频繁,这天进程君正与自己的孩子沟通,进程君的孩子说道: “爸爸,昨天我看他们斗法,小明一拳打到了小刚的肚子上&…...
SpringBoot 动态路由菜单 权限系统开发 菜单权限 数据库设计 不同角色对应不同权限
介绍 系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成,而不是固定在系统中。不同的用户根据其权限会看到不同的路由,访问不同的页面。对应各部门不同的权限。 效果 [{"id": 1,"menuName": "用户管理"…...
[dp8_子数组] 乘积为正数的最长子数组长度 | 等差数列划分 | 最长湍流子数组
目录 1.乘积为正数的最长子数组长度 2.等差数列划分 3.最长湍流子数组 写代码做到,只用维护好自己的一小步 1.乘积为正数的最长子数组长度 链接:1567. 乘积为正数的最长子数组长度 给你一个整数数组 nums ,请你求出乘积为正数的最长子数…...
资深词源学家提示词
Role: 资深词源学家 Profile: Language: 中文Description: 作为在词源学领域的卓越专家,具备深厚且多元的学术背景。精通拉丁语、古希腊语、梵语等一众古老语言,能够精准解析这些语言的古代文献,为探寻词汇起源挖掘第一手资料。在汉语研究方…...
深入探讨MySQL存储引擎:选择最适合你的数据库解决方案
前言 大家好,今天我们将详细探讨MySQL中几种主要的存储引擎,了解它们的工作机制、适用场景以及各自的优缺点。通过这篇文章,希望能帮助你根据具体需求选择最合适的存储引擎,优化数据库性能。 1. InnoDB - 默认且强大的事务性存储…...
【图像处理基石】什么是通透感?
一、画面的通透感定义 画面的通透感指图像在色彩鲜明度、空间层次感、物体轮廓清晰度三方面的综合表现,具体表现为: 色彩鲜明:颜色纯净且饱和度适中,无灰暗或浑浊感;层次分明:明暗过渡自然,光…...
无锡无人机超视距驾驶证怎么考?
无锡无人机超视距驾驶证怎么考?在近年来,无人机技术的迅猛发展使得无人机的应用场景变得愈发广泛,其不仅在环境监测、农业喷洒、快递配送等领域展现出真金白银的价值,同时也推动了无人机驾驶证的需求。尤其是在无锡,随…...
213、【图论】有向图的完全联通(Python)
题目描述 原题链接:105. 有向图的完全联通 代码实现 import collectionsn, k list(map(int, input().split())) adjacency collections.defaultdict(list) for _ in range(k):head, tail list(map(int, input().split()))adjacency[head].append(tail)visited_…...
(二十二)安卓开发中的数据存储之SQLite简单使用
在Android开发中,SQLite是一种非常常用的数据库存储方式。它轻量、简单,非常适合移动设备上的数据管理。本文将通过通俗易懂的语言,结合代码示例和具体场景,详细讲解SQLite在Android中的使用。 1. 什么是SQLite? SQLite是一个开…...
图像形态学操作对比(Opencv)
形态学基于图像的形状进行操作,用于处理二值化图像,主要包括腐蚀和膨胀两种基本操作。这些操作通常用于去除噪声、分隔或连接相邻的元素以及寻找图像中显著的最大点和最小点。 1. 形态学操作 import cv2 import numpy as np import matplotlib.pyplot …...
复刻系列-星穹铁道 3.2 版本先行展示页
复刻星穹铁道 3.2 版本先行展示页 0. 视频 手搓~星穹铁道~展示页~~~ 1. 基本信息 作者: 啊是特嗷桃系列: 复刻系列官方的网站: 《崩坏:星穹铁道》3.2版本「走过安眠地的花丛」专题展示页现已上线复刻的网…...
请你说一说测试用例的边界
一、什么是测试用例的边界? 边界是指输入、输出、状态或操作的极限条件,是系统行为可能发生变化的临界点。例如: 输入字段的最小值、最大值、空值、超长值; 循环的第0次、第1次、最后一次; 时间相关的闰年、月末、跨时区操作等。 边界测试的核心思想是:缺陷更容易出现在…...
Linux:进程理解1(查看进程,创造进程,进程状态)
进程理解 (一)查看进程通过系统调用获取进程标示* (二)创造进程(fork)1. 创造的子进程的PCB代码数据怎么来?2.一个函数为什么有两个返回值?3. 为什么这里会有 两个 id值?…...
异形遮罩之QML中的 `OpacityMask` 实战
文章目录 🌧️ 传统实现的问题👉 效果图 🌈 使用 OpacityMask 的理想方案👉代码如下🎯 最终效果: ✨ 延伸应用🧠 总结 在 UI 设计中,经常希望实现一些“异形区域”拥有统一透明度或颜…...
如何为您的设计应用选择高速连接器
电气应用的设计过程需要考虑诸多因素,尤其是在设计高速网络时。许多连接器用户可能没有意识到,除了在两个互连之间组装导电线路之外,还需要考虑各种工艺。在建立高速连接并确保适当的信号完整性时,必须考虑蚀刻、公差、屏蔽等因素…...
mongodb 4.0+多文档事务的实现原理
1. 副本集事务实现(4.0) 非严格依赖二阶段提交 MongoDB 4.0 在副本集环境中通过 全局逻辑时钟(Logical Clock) 和 快照隔离(Snapshot Isolation) 实现多文档事务,事务提交时通过…...
【论文阅读】UniAD: Planning-oriented Autonomous Driving
一、Introduction 传统的无人驾驶采用了区分子模块的设计,即将无人驾驶拆分为感知规划控制三个模块,这虽然能够让无人驾驶以一个很清晰的结构实现,但是感知的结果在传达到规划部分的时候,会导致部分信息丢失,这势必会…...
upload-labs二次打
1(前端js绕过) 弹窗,先看看有没有js有,禁用js 禁用后就可以上传php文件了,然后我们就去访问文件,成功 2(MIME绕过) 先上传一个php文件试试,不行,.htaccess不行, 试试MIME类型&am…...
Flutter命令行打包打不出ipa报错
Flutter打包ipa报错解决方案 在Flutter开发中,打包iOS应用时可能会遇到以下错误: error: exportArchive: The data couldn’t be read because it isn’ in the correct format. 或者 Encountered error while creating the IPA: error: exportArchive…...
网页制作中的MVC和MVT
MVC(模型-视图-控制器)和MVT(模型-模板-视图)是两种常见的软件架构模式,通常用于Web应用程序的设计。它们之间的主要区别在于各自的组件职责和工作方式。 MVC(模型-视图-控制器): 模…...
C. Good Subarrays
time limit per test 2 seconds memory limit per test 256 megabytes You are given an array a1,a2,…,ana1,a2,…,an consisting of integers from 00 to 99. A subarray al,al1,al2,…,ar−1,aral,al1,al2,…,ar−1,ar is good if the sum of elements of this subarra…...
