WDF队列分析(1)--序幕

本文深入剖析了WDF框架中的IoQueue实现,并以toaster为例,详细解释了FxDevice::DispatchWithLock的作用及其如何处理不同类型的IRP。文章还探讨了WDF驱动中派遣函数的设置时机。

    WDF框架中IoQueue的实现相当复杂,覆盖的内容很广,需要大量的篇幅来分析。至于demo程序,还是以我们熟悉的toaster入手。虽然IoQueue的实现分散在WDF源码的很多角落,但我还是整理出一个线索,这几篇文章会围绕着它逐步展开。好,现在来看下所谓的线索:

kd> g
Breakpoint 0 hit
wdfsimple!ToasterEvtIoRead+0x39:
a64b41b9 8b5508          mov     edx,dword ptr [ebp+8]
kd> kb
ChildEBP RetAddr  Args to Child              
acd13a00 86715c84 368477c8 4fbd0228 0000000a wdfsimple!ToasterEvtIoRead+0x39 [c:\winddk\7600.16385.1\src\general\toaster\kmdf\func\simple\toaster.c @ 306]
acd13a1c 8674c82a 368477c8 4fbd0228 0000000a Wdf01000!FxIoQueueIoStop::Invoke+0x2e [minkernel\wdf\framework\shared\inc\private\common\fxioqueuecallbacks.hpp @ 159]
acd13a54 86712b91 0000000a b042fdd0 c97b8830 Wdf01000!FxIoQueue::DispatchRequestToDriver+0x39a0a [minkernel\wdf\framework\shared\irphandlers\io\fxioqueue.cpp @ 3272]
acd13a78 867133df acd13a00 00000000 af9b88f0 Wdf01000!FxIoQueue::DispatchEvents+0x241 [minkernel\wdf\framework\shared\irphandlers\io\fxioqueue.cpp @ 3125]
acd13a98 86711bb6 b042fdd0 8ac98244 8d656020 Wdf01000!FxIoQueue::QueueRequest+0x7f [minkernel\wdf\framework\shared\irphandlers\io\fxioqueue.cpp @ 2371]
acd13af0 821584b8 01656020 00647374 c96472e0 Wdf01000!FxDevice::DispatchWithLock+0x316 [minkernel\wdf\framework\shared\core\fxdevice.cpp @ 1430]
acd13b0c 8239ce2c c9647398 c96472e0 8d656020 nt!IofCallDriver+0x48

这是toaster处理IRP_MJ_READ时的调用堆栈,请不要因为他是所谓的线索而感到意外,我也是顺着这个调用栈,慢慢梳理出IoQueue的轮廓。所以,请你耐心的往下看下去。

    如果熟悉wdm驱动,那你一定知道调用IoCallDriver后,会调用对应驱动的Dispatch函数。根据上面堆栈的最后两行输出,可知Toaster处理IRP_MJ_READ的Dispatch函数是FxDevice::DispatchWithLock。是不是有点震惊?看toaster\kmdf\func\simple\toaster.c的代码,MS像是把Dispatch函数设置为:

    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig,  WdfIoQueueDispatchParallel);

    queueConfig.EvtIoRead = ToasterEvtIoRead;
    queueConfig.EvtIoWrite = ToasterEvtIoWrite;
    queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl;

    看来一定是FxDevice::DispatchWithLock封装并调用了ToasterEvtIoRead。所以现在要做的是确定IRP_MJ_READ回调函数确实是FxDevice::DispatchWithLock(具体步骤请移步我的另一篇博客):

kd> !drvobj 8e54baf8 7
Driver object (8e54baf8) is for:
 \Driver\wdffeatured
Driver Extension List: (id , addr)
(862ecd8a a4a06068)  
Device Object list:
b0a90390  

DriverEntry:   a82224e0	wdffeatured!FxDriverEntry
DriverStartIo: 00000000	
DriverUnload:  a82225cc	wdffeatured!FxStubDriverUnload
AddDevice:     862b09de	Wdf01000!FxDriver::AddDevice

