07Windows文件系统过滤驱动程序教程7.docx

上传人:b****7 文档编号:9434006 上传时间:2023-02-04 格式:DOCX 页数:9 大小:18.36KB
下载 相关 举报
07Windows文件系统过滤驱动程序教程7.docx_第1页
第1页 / 共9页
07Windows文件系统过滤驱动程序教程7.docx_第2页
第2页 / 共9页
07Windows文件系统过滤驱动程序教程7.docx_第3页
第3页 / 共9页
07Windows文件系统过滤驱动程序教程7.docx_第4页
第4页 / 共9页
07Windows文件系统过滤驱动程序教程7.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

07Windows文件系统过滤驱动程序教程7.docx

《07Windows文件系统过滤驱动程序教程7.docx》由会员分享,可在线阅读,更多相关《07Windows文件系统过滤驱动程序教程7.docx(9页珍藏版)》请在冰豆网上搜索。

07Windows文件系统过滤驱动程序教程7.docx

07Windows文件系统过滤驱动程序教程7

Windows文件系统过滤驱动开发教程(7)

7.IRP完成函数,中断级,如何超越中断级别的限制

先讨论一下Volumne设备是如何得到的.首先看以下几个函数:

//------------------wdf.h中的内容-------------------------

typedefVPBwd_vpb;

_inlinewd_vpb*wd_dev_vbp(wd_dev*dev)

{

returndev->Vpb;

}

_inlinewd_dev*wd_vbp_dev(wd_vpb*vpb)

{

returnvpb->DeviceObject;

}

VPB是Volumeparameterblock.一个数据结构.它的主要作用是把实际存储媒介设备对象和文件系统上的卷设备对象联系起来.

wd_dev_vbp可以让你从一个StorageDeviceObject得到一个VPB,而wd_vbp_dev这个函数可以得到这个VPB所对应的Volmue设备.

现在首先要得到StorageDeviceObject.实际上这个东西保存在当前IO_STACK_LOCATION中.

//------------------wdf.h中的内容-----------------------

_inlinewd_dev*wd_irpsp_mount_storage(wd_io_stack*irpsp)

{

returnirpsp->Parameters.MountVolume.Vpb->RealDevice;

};

那么,从irp出发,我最终可以通过以下的方式得到Volumue设备:

wd_irpsp*irpsp=wd_cur_io_stack(irp);

wd_dev*storage_dev=wd_irpsp_mount_storage(irp);

wd_vpb*vpb=wd_dev_vbp(storage_dev);

wd_dev*volume_dev=wd_vbp_dev(vpb);

不过实际情况并不这么简单.这里的IRP是一个MOUNT请求.而volume设备对象实际上是这个请求完成之后的返回结果.因此,在这个请求还没有完成之前,我们就试图去获得Volume设备对象,当然是竹篮打水一场空了.

这里,你可以直接拷贝当前IO_STACK_LOCATION,然后向下发送请求,但在此之前,要先给irp分配一个完成函数.irp一旦完成,你的完成函数将被调用.这样的话,你可以在完成函数中得到Volume设备,并实施你的绑定过程.

这里要讨论一下中断级别的问题.常常碰到人问某函数只能在PassiveLevel调用是什么意思.总之我们的任何代码执行的时候,总是处在某个当前的中断级之中.某些系统调用只能在低级别中断级中执行.请注意,如果一个调用可以在高处运行,那么它能在低处运行,反过来则不行.

我们需要知道的只是我们关心PassiveLevel和DispatchLevel.而且DispatchLevel的中断级较高.一般ddk上都会标明,如果注明irqlevel>=dispatch,那么你就不能在passivelevel的代码中调用它们了.

那么你如何判断当前的代码在哪个中断级别中呢?

我一般是这么判断的:

如果你的代码执行是由于应用程序(或者说上层)的调用而引发的,那么应该在PassiveLevel.如果你的代码执行是由于下层硬件而引发的,那么则可能在dispatchlevel.

