青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

aurain
技術文摘
posts - 137,  comments - 268,  trackbacks - 0
原文地址 http://hi.baidu.com/wukongafei/blog/item/7f96853e14fb47fe838b1345.html

Windows NT為每個硬件中斷和少數軟件事件賦予了一個優先級,即中斷請求級(interrupt request level - IRQL)。IRQL為單CPU上的活動提供了同步方法,它基于下面規則:

一旦某CPU執行在高于PASSIVE_LEVEL的IRQL上時,該CPU上的活動僅能被擁有更高IRQL的活動搶先。

圖4-1顯示了x86平臺上的IRQL值范圍。(通常,這個IRQL數值要取決于你所面對的平臺) 用戶模式程序執行在PASSIVE_LEVEL上,可以被任何執行在高于該IRQL上的活動搶先。許多設備驅動程序例程也執行在PASSIVE_LEVEL上。第二章中討論的DriverEntryAddDevice例程就屬于這類,大部分IRP派遣例程也屬于這類。

某些公共驅動程序例程執行在DISPATCH_LEVEL上,而DISPATCH_LEVEL級要比PASSIVE_LEVEL級高。這些公共例程包括StartIo例程,DPC(推遲過程調用)例程,和其它一些例程。這些例程的共同特點是,它們都需要訪問設備對象和設備擴展中的某些域,它們都不受派遣例程的干擾或互相干擾。當任何一個這樣的例程運行時,上面陳述的規則可以保證它們不被任何驅動程序的派遣例程搶先,因為派遣例程本身執行在更低級的IRQL上。另外,它們也不會被同類例程搶先,因為那些例程運行的IRQL與它們自己的相同。只有擁有更高IRQL的活動才能搶先它們。

注意
派遣例程(Dispatch routine)和DISPATCH_LEVEL級名稱類似。之所以稱做派遣例程是因為I/O管理器向這些函數派遣I/O請求。而存在派遣級(DISPATCH_LEVEL)這個名稱是因為內核線程派遣器運行在這個IRQL上,它決定下一次該執行哪個線程。(現在,線程調度程序通常運行在SYNCH_LEVEL級上)

圖4-1. 中斷請求級

在DISPATCH_LEVEL級和PROFILE_LEVEL級之間是各種硬件中斷級。通常,每個有中斷能力的設備都有一個IRQL,它定義了該設備的中斷優先級別。WDM驅動程序只有在收到一個副功能碼為IRP_MN_START_DEVICE的IRP_MJ_PNP請求后,才能確定其設備的IRQL。設備的配置信息作為參數傳遞給該請求,而設備的IRQL就包含在這個配置信息中。我們通常把設備的中斷級稱為設備IRQL,或DIRQL。

其它IRQL級的含義有時需要依靠具體的CPU結構。這些IRQL通常僅被Windows NT內核內部使用,因此它們的含義與設備驅動程序的編寫不是特別密切相關。例如,我將要在本章后面詳細討論的APC_LEVEL,當系統在該級上為某線程調度APC(異步過程調用)例程時不會被同一CPU上的其它線程所干擾。在HIGH_LEVEL級上系統可以執行一些特殊操作,如系統休眠前的內存快照、處理bug check、處理假中斷,等等。

IRQL的變化

為了演示IRQL的重要性,參見圖4-2,該圖顯示了發生在單CPU上的一系列事件。在時間序列的開始處,CPU執行在PASSIVE_LEVEL級上。在t1時刻,一個中斷到達,它的服務例程執行在DIRQL1上,該級是在DISPATCH_LEVEL和PROFILE_LEVEL之間的某個DIRQL。在t2時刻,另一個中斷到達,它的服務例程執行在DIRQL2上,比DIRQL1低一級。我們討論過搶先規則,所以CPU將繼續服務于第一個中斷。當第一個中斷服務例程在t3時刻完成時,該中斷服務程序可能會請求一個DPC。而DPC例程是執行在DISPATCH_LEVEL上。所以當前存在的未執行的最高優先級的活動就是第二個中斷的服務例程,所以系統接著執行第二個中斷的服務例程。這個例程在t4時刻結束,假設這之后再沒有其它中斷發生,CPU將降到DISPATCH_LEVEL級上執行第一個中斷的DPC例程。當DPC例程在t5時刻完成后,IRQL又落回到原來的PASSIVE_LEVEL級。

圖4-2. 變化中的中斷優先級

基本同步規則

遵循下面規則,你可以利用IRQL的同步效果:

所有對共享數據的訪問都應該在同一(提升的)IRQL上進行。