Dispatch routines:
[00] IRP_MJ_CREATE                      862918a0	Wdf01000!FxDevice::DispatchWithLock
[02] IRP_MJ_CLOSE                       862918a0	Wdf01000!FxDevice::DispatchWithLock
[03] IRP_MJ_READ                        862918a0	Wdf01000!FxDevice::DispatchWithLock
[04] IRP_MJ_WRITE                       862918a0	Wdf01000!FxDevice::DispatchWithLock
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     862918a0	Wdf01000!FxDevice::DispatchWithLock
[10] IRP_MJ_SHUTDOWN                    862918a0	Wdf01000!FxDevice::DispatchWithLock
[12] IRP_MJ_CLEANUP                     862918a0	Wdf01000!FxDevice::DispatchWithLock
[16] IRP_MJ_POWER                       862918a0	Wdf01000!FxDevice::DispatchWithLock
[17] IRP_MJ_SYSTEM_CONTROL              862918a0	Wdf01000!FxDevice::DispatchWithLock
[1b] IRP_MJ_PNP                         862918a0	Wdf01000!FxDevice::DispatchWithLock

参windbg的输出所示,WDF驱动的IRP处理函数清一色被设置成FxDevice::DispatchWithLock!起初我还以为调试器出了问题,反复核对源码才确定这既是事实!已知IRP处理函数是FxDevice::DispatchWithLock,只要查找它的所有引用即可知道在哪设置了这些派遣函数。但是,先不要急着查找引用,反问自己一个问题:在wdm中,一般什么时候设置驱动派遣函数?答案是在DriverEntry返回前。以此类推,wdf驱动也做了同样的事。在wdf中DriverEntry主要是调用WdfCreateDriver,因此,我猜测为驱动程序设置回调函数是由WdfCreateDriver完成。我们可以在FxDriver::Initialize中找到这样的代码:

WdfDriverCreate(...)
{
...
	pDriver = new(pFxDriverGlobals, DriverAttributes)
        FxDriver(DriverObject, DriverConfig, pFxDriverGlobals);

    if (pDriver != NULL) {

        if (NT_SUCCESS(status)) {

            status = pDriver->Initialize(RegistryPath, DriverConfig, DriverAttributes);
...
}
在FxDriver::Initialize中,驱动程序的派遣函数在循环内被统一的设置成Wdf01000!FxDevice::DispatchWithLock,如下:
FxDriver::Initialize(
__in PCUNICODE_STRING ArgRegistryPath,
__in PWDF_DRIVER_CONFIG Config,
__in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
)
{
    #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
	for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
            if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) {
                m_DriverObject.SetMajorFunction(i, FxDevice::Dispatch);
            }
            else {
                m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLock);
            }
}

嗯,感觉DispatchWithLock十有八九是个代理函数:根据不同类型的IRP,做不同的处理。再继续分析之前,容我啰嗦一下DispatchWithLock这个函数名中的Lock的含义:它指设备对象扩展域中的自定义的RemoveLock。在WDF框架中,处理PNP/Power这类IRP前需要获取RemoveLock,而处理Create/Close/Cleanup以及Read/Write/ioctl这类IRP没有强制需要获得RemoveLock。关于RemoveLock的细节,参考win7 ddk的event样例。

    回到正题,DispatchWithLock在判断和获取RemoveLock后,先后进入FxDevice::Dispatch和DispatchWorker。DispatchWorker将引出本篇的主角----IoQueue:

__inline
NTSTATUS
DispatchWorker(
    __in FxDevice*  Device,
    __in MdIrp       Irp,
    __in WDFCONTEXT DispatchContext
    )
{
	...
    return Device->GetDispatchPackage(
        irp.GetMajorFunction()
        )->Dispatch(Irp);
}

GetDispatchPackage返回FxPackage*基类指针,Dispatch是类FxPackage中的虚函数。很明显,MS是想通过多态实现对IRP多元化处理。目前WDF中有4种FxPackage的派生类满足4种处理方式:

1).IRP_MJ_Create/Close/Cleanup/Shutdown对应的派生类为FxPkgGeneral;

2).IRP_MJ_Read/Write/DeviceIoControl对应的派生类为FxPkgIo;

3).IRP_MJ_Pnp/Power对应的派生类为FxPkgPnp;

