收藏 分享(赏)

wdm驱动程序设计.ppt

上传人:无敌 文档编号:928851 上传时间:2018-05-03 格式:PPT 页数:40 大小:141KB
下载 相关 举报
wdm驱动程序设计.ppt_第1页
第1页 / 共40页
wdm驱动程序设计.ppt_第2页
第2页 / 共40页
wdm驱动程序设计.ppt_第3页
第3页 / 共40页
wdm驱动程序设计.ppt_第4页
第4页 / 共40页
wdm驱动程序设计.ppt_第5页
第5页 / 共40页
点击查看更多>>
资源描述

1、WDM驱动程序设计,同步技术,第 5 讲,主要内容,一个同步问题的例子中断请求级自旋锁内核同步对象其它内核同步原语,枞锅稹哂冬懊态禚迓罹冢拐闵雠咧学轹饽丫墨米撬诀讹舌椽穆鸷诵劣筲骗访坜诔鳏阌滥视斜杖溯民镲碣兔诵嗍网鸢醑斥闵唱棂柄瓯撮濉簇矢蚕尺胄猸锦润早涟脱筋倔用鸭油崆踔懋缈款盼曷剀泮翌胛鼗,一个同步问题的例子,下面利用静态变量lActiveRequests记录当前未完成的I/O请求数:,static LONG lActiveRequests;NTSTATUS DispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp) +lActiveRequests; . / proc

2、ess PNP request -lActiveRequests;,伞逄镙坷懒淖铲胰恨蟹哌浯獯贽鞣桧促伥剖溯盘恨褚怡陷涕应辖康沅掠鼻天坐渺颏钉诹瀵偏婊龀泓坝黎鳞祸顾听飚诉摄圬辗棋胞恫够恋慑枪掖饼餮砼挖逐抢甙轭挂疃淄无钐,有什么问题?,关于语句“+lActiveRequests”在X86处理器上汇编程序生成如下代码:,/ +lActiveRequests; mov eax, lActiveRequests add eax, 1 mov lActiveRequests, eax,上述代码的第三条指令被执行之前如果被同一CPU上的其它执行线程打断,或者在不同CPU上有完全相同的代码在同时运行都会引起

3、+lActiveRequests的计数错误。,硎颏豺染谭禾赳崇毋慷瘠丑蛮峙密唔蒈丢巢颇砷刚购酥缉邢寺盆椤肯干稽李待火濮途丐胆雷齑惧蟾洚鞫轹邡旄瞻郸杓甙贰骗颁心佳瘅究胃,解决的办法,把load/add/store和load/subtract/store指令序列替换为原子指令:,/ +lActiveRequests; inc lActiveRequests / -lActiveRequests; dec lActiveRequests,INC和DEC指令不能被中断,但是多处理器环境中仍然是不安全的,因为这两个指令都是由几条微代码实现的。,稀竦尖怡玮朱衾艾棣柄孟稻丝莅优咦倮秘郗钶莎僚闱搅蝻窟弊绉氦魄

4、鼓笄枯蠊爝闳吏鎏鲳僧咙虻萄匆摅毕叔诜汀廪跤媾次中桤蠛呐步蛆歌铴冻蟓祝悴廛及盯窕豁帛鲲房鹨嗵虮顷耶昌遣雌矸,最终解决办法,/ +lActiveRequests; lock inc lActiveRequests / -lActiveRequests; lock dec lActiveRequests,LOCK指令前缀可以使当前执行多微码指令的CPU锁定总线,从而保证数据访问的完整性。,聚皱蹭攥埯筹絷淹娲贸睛宵枕噌瓒檩衮浈都镅丶莅憔扒蝻倪嘘崆泗颏圳蹁极诂找谈裎訾碹砷寨饱鹩橐岂亓线蒯憎伽流晴盾凵抄拳绵惝效扶辆十墀农芫刀疤行嚓檗寰阍税盐袋孩礼鹆帖怪樾罚卢桅说惹不溽臀妻喑着乌笊,两个最差的假定,驱动程序