換句話說,不論何時何地,如果你的代碼訪問的數據對象被其它代碼共享,那么你應該使你的代碼執行在高于PASSIVE_LEVEL的級上。一旦越過PASSIVE_LEVEL級,操作系統將不允許同IRQL的活動相互搶先,從而防止了潛在的沖突。然而這個規則不足以保護多處理器機器上的數據,在多處理器機器中你還需要另外的防護措施——自旋鎖(spin lock)。如果你僅關心單CPU上的操作,那么使用IRQL就可以解決所有同步問題。但事實上,所有WDM驅動程序都必須設計成能夠運行在多處理器的系統上。

IRQL與線程優先級

線程優先級是與IRQL非常不同的概念。線程優先級控制著線程調度器的調度動作,決定何時搶先運行線程以及下一次運行什么線程。然而,當IRQL級高于或等于DISPATCH_LEVEL級時線程切換停止,無論當前活動的是什么線程都將保持活動狀態直到IRQL降到DISPATCH_LEVEL級之下。而此時的“優先級”僅指IRQL本身,由它控制到底哪個活動該執行,而不是該切換到哪個線程的上下文。

IRQL和分頁

執行在提升的IRQL級上的一個后果是,系統將不能處理頁故障(系統在APC級處理頁故障)。這意味著:

執行在高于或等于DISPATCH_LEVEL級上的代碼絕對不能造成頁故障。

這也意味著執行在高于或等于DISPATCH_LEVEL級上的代碼必須存在于非分頁內存中。此外,所有這些代碼要訪問的數據也必須存在于非分頁內存中。最后,隨著IRQL的提升,你能使用的內核模式支持例程將會越來越少。

DDK文檔中明確指出支持例程的IRQL限定。例如,KeWaitForSingleObject例程有兩個限定:

  • 調用者必須運行在低于或等于DISPATCH_LEVEL級上。
  • 如果調用中指定了非0的超時,那么調用者必須嚴格地運行在低于DISPATCH_LEVEL的IRQL上。

上面這兩行想要說明的是:如果KeWaitForSingleObject真的被阻塞了指定長的時間(你指定的非0超時),那么你必定運行在低于DISPATCH_LEVEL的IRQL上,因為只有在這樣的IRQL上線程阻塞才是允許的。如果你所做的一切就是為了檢測事件是否進入信號態,則可以執行在DISPATCH_LEVEL級上。但你不能在ISR或其它運行在高于DISPATCH_LEVEL級上的例程中調用KeWaitForSingleObject例程。

IRQL的隱含控制

在大部分時間里,系統都是在正確的IRQL上調用驅動程序中的例程。雖然我們還沒有詳細地討論過這些例程,但我希望舉一個例子來表達這句話的含義。你首先遇到的I/O請求就是I/O管理器調用你的某個派遣例程來處理一個IRP。這個調用發生在PASSIVE_LEVEL級上,因為你需要阻塞調用者線程,還需要調用其它支持例程。當然,你不能在更高的IRQL級上阻塞一個線程,而PASSIVE_LEVEL也是唯一能讓你無限制地調用任何支持例程的IRQL級。

如果你的派遣例程通過調用IoStartPacket來排隊IRP,那么你第一個遇到的請求將發生在I/O管理器調用你的StartIo例程時。這個調用發生在DISPATCH_LEVEL級,因為系統需要在沒有其它例程(這些例程能在隊列中插入或刪除IRP)干擾的情況下訪問I/O隊列。回想一下前面提到的規則:所有對共享數據的訪問都應該在同一(提升的)IRQL級上進行。因為每個能訪問IRP隊列的例程都執行在DISPATCH_LEVEL級上,所以任何例程在操作隊列期間都不可能被打斷(僅指在單CPU系統)。

之后,設備可能生成一個中斷,而該中斷的服務例程(ISR)將在DIRQL級上被調用。設備上的某些寄存器也許不能被安全地共享。但是,如果你僅在DIRQL上訪問那些寄存器,可以保證在單CPU計算機上沒人能妨礙你的ISR執行。如果驅動程序的其它代碼需要訪問這些關鍵的硬件寄存器,你應該讓這些代碼僅執行在DIRQL級上。KeSynchronizeExecution服務函數可以幫助你強制執行這個規則,我將在第七章的“與中斷處理連接”段中討論這個函數。

再往后,你應該安排一個DPC調用。DPC例程執行在DISPATCH_LEVEL級上,它們需要訪問你的IRP隊列,并取出隊列中的下一個請求,然后把這個請求發送給StartIo例程。你可以調用IoStartNextPacket服務函數從隊列中提取下一個請求,但必須在DISPATCH_LEVEL級上調用。該函數在返回前將調用你的StartIo例程。注意,這里的IRQL吻合得相當巧妙:隊列訪問,調用IoStartNextPacket,和調用StartIo都需要發生在DISPATCH_LEVEL級上,并且系統也是在這個IRQL級上調用DPC例程的。