4).其他类型的IRP对应的派生类为FxDefaultIrpHandler。

这些派生类各自实现了各自的Dispatch函数,自此,IRP开始分门别类的被处理,本篇完。下篇分析这些派生类对象被设置的时机。

内容概要:本文围绕“新能源发电接入弱电网的宽频带振荡机理及抑制方法”开展深入研究,依托Matlab/Simulink平台完整复现了相关博士论文的核心内容。研究聚焦于新能源并网系统在弱电网条件下引发的宽频带振荡问题,通过构建光伏并网逆变器、虚拟同步发电机(VSG)等关键设备的精确动态模型,采用阻抗建模、序阻抗分析、扫频法和小信号稳定性分析等先进理论工具,系统揭示了锁相环、电流控制环与电网阻抗之间复杂的动态交互机制及其诱发不稳定振荡的内在机理。在此基础上,提出了包括自适应控制、虚拟阻抗、增益调度等多种针对性的抑制策略,并通过详尽的仿真验证了其有效性。该资源不仅提供了核心研究成果的复现代码与模型,还整合了大量电力系统稳定性、微电网优化、智能算法应用等领域的配套案例,构成一套体系完整、理论与实践紧密结合的高水平科研参考资料。; 适合人群:具备电力系统分析、新能源并网技术、自动控制理论等专业知识背景,熟练掌握Matlab/Simulink仿真工具的研究生、高校科研人员及电力电子与电力系统领域的工程技术人员。; 使用场景及目标:① 深入探究新能源并网系统在弱电网环境下面临的稳定性挑战与宽频带振荡的产生根源;② 系统学习并掌握阻抗建模、扫频分析等现代电力电子系统稳定性评估的关键技术与方法论;③ 实践复现高水平学术论文(特别是博士论文)中的复杂模型与核心结论,为自身的课题研究、论文撰写与项目攻关提供坚实的理论依据和技术验证;④ 借助丰富的配套案例资源,进行新算法开发、模型优化与综合技术方案的设计与测试。; 阅读建议:建议读者结合文中提供的网盘链接,下载完整的Matlab代码与Simulink仿真模型进行动手实践。在学习过程中,应着重关注核心模型的搭建逻辑、参数设计依据以及不同控制策略的实现细节,通过主动修改系统参数、切换控制方案等方式进行对比仿真分析,从而深刻理解理论分析、数学模型与实际仿真结果之间的内在联系,充分发挥该资源在科研学习与技术创新中的最大价值。
这个是完整源码 python实现 大数据 Spark pyspark 可视化大屏+Kafka+FastAPI+Vue3 【大数据毕业设计】基于Spark实时电商用户行为分析与预测(Python版本+pyspark+可视化大屏+Kafka+FastAPI+Vue3) 源码+论文 完整版 数据库Mysql 随着微博、抖音、知乎、小红书等社交媒体的快速发展,网络舆情呈现出数据规模大、传播速度快、情感变化剧烈等特点。传统基于离线批处理的舆情分析方法难以满足“秒级感知、分钟级研判”的业务需求。针对上述问题,本文设计并实现了一套基于 Spark 的实时社交媒体舆情分析与趋势预测系统。系统采用前后端分离架构:前端基于 Vue3、Element Plus 与 ECharts 构建管理后台和可视化大屏;后端基于 Python 与 FastAPI 提供统一 REST API;消息层引入 Kafka 承接高并发舆情事件流;计算层使用 Spark Streaming(Structured Streaming)完成按小时窗口的帖文量、独立用户数、正中负情感分布与热度指数聚合;预测层基于 Spark ML 线性回归,结合滞后热度特征与小时特征,对舆情热度进行趋势预测,并以 RMSE、MAE、MAPE 评估模型误差。数据持久化采用 MySQL,数据库名为 db_social_opinion。系统还设计了 Kafka/Spark 不可用时的 pandas 与 scikit-learn 降级方案,保证演示与实验环境的可用性。测试结果表明,系统能够稳定完成舆情数据采集、实时统计、趋势预测与可视化展示,功能完整、结构清晰,达到本科毕业设计要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值