希望不要机械的理解我的话!

以上只是极为粗略的便于记忆的理解方法.实际的应用应该是这样的:

所有的dispatchfunctions由于是上层发来的irp而导致的调用,所以应该都是PassiveLevel,在其中你可以调用绝大多数系统调用.而如网卡的OnReceive,硬盘读写完毕,返回而导致的完成函数,都有可能在Dispatch级.注意都是有可能,而不是绝对是.但是一旦有可能,我们就应该按就是考虑.

好,现在我们发现,我们已经注册了完成函数,并且这个函数执行中可能是dispatchlevel.

现在面临的问题是,我们已经决定在完成函数中调用IoAttachDeviceToDeviceStack来绑定Volume.而DDK说明有:

CallersofIoAttachDeviceToDeviceStackmustberunningatIRQL<=DISPATCH_LEVEL.

实际上前边说过有IoAttachDeviceToDeviceStackSafe,这个调用可以在Dispatchlevel进行.无奈这个调用仅仅出现在Xp以上的系统中.

超越中断级别的限制有几种方法.第一种是自己生成一个系统线程来完成此事.系统线程将保证在PassiveLevel中运行.另一种方法就是把自己的任务插入Windows工作者线程,这会使你的任务迟早得到执行.如果你的任务比较小,可以实行第二种方法.对系统来说比较省事,对程序员来说则反正都是麻烦.

我做了以下几个函数专门来插入任务到工作者线程.

//---------------wdf.h中的内容------------------------

typedefWORK_QUEUE_ITEMwd_work_item;

typedefPWORKER_THREAD_ROUTINEwd_work_func;

//任务的初始化

wd_work_funcworker,

wd_void*context)

{

ExInitializeWorkItem(item,worker,context);

}

//三种任务队列

typedefenum_wd_work_quque_type{

wd_work_crit=CriticalWorkQueue,

wd_work_delay=DelayedWorkQueue,

wd_work_hyper=HyperCriticalWorkQueue

}wd_work_queue_type;

_inlinewd_voidwd_work_queue(inwd_work_item*item,

inwd_work_queue_typetype)

{

ExQueueWorkItem(item,(WORK_QUEUE_TYPE)type);

}

_inlinewd_voidwd_work_run(inwd_work_item*item)

{

(item->WorkerRoutine)(item->Parameter);

}

任务是一个数据结构,已经被我重定义为wd_work_item,wd_work_init能初始化它.初始化的时候你只需要填写一个你的任务的函数.同时一个context用来记录上下相关参数.(这是个空指针,你可以只想你任何想要的参数类型).

一般这个任务会自动执行,但是有时我们也想不插入队列,我们自己执行它.那么调用wd_work_run即可.

然后调用wd_work_queque插入工作者队列,之后会被执行.插入类型这里选择wd_work_delay.

希望你没有被这一串东西搞糊涂.现在我会写一个"设置完成函数"的函数.执行后,自动在PassiveLevel级执行你的完成函数.希望不会把你搞得晕头转向的:

).

//完成例程上下文。

好几个fsctl需要注册完成例程。

而例程中的工作可能

//只能在passivelevel中运行,因此不得不加入一个work_item,把任务塞

//入工作线程等待完成

typedefstruct_my_fsctl_comp_con

{

wd_work_itemwork;

wd_dev*dev;

wd_irp*irp;

wd_dev*new_dev;//这个元素仅仅用于mount的时候。

因为我

//们要生成一个新设备来绑定vdo.

}my_fsctl_comp_con;

wd_boolmy_fsctl_set_comp(wd_dev*dev,

wd_irp*irp,

wd_dev*new_dev,

wd_irp_comp_funccomplete,

wd_work_funcwork_complete)