盡管明確地控制IRQL也是可能的,但幾乎沒有理由這樣做,因為你需要的IRQL和系統調用你時使用的IRQL總是相應的。所以不必不時地提高IRQL,例程希望的IRQL和系統使用的IRQL幾乎總是正確對應的。

IRQL的明確控制

如果必要,你還可以在當前處理器上臨時提升IRQL,然后再降回到原來的IRQL,使用KeRaiseIrqlKeLowerIrql函數。下面代碼運行在PASSIVE_LEVEL級上:

KIRQL oldirql;        <--1
            ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);    <--2
            KeRaiseIrql(DISPATCH_LEVEL, &oldirql);     <--3
            ...
            KeLowerIrql(oldirql);       <--4

  1. KIRQL定義了用于保存IRQL值的數據類型。我們需要一個變量來保存當前IRQL。
  2. 這個ASSERT斷定了調用KeRaiseIrql的必要條件:新IRQL必須大于或等于當前IRQL。如果這個關系不成立,KeRaiseIrql將導致bug check。(即用死亡藍屏報告一個致命錯誤)
  3. KeRaiseIrql把當前的IRQL提升到第一個參數指定的IRQL級上。它同時還把當前的IRQL值保存到第二個參數指定的變量中。在這個例子中,我們把IRQL提升到DISPATCH_LEVEL級,并把原來的IRQL級保存到oldirql變量中。
  4. 執行完任何需要在提升的IRQL上執行的代碼后,我們調用KeLowerIrql把IRQL降低到調用KeRaiseIrql時的級別。

DDK文檔中提到,你必須用與你最近的KeRaiseIrql調用所返回的值調用KeLowerIrql。這在大的方面是對的,因為你提升了IRQL就必須再降低它。然而,由于你調用的代碼或者調用你的代碼所做的各種假設會使后面的決定變得不正確。所以,文檔中的這句話從嚴格意義上講是不正確的。應用到KeLowerIrql函數的唯一的規則就是新IRQL必須低于或等于當前IRQL。

當系統調用你的驅動程序例程時,你降低了IRQL(系統調用你的例程時使用的IRQL,或你的例程希望執行的IRQL),這是一個錯誤,而且是嚴重錯誤,盡管你在例程返回前又提升了IRQL。這種打破同步的結果是,某些活動可以搶先你的例程,并能訪問你的調用者認為不能被共享的數據對象。

有一個函數專用于把IRQL提升到DISPATCH_LEVEL級:

KIRQL oldirql = KeRaiseIrqlToDpcLevel();
            ...
            KeLowerIrql(oldirql)

注意:該函數僅在NTDDK.H中聲明,WDM.H中并沒有聲明該函數,因此WDM驅動程序不應該使用該函數。

posted on 2009-08-13 11:34 閱讀(1173) 評論(0)  編輯 收藏 引用 所屬分類: windows驅動

<2010年5月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用鏈接

留言簿(17)

隨筆分類(138)

隨筆檔案(137)

網絡開發

最新隨筆

搜索

  •  

積分與排名

  • 積分 - 501925
  • 排名 - 37