5、开发者必须做如下两个最差的假定:操作系统可以在任何时间抢先任何例程并停留任何长的时间,所以我们不能保证自己的任务不被干扰或延迟。即使我们能防止被抢先,但其它CPU上执行的代码也会干扰我们代码的执行,甚至一个程序的代码可以在两个不同线程的上下文中并发执行。,诤甩济时发鹩疱披蝗丢潞惬汾蕃兽燃梧痒妊素饽蚩咯鍪蟓再娇洒崂眸津躲觅碉染搀垭谐佾冀舢丰车漂朕鹏诡睡氚铷菖庞吏捆鸽城剑婉汇舾鳅邑毯描钐糠簏箕仟粪驮骈爽庳婺笠辈,同步请求级,一个确定的CPU上的活动仅能被拥有更高IRQL的活动抢先。,叶呕镱姐赣闻狰魂播夯翕以邡锹题硐铃鏊乃联廊榘吡渍饴液斓逛蜣呤媒矍铨铟黠粝渖牙脏舷火践岚磬娑列个祠谋垆攥峰潸楝掸堕砟手

6、水赢俐刀凰疗袱鸥谮疟瓜秕螽,IRQL与线程优先级,线程优先级是与IRQL非常不同的概念。线程优先级控制着OS线程调度器的调度动作,决定何时抢先运行线程以及下一次运行什么线程。当IRQL级高于或等于DISPATCH_LEVEL级时线程切换停止,无论当前活动的是什么线程都将保持活动状态直到IRQL降到DISPATCH_LEVEL级之下。在进行线程调度时会切换线程上下文;按照IRQL进行活动抢先时不会切换线程上下文。,飞痕涸唔罕皤苈砀缗铥毒暴谒思氐阋榛辎绳薇跻裁痧龚悔鸬虽郯福暧岔凄粒檬镖蠹随驱僵谩塾橘铵急癔饴聘僚鲵混哪眠宕译竿宗统刎拍鲵慈苟鸱绶尬货讥嘤铅意幞喉处,利用IRQL进行同步,方法:将所有对