{

my_fsctl_comp_con*context;

context=(wdff_fsctl_comp_con*)wd_malloc(wd_false,

sizeof(wdff_fsctl_comp_con));

if(context==NULL)

{

wd_printf0("fsctlsetcomp:

failedtomalloccontext.\r\n");

returnwd_false;

}

//初始化工作细节

wd_work_init(&context->work,

work_complete,

context);

context->dev=dev;

context->irp=irp;

context->new_dev=new_dev;

//设置irp完成例程

wd_irp_comp(irp,complete,context);

returnwd_true;

}

//以下函数作为以上complete的参数被使用

wd_statmy_fsctl_comp(inwd_dev*dev,

inwd_irp*irp,

inwd_void*context)

{

wd_printf0("fsctl_comp:

comein!

!

!

\r\n");

UNREFERENCED_PARAMETER(dev);

UNREFERENCED_PARAMETER(irp);

//判断当前中断级

if(wd_get_cur_irql()>wd_irql_passive)

{

wd_printf0("fsctl_comp:

intoquque!

!

!

\r\n");

//如果在passive更低的中断级别,必须插入延迟队列中运行

wd_work_queue((wd_work_item*)context,wd_work_delay);

}

else

{

//否则可以直接执行

wd_printf0("fsctl_comp:

rundirectly!

!

!

\r\n");

wd_work_run((wd_work_item*)context);

}

returnwd_stat_more_processing;

}

我想以上的过程应该已经可以理解了!

注册了基本的完成历程complete函数(也就是我最后写的函数my_fsctl_comp后),irp执行完毕回调my_fsctl_comp,而我事先已经把已经做好的任务(wd_work_item)写在上下文指针中(context)中.一回调这个函数,我就wd_work_queque插入队列.结果wd_work_item中记录的work_complete函数显然会在Passivelevel中执行.我们的系统也将保持稳定.

work_complete函数将从context上下文指针中得到足够的参数,来完成对Volume的绑定.

希望你没有被弄昏头:

),我们下回再分解.

她含着笑,切着冰屑悉索的萝卜,  

她含着笑,用手掏着猪吃的麦糟,  

她含着笑,扇着炖肉的炉子的火,  

她含着笑,背了团箕到广场上去  

晒好那些大豆和小麦,  

大堰河,为了生活,  

在她流尽了她的乳液之后,  

她就用抱过我的两臂,劳动了。

  

大堰河,深爱着她的乳儿;  

在年节里,为了他,忙着切那冬米的糖,  

为了他,常悄悄地走到村边的她的家里去,  

为了他,走到她的身边叫一声“妈”,  

大堰河,把他画的大红大绿的关云长  

贴在灶边的墙上,  

大堰河,会对她的邻居夸口赞美她的乳儿;  

大堰河曾做了一个不能对人说的梦:

  

在梦里,她吃着她的乳儿的婚酒,  

坐在辉煌的结彩的堂上,  

而她的娇美的媳妇亲切的叫她“婆婆”  

…………  

大堰河,深爱她的乳儿!

  

大堰河,在她的梦没有做醒的时候已死了。

  

她死时,乳儿不在她的旁侧,  

她死时,平时打骂她的丈夫也为她流泪,  

五个儿子,个个哭得很悲,  

她死时,轻轻地呼着她的乳儿的名字,  

大堰河,已死了,  

她死时,乳儿不在她的旁侧。

  

大堰河,含泪的去了!

  

同着四十几年的人世生活的凌侮,  

同着数不尽的奴隶的凄苦,  

同着四块钱的棺材和几束稻草,  

同着几尺长方的埋棺材的土地,  

同着一手把的纸钱的灰,  

大堰河,她含泪的去了。

  

这是大堰河所不知道的:

  

她的醉酒的丈夫已死去,  

大儿做了土匪,  

第二个死在炮火的烟里,  

第三,第四,第五  

而我,我是在写着给予这不公道的世界的咒语。

  

当我经了长长的飘泊回到故土时,  

在山腰里,田野上,  

兄弟们碰见时,是比六七年

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1