最新隨筆

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            老司机凹凸av亚洲导航| 老司机精品视频一区二区三区| 久久深夜福利| 两个人的视频www国产精品| 久久精品亚洲乱码伦伦中文 | 亚洲精品一区中文| 亚洲激情二区| 亚洲国产另类久久久精品极度| 亚洲国产mv| 在线视频欧美日韩| 欧美中文字幕在线| 欧美一区二区三区在线视频| 亚洲美女在线国产| 亚洲高清不卡在线| 亚洲久久一区| 小嫩嫩精品导航| 久久午夜精品一区二区| 亚洲国产高清自拍| 亚洲专区国产精品| 西西人体一区二区| 欧美sm极限捆绑bd| 国产精品亚洲а∨天堂免在线| 国内精品国语自产拍在线观看| 亚洲国产综合在线| 午夜精品久久久| 欧美不卡三区| 亚洲永久免费观看| 欧美国产第一页| 国产一区二区三区四区三区四| 亚洲欧洲在线免费| 久久精品国产99国产精品| 欧美插天视频在线播放| 亚洲视频图片小说| 欧美不卡激情三级在线观看| 国产精品男女猛烈高潮激情| 在线精品视频在线观看高清| 亚洲一级在线| 欧美黑人国产人伦爽爽爽| 亚洲一区二区四区| 欧美国产在线观看| 在线看片欧美| 久久精品国产91精品亚洲| 亚洲另类视频| 欧美顶级大胆免费视频| 国产日韩一区在线| 午夜精品久久久久久久蜜桃app| 欧美黄色成人网| 欧美在线亚洲在线| 国产精品永久免费观看| 亚洲调教视频在线观看| 亚洲精品五月天| 欧美成人免费视频| 91久久精品国产91久久性色| 美女日韩欧美| 久久经典综合| 国产亚洲欧美一区在线观看| 午夜亚洲影视| 亚洲无限乱码一二三四麻| 欧美日韩精品免费看| 日韩小视频在线观看| 亚洲国产精品va| 麻豆精品一区二区av白丝在线| 国产一区二区日韩精品| 久久精品中文字幕一区| 欧美一级专区| 国产在线不卡| 久久久免费精品| 久久精品视频在线看| 黑人巨大精品欧美黑白配亚洲| 久久久久久久久久久久久9999| 91久久中文| 欧美顶级少妇做爰| 久久精品中文| 在线观看成人网| 免费欧美视频| 欧美精品国产一区二区| 国产精品99久久久久久久久久久久 | 欧美高清视频在线观看| 久久综合一区二区| 日韩视频一区二区三区| 亚洲欧洲久久| 欧美天堂在线观看| 久久狠狠婷婷| 欧美+日本+国产+在线a∨观看| 亚洲精品欧美一区二区三区| 亚洲裸体俱乐部裸体舞表演av| 国产精品欧美久久久久无广告| 欧美中文字幕精品| 免费成人性网站| 亚洲网站在线观看| 久久国产精品一区二区三区四区 | 亚洲黄色av一区| 99视频在线观看一区三区| 国产日韩欧美一区| 亚洲国产高清aⅴ视频| 国产精品成人播放| 另类春色校园亚洲| 欧美视频一区在线| 蜜桃av一区| 国产精品久久午夜夜伦鲁鲁| 免费成人小视频| 欧美日韩一区二区免费在线观看| 欧美制服丝袜| 欧美日韩亚洲视频| 欧美77777| 国产日韩欧美在线观看| 亚洲激情欧美激情| 国语自产精品视频在线看一大j8 | 亚洲最新视频在线| 亚洲国产日韩一区二区| 亚洲免费在线观看视频| 亚洲看片一区| 久久久精品动漫| 香蕉精品999视频一区二区 | 欧美激情亚洲精品| 老司机aⅴ在线精品导航| 国产美女扒开尿口久久久| 91久久久久久国产精品| 在线色欧美三级视频| 亚洲欧美日韩精品久久| 亚洲一区欧美激情| 欧美日韩第一区| 亚洲欧美乱综合| 亚洲一区二区伦理| 亚洲六月丁香色婷婷综合久久| 亚洲午夜精品一区二区| 一本久久综合亚洲鲁鲁五月天| 久久久久五月天| 久久久青草青青国产亚洲免观| 国产精品毛片a∨一区二区三区|国| 亚洲国产一区二区三区青草影视| 伊甸园精品99久久久久久| 久久久久久久久久码影片| 久久不射中文字幕| 国产欧美高清| 小黄鸭精品密入口导航| 欧美一区深夜视频| 国产日韩视频一区二区三区| 羞羞视频在线观看欧美| 久久精品女人的天堂av| 国产亚洲女人久久久久毛片| 久久国产欧美日韩精品| 免费成人网www| 91久久精品视频| 欧美精品亚洲精品| 亚洲免费久久| 篠田优中文在线播放第一区| 国产午夜精品全部视频在线播放| 欧美一区二区在线观看| 蜜桃精品久久久久久久免费影院| 亚洲韩日在线| 国产精品a久久久久| 午夜精品久久久久久久久久久久| 久久精品99国产精品日本| 亚洲国产精品一区| 欧美日韩一区三区四区| 亚洲综合日韩中文字幕v在线| 久久国产精品久久久久久久久久| 韩日在线一区| 欧美乱人伦中文字幕在线| 亚洲婷婷国产精品电影人久久| 久久精品91久久久久久再现| 在线精品视频一区二区三四| 欧美精品一区二区三区在线看午夜| 夜色激情一区二区| 久久国产精品99久久久久久老狼| 一区一区视频| 欧美精品97| 亚洲尤物在线视频观看| 免费观看成人www动漫视频| 亚洲日本一区二区三区| 国产精品久久毛片a| 免费成人你懂的| 欧美亚洲在线| 亚洲精品久久久久久久久| 欧美一级二区| 亚洲精品视频在线| 国产欧美日韩一区二区三区在线观看| 久久一本综合频道| 亚洲一区二区三区涩| 亚洲成色777777在线观看影院| 亚洲一区二区三区影院| 亚洲国产精品久久久久婷婷884| 欧美三级视频| 免费看亚洲片| 久久国产一区| 亚洲欧美福利一区二区| 亚洲美女在线视频| 欧美不卡视频| 久久三级视频| 久久爱另类一区二区小说| 亚洲一区二区三区欧美| 亚洲另类一区二区| 亚洲国产成人在线| 国产精品成人国产乱一区| 国产乱码精品一区二区三区忘忧草| 久久亚洲色图| 欧美在线资源| 校园春色综合网| 亚洲欧美日产图|