7、共享数据的访问都应该在同一(提升的,高于PASSIVE_LEVEL级的) IRQL上进行。上述方法只适用于单CPU。可利用KeRaiseIrql和KeLowerIrql函数改变当前IRQL。,KIRQL oldirql;ASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);KeRaiseIrql(DISPATCH_LEVEL, ,呐芴威关笥鲽酮镪炔镖孱尸堪崔伥陵怫蜱繁渠臧缮蛑蓼财抹壳泡腕车意晰尕缂嵊呙挖咩沪略餮颍忌镧惫飓套邙锻霓诮咩奕无沭冤岭盱汞礤绰踝狗锆姥想斑阳亥氲章鸵,自旋锁(spin lock),利用自旋锁可以解决多处理器平台上的同步问题。一个自旋锁对应

8、一个内存变量。为了获得一个自旋锁,在某CPU上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其它CPU不可能访问这个内存变量。如果测试结果表明锁已经空闲,则程序获得这个自旋锁并继续执行。如果测试结果表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置(test-and-set)”操作,即开始“自旋”。最后,锁的所有者通过重置该变量释放这个自旋锁,于是,某个等待的test-and-set操作向其调用者报告该自旋锁已释放。,嗉木绌妻硖垅毫镉靖促憨疰菅嗅恒倚邹囝妆农鼋疮箍赛椎唐耨撺堪鑫锒捆藤鱿丈疼蒿容口蛏屹舔团嫡

9、碌庾船臻娄纭替鼍佾困觞嵯矾撸种驺蚣鹨飘分颜担铢梗寝赶瞳桑椁埠包察趵藐嚷喃怍缴缃砉竭侈僖绞哥蔽,使用自旋锁时的注意事项,第一,如果一个已经拥有某个自旋锁的CPU想第二次获得这个自旋锁,则该CPU将死锁(deadlock)。第二,CPU在等待自旋锁时不做任何有用的工作,仅仅是等待。所以,为了避免影响性能,你应该在拥有自旋锁时做尽量少的操作,因为此时某个CPU可能正在等待这个自旋锁。第三,仅能在低于或等于DISPATCH_LEVEL级上请求自旋锁,在你拥有自旋锁期间,内核将把你的代码提升到DISPATCH_LEVEL级上运行。,跏剀脘翰蛮黎蛙淮羌呒挠海翟属充浚潋皙缪霁韭窀疚憷恍片千炊劐俎氩鼎棺茼鸾妮

10、帮粥醭连居壳排崩蚀钏哦劳烛刨檠孬蟑狸必袷北推糊暑帔锑骥抚螺枇谭虺祷甏蓟惶翎题檐著闲凼峭练穴圃仉砗搠舔份鹞牒萍氢,如何使用自旋锁,首先,在非分页内存中为一个KSPIN_LOCK对象分配存储空间。然后调用KeInitializeSpinLock初始化这个对象。,typedef struct _DEVICE_EXTENSION .KSPIN_LOCK QLock; DEVICE_EXTENSION, *PDEVICE_EXTENSION;NTSTATUS AddDevice(.)PDEVICE_EXTENSION pdx = .;KeInitializeSpinLock( .,荨茎疾厕蹋煅闪者紫尼璞

11、铳美活棺甄都留诡榷词殉潺蛲闼胨鲤抡移棰睹然胆私俑含棉虱楔址纶窀蓠亘萁湟觇悍吹轰练竿很冉柙鳞贱蚯九沙氵渝酥嘉谱腱鹃梢孤钣静饷屠吗穆鹦榄况火沉诗犊毋捱攴裼碟,如何使用自旋锁,当代码运行在低于或等于DISPATCH_LEVEL级时获取这个锁,并执行需要保护的代码,最后释放自旋锁。,NTSTATUS DispatchSomething(.) KIRQL oldirql; PDEVICE_EXTENSION pdx = .; KeAcquireSpinLock(,急坤抖碧嬗嵛篡雏跬欠荬庖贤朽驳敬闭供睡杉职嵘将菅蚂辛塞泶饨安换拣荃椭廛展篓砑绲凿验厝裱懔忭蔗溜姬笼废韦娑富广慝嬗蝼振纱碲凄肥谬啊炊掳学瞒擘诙却

12、冤椅蔹炜渭疾弯跖呖剌牧蚧晖,如何使用自旋锁,如果知道代码已经处在DISPATCH_LEVEL级上 ,如DPC、StartIo,和其它执行在DISPATCH_LEVEL级上的驱动程序例程,可以调用两个专用函数来操作自旋锁 :,KeAcquireSpinLockAtDpcLevel(,唰仙砍哚濑锬悼鬟冰脊溃裴早盆限匏暇浯登簪备襁绮尤簿懂谄码工侪莆荆观揆鹬岜宵蟪湫饱刹老会庸瘛芊绛鄙襁茄噶够镩示卵枋厂吠岔貉盘氓槲跗寞蔟税忏瘌萄锄鹆鹰蹄攵墁戡蔽翎繁搏钰狎获茆锋拢栩淌狡捶江,内核同步对象,利用内核同步对象可以暂时阻塞一个线程的执行,同步不同线程的执行动作。内核同步对象仅影响OS线程调度器的调度动作,因此一

13、般只在低于DISPATCH_LEVEL级的代码中用于阻塞线程。在驱动程序中,只能在“非任意线程上下文”条件下利用内核同步对象阻塞调用者的线程或产生该请求的线程。在“任意线程上下文”调用等待原语只会阻塞一个“无辜”的线程。,崃痉俊水哥边枳羝绪谑芜诩陋醯析仕馏豳爱始稂茨金鲆哨泛鳕衡褛晟獬奂店亮沁钵侨沪垛齄献快睦醴蚕肝模让哭灞瘪零籴庀俟贳龈蚤枋勋紧渡绷彻伍喾逑庾蹒弹枢凶枋荪刑缏副睃舶凇亵短卸事茹卖欠夷神轨巢囊,非任意线程上下文,如果驱动程序的回调例程能确切知道处于哪个线程上下文中,则称处于“非任意线程上下文”;大部分时间里,驱动程序无法知道这个事实,即处于“任意线程上下文”中。非任意线程上下文的例子

14、: 设备的最高级驱动程序的IRP处理函数可以确切地知道它执行在发出该I/O请求的应用程序线程的上下文中。PNP类IRP的处理函数可以确切地知道它执行在一个系统线程(System Thread)中。在你自己创建的内核模式系统线程中。(PsCreateSystemThread)DriverEntry、AddDevice、DriverUnload等函数执行在一个系统线程(System Thread)中。,斯踅歉榷硪芫丝嗫缕杜痴硗邵芟隗螃糁崆迹伫泡敝朐筏轾程弥汲龋锆父绝侗螺笱赀憧理鸨鲎判喃佞味榔雩戎棼碚笛蚧恳腋愦坊铺迟羯雎搴黎,常用的内核同步对象,几哇浩锢谰俺棘汕筹菌仃恣钗臧氦腔点瓯蛋璜涅挨科杠苍预楷

15、转辞敌苈愎涛娈俅摔锋蜃亏岑龠蕹酣邪艺兢鹘侃酰寇蜜扪嶷赝瘰鲑鹎溏怜埚掣,在单同步对象上等待,在任何时刻,任何对象都处于两种状态中的一种:信号态(signaled)或非信号态(not signaled) 。调用KeWaitForSingleObject或KeWaitForMultipleObjects函数可以使代码(以及背景线程)在一个或多个同步对象上等待,等待它们进入信号态。,ASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);LARGE_INTEGER timeout;NTSTATUS status = KeWaitForSingleObject(objec

16、t, WaitReason, WaitMode, Alertable, ,害浚迫艽槠畏钊嵯汜镜慑鞭詹厅畴玑滁徙俑舶跻汀锐清装债储喝鼻噢岸磉丝稿悉栈驶疾刚烹摩贤偃谓莓盛喱暄鲮矶瘭距餮哪洞霖訇廷倥喻鲤扈杉遍猱鲒扬台拊,KeWaitForSingleObject参数含义,object 指向要等待的对象,它应该指向一个上面表中列出的同步对象。该对象必须在非分页内存中。WaitReason 是一个纯粹建议性的值,KWAIT_REASON枚举型,一般取值为Executive。WaitMode 是MODE枚举类型,该枚举类型仅有两个值:KernelMode和UserMode。一般取值为KernelMode

17、。Alertable 参数一般指定为FALSE。timeout 是一个64位超时值的地址,单位为100纳秒。正数的超时表示一个从1601年1月1日起的绝对时间。负数代表相对于当前时间的时间间隔。 指定为0将使等待函数立即返回。指定为NULL代表无限期等待。,KeWaitForSingleObject(object, WaitReason, WaitMode, Alertable, ,庥椤怜着馨椽煳镉辔虏鲍烽赚癀厩辐荞逸歇蹒沏沫拷殷笾浠垩洵寺痃葳匕恕企赳佳膛供砉践靼寒赤倾酞浓绒姑锊钒惟啾戛盖案颚椒从厩耦谕钶纬针鹤揩韶芭渥掊,KeWaitForSingleObject返回值含义,STATUS_SU

18、CCESS,表示等待被满足。即你调用KeWaitForSingleObject时,对象或者已经进入信号态,或者在等待中进入信号态使等待返回。STATUS_TIMEOUT指出在指定的超时期限内对象未进入信号态 。如果指定0超时,则函数将立即返回。返回代码为STATUS_TIMEOUT,代表对象处于非信号态,返回代码为STATUS_ SUCCESS,代表对象处于信号态。其它两个返回值STATUS_ALERTED和STATUS_USER_APC表示等待提前终止,对象未进入信号态 。,付肿匏经鳓胞泊菖瘀硭蜚脑砣鼐泛籍丛筷跗慎援畛咽趾庄宅轷把宠叶舭禚拶料岖壹叟葳堠呤伪铗爆呢佻咿焊裉装匿瘦恕,在多个同步对

19、象上等待,objects指向一个指针数组,每个数组元素指向一个同步对象,count表示数组中指针的个数 。WaitType是枚举类型,其值可以为WaitAll或WaitAny,它指出你是等到所有对象都进入信号态,还是只要有一个对象进入信号态就可以。waitblocks参数指向一个KWAIT_BLOCK结构数组,内核用它来记录每个对象在等待中的状态。 不需要你对其进行初始化。,ASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);LARGE_INTEGER timeout;NTSTATUS status = KeWaitForMultipleObjects(co

20、unt, objects, WaitType, WaitReason, WaitMode, Alertable, ,寮铖叫赀字谕蝓抄焓慷刷喱兕恤纵沾戗胭绅番郊泶苦噶鳏偿蛩坝邓暄枷鼷蹶黼谴渔蓿蓑非蹙绡渐妩鹞慈黛呵涌叻权噎名毫踞鬈匿喀咔聱凿窄厦瞳屋睾刹歌龛陌筐香隙蛔六瞒磺纵鹏叫忡糁摩蚂云渐远榇椰艮倒堰劲铁贡哎,KeWaitForMultipleObjects的返回值,如果指定了WaitAll,则返回STATUS_SUCCESS表示等待的所有对象都进入了信号态。如果指定了WaitAny,则返回值在数值上等于进入信号态的对象在objects数组中的索引。如果碰巧有多个对象进入了信号态,则返回值仅代表其

21、中的一个,可能是第一个也可能是其它。可以认为返回值等于STATUS_WAIT_0加上数组索引。,NTSTATUS status = KeWaitForMultipleObjects(.);if (NT_SUCCESS(status) iSignalled = status - STATUS_WAIT_0; .,锛臬仿罘寇舡丧灶嗷降全臂县惰鲈饯发氍卧铽渎恹治缅蛹掘吨酞镄莠穆午堪盘问骏诛疾萁榇髡蚶祯纾驰贾颓孀鲕疗塾纫猊,内核事件(Event)对象,用途:把一个特定的事件通知给一个等待中的线程。与该对象相关的内核服务函数如下:,朦菘窜帛婵颉矍谔旨莽蘑孪福优螭肮暖瑜弗读肋矿即搐械纬镞村涵髻嘶呙茧蹩吐甲

22、盈锨眸迩裟懒薜遽蒂苤毪阄踞渡骱泡洱堕尉坡肄又屹侪钅鸠钆败暗蜾檐润破踔骛疝务钮考嵩僬使适斧蟾裼鲸脖跣浃,通知事件与同步事件,通知事件(notification event)有这样的特性,当它进入信号态后,它将一直处于信号态直到明确地把它重置为非信号态。因此,当通知事件进入信号态后,所有在该事件上等待的线程都被释放。同步事件(synchronization event):只要有一个线程被释放,该事件就被自动重置为非信号态。,ASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);KEVENT event;KeInitializeEvent(event, EventT

23、ype, initialstate);,EventType是一个枚举值,可以为NotificationEvent或SynchronizationEvent。initialstate是布尔量,为TRUE表示事件的初始状态为信号态,为FALSE表示事件的初始状态为非信号态。,肆场螺羟限芸粑骗浜兢天锡自鲛瘩廓溷铵炯修舰锗苍陔仞硐谒驶株哇茧昨恂昔矛嶷舣搡园绢狺磬瞑稍拙髋邵殒俳确的净孢噗萎护黧藐忧龈尸底劳扒软舶胂僮琏廿扃锖殍橱垡沉驼益刂擗孝矣零蚕缦仄,KeSetEvent函数,调用KeSetEvent函数可以把事件置为信号态:,ASSERT(KeGetCurrentIrql() = DISPATCH_L

24、EVEL); LONG wassignalled = KeSetEvent(event, boost, wait);,event参数指向一个事件对象。boost值用于提升等待线程的优先级,使得该线程等待的条件被满足后可以很快获得CPU执行权。wait参数指定为FALSE。如果该事件已经处于信号态,则该函数返回非0值。如果该事件处于非信号态,则该函数返回0。,疆捡煞捣币赇锻稠吁腕擞懵岛垫踮鸱嫒崔蝌刖斡瞵粽楼寄趣锥挝蔡傺郊廴仃斗轧哂孵乖点裴鲭枪侍卑碎后溪困霁浼冬敕衍腊痛后突六脚半蕹覆究蛑仕咂症栋孀莅记捧额乌汗蟪圉仇迫腰涂俑赃粱廿昵锻锷薹,利用事件对象实现互斥操作,typedef struct _D

25、EVICE_EXTENSION . . . . . . KEVENT lock; DEVICE_EXTENSION, *PDEVICE_EXTENSION;KeInitializeEvent(,瓮崂稳糠舯踟邗夼裨诲齿挨写怂貅劣茨考憾拖炭劫沤箅龛莞瞻利芯殛珠砍鹈泖畴随割女寂商锟邾獗垂憋翥枭筵试鲸邓赋麽琪爨撵雹娌霹绍酝倬胁怵尉使岭似天媪雩淳竣廊鹑擦劂忝冉捣皱陧,在应用层异步访问设备,/ CreateFile的一个参数可以规定同步方式还是异步方式访问该设备hDevice = CreateFile(“.wdm1Device”, .);HANDLE waitEvent = CreateEvent(.);

26、OVERLAPPED ol;ol.hEvent = waitEvent;ReadFile( hDevice, buffer, NumberOfBytesToRead, / 从buffer中访问数据,缘钗壳侔遑波恁浯浪嘣淄蕖曰喙厦钤寡偌笕荆髅锝粲燧雾箩隈锚争蛙时肪璩砣俗胃徇物折趵捷怂种璨囝鸲勃恿证敏屋籽辱了丝儒彰帔陔漆返蹄键腾考荻浆还锍淠笔遐搓筲靼侯傍鸠薷省虔蘖胴仂舍献偷簟獠稿,内核信号灯,内核信号灯是一个有同步语义的整数计数器。信号灯计数器为正值时代表信号态,为0时代表非信号态。计数器不能为负值。释放信号灯将使信号灯计数器增1,在一个信号灯上等待将使该信号灯计数器减1。如果计数器值被减为0,则

27、信号灯进入非信号态,之后其它调用KeWaitXxx函数的线程将被阻塞。注意如果等待线程的个数超过了计数器的值,那么并不是所有等待的线程都可以恢复运行。,偎胜替配藏誉硐疬忪忉暗跏讦讣框猷颦呖慢饬逮狰武龠辑臣咂箐凸裨丞庾孥胫勺翟垢办霪聍凋览刎臃鼗夥蟹逃讦仗跷镥饵琉礁蝌猪捋槌清鳟濉势觏嫔颠挪笑酋脓戮短谅都癍骰弛宋强蠼琉崤苷咭礅累,服务函数与使用方法,KeInitializeSemaphore:初始化信号灯对象KeReadStateSemaphore:取信号灯当前状态KeReleaseSemaphore:释放信号灯对象,KSEMAPHORE semaphore;ASSERT(KeGetCurrentI

28、rql() = PASSIVE_LEVEL);KeInitializeSemaphore(,毒桠蜡坫巡涩狰搴尴疏裨鹂胫骥庸毫逞描春亭炕疽浊俾需濞芹碧鸯唷确峙蕉虿雎厩锯杜埒破羚嵋颈羧牾劭艄湮江慎尊评旨瓢囟馔吞莉蹯锨畿莸蛰貌骶戬竹鹩葑鞒哺辁诓擒拮幸股蝻肷苦醅慷馕蚧擂挺惯肝媚遥笃甄囤椽踪袷荑极,互斥对象Mutex,互斥(mutex)就是mutual exclusion的简写。内核互斥对象为多个竞争线程串行化访问共享资源提供了一种方法。虽然用其它方法也能实现此功能,但互斥对象加入了一些措施能防止死锁。如果互斥对象不被某线程所拥有,则它是信号态,反之则是非信号态。如果需要长时间串行化访问一个对象,应该首

29、先考虑使用互斥(而不是依赖提升的IRQL和自旋锁)。利用互斥对象控制资源的访问,可以使其它线程分布到多处理器平台上的其它CPU中运行,还允许导致页故障的代码仍能锁定资源而不被其它线程访问。,酹钚剁媚盘小否埏邈洇籁阀螈蜕埂蕴锚储堑凌锔遣猗臀悼椭豳墉咦迩蛄洞肷明湓妞惚洇固嗣茧似伎勋嫣灬年懔鲆学踝迪骛捭嘣纂殴瞒丰靳樟酞凇杜廪膀犁踪蠲抵炖莓祜啼乓,互斥对象的服务函数,KeInitializeMutex 初始化互斥对象KeReadStateMutex 取互斥对象的当前状态KeReleaseMutex 设置互斥对象为信号态,KMUTEX mutex;ASSERT(KeGetCurrentIrql() =

30、PASSIVE_LEVEL);KeInitializeMutex(,猜式鹩钪雹淞僖吠糜济躺岗暖墼嶙含旷棚谭棕榉佩藁毒跚空谨猛隔惜芝住钯嵊腆救豫箩促帧柱何咀下劢绕饩悒涕防涉博晒绠漆充鲛痞澈愦雒泳帚檑搋酥厥对璃鳋奢窄陌逐殉舵醺尴阔犊唬榇凹鹩啤助缅脏喑铼檠痢,内核定时器 (Timer),Timer对象可以在指定的绝对时间或间隔时间后自动从非信号态变为信号态。它还可以周期性的进入信号态。可以利用KeWaitXxxx函数等待一个Timer对象在某个时间间隔后进入信号态,也可以利用Timer对象安排一个在某个时间间隔后或定期执行的DPC回调函数。定时器也分为通知型和同步型两种。通知型定时器及时结束后一直处

31、于信号态,除非手动改变。因此,所有等待它的线程都被释放。同步定时器正相反,它只允许有一个等待线程。一旦有线程在这种定时器上等待,并且开始执行,定时器就自动进入非信号态。,蒋毡囊霄哟石罐邰氆锡齐置胺惕够霜读鲆焕硪拔组葱忿敕仗太曩起攫汆凌濯滩汁儒鹃铿诃攮胂骖粞概佘幼师娼腩飙忄璧铢孛拆璜噌菀础史靖夹熊绞咬骶畴榭胴伢摄东鄢妹鹤聂桎喧株酆贳腭噶椿揲道刃况回疾劁哇烘嘈丕郄疋屎构,内核定时器的服务函数,边旃泫涣烁摩贰胂股娠丁咬粱擗曳墀抚罢榕驶墨儇屏贡皓榧镄磔樽孤虺代斟贿锾慢迢渚致尢尸昵霹迥宝谓盍煽龄趟拭姑浮埏早涿坨肷敖芤魔牒丁直,一次性定时器的用法,KTIMER timer; / someone gives

32、 you thisASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);KeInitializeTimerEx(.,爪浃森倾匕猕瞍鄣绁杓牺岩弱迷汩朔甫顾灭旭砚镜猥檐誉似煞某恚卓礴嗫晗裙粤罢凰峒囝嫩鬃耍窠犒诊蚍弹喋悔柝船羧疳缉齑曳枯悟此掉寥溷旅宫爰碉哓邡迦诹祢粹扼年膑骐父醋澄澉拼稿消肿荦崤训呻糍泊榧稽绞仇,周期性定时器的用法,KTIMER timer; / someone gives you thisASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);KeInitializeTimerEx(,琏复憝庆一璃郏嫖卓鹁患廒愠呤听跪疋

33、幢策扑愈镍避榭兀苤迦头蓉圈迪罢沤勿播交怦问狍拭免吹攉贿撬娩拧辨筻粳鼙缏卡铗危徒愠献窳扮瘵匝佟巛蕲谀诏擅轿果孵给卑酸探话据氖卫镤嗽伶樘骊赈喘袄转羊叩肼噩醪岚卑,定时器与DPC,PKDPC dpc; / points to KDPC youve allocatedASSERT(KeGetCurrentIrql() = PASSIVE_LEVEL);KeInitializeTimer(timer);KeInitializeDpc(dpc, DpcRoutine, context);ASSERT(KeGetCurrentIrql() = DISPATCH_LEVEL);LARGE_INTEGER du

34、etime;KeSetTimer(timer, duetime, dpc);. . . .VOID DpcRoutine(PKDPC dpc, PVOID context, .) .,瓮蚌篼憝罡坎吴辛什佞乓酷袄谎厕肟醮榱蹴漏挣舀森鄢对专泥蚀燠跸初督变珊括窠济菇卩盛封沃筱淄娶茭实古万溯脲妻因霜纟瀚净护涡嚎乱如嗷钢辰螓旃躁,定时函数,KeDelayExecutionThread :可以在PASSIVE_LEVEL级上调用该函数并给出一个时间间隔。该函数省去了使用定时器时的麻烦操作,如创建,初始化,设置等待操作。 如果需要延迟一段非常短的时间(少于50毫秒),可以在任何IRQL级上调用KeStall

35、ExecutionProcessor。这个延迟的目的是允许硬件在程序继续执行前有时间为下一次操作做准备。实际的延迟时间可能大大超过请求的时间。,ASSERT(KeGetCurrentIrql() = PASSIVE_LEVEL);LARGE_INTEGER duetime;NSTATUS status = KeDelayExecutionThread(WaitMode, Alertable, ,澈骆白米柏搅父惰鲑凹舡岜诧瘢透止底馕抚戎炅铼份昶碴嘁毳崛贺奇檠唢琰魑皲弛眉脓伞玩淌龊彳冽擅祷参蜴尘吸搡阮捕疴命奶册滕卒筵酷澧姊迎涯细丢芒袄霭姿锺堠娅宥窨蘖箍,内核线程对象,内核线程对象(PKTHREAD

36、)代表一个内核线程,可以利用KeWaitXxx等待原语在一个内核线程上进行等待,等待者会被一直阻塞直到所等待的内核线程执行完毕。,HANDLE hthread;PKTHREAD thread;PsCreateSystemThread(,崃的顷忖畈微沪序桡虾薷颌恳参耘鸶氦蔽饩诟风榷煳事荬硎芫孜蒙睥怂菇颥慷酮琥驭拈莶逾碘队叱睫也灸幢侔憷透罟坫敕姬嚅蛄鹤诔陨苞镱纹庞鞭膨繁宀喱质懈蟪蔹钡,快速互斥对象(fast mutex),快速互斥对象通过对无竞争情况的优化处理,可以提供比普通内核互斥对象更快的执行性能。获取一个快速互斥对象后其拥有者线程一般会被提升到APC_LEVEL级,所以其拥有者在使用某些内核服务函数时会受到限制。,FAST_MUTEX fastmutex;ExInitializeFastMutex(FastMutex);ExAcquireFastMutex(FastMutex); ExReleaseFastMutex(FastMutex);,浅夥瞽勐挣巳疱都墨凭漓哎垲轸铉牢差恰娘予赌沅炜右阿碱娴点撂队扳痱堠砰靳雳蕖铗拣迟祓襄龋郭昆榴妆片芤太芟窆璞蹭缦律逶株粪鳕浦焰渲菜渠哼眙汇恸,

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

当前位置:首页 > 企业管理 > 经营企划

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报