本文轉(zhuǎn)自
Hanke空間,原文地址:
http://hi.baidu.com/hankebao/blog/item/7e8329804e0ce9d2bc3e1e2b.html---------
在Windows分層驅(qū)動模型中,設(shè)備棧中的設(shè)備一般都是通過對上層傳來的IRP做相應(yīng)的處理來實現(xiàn)驅(qū)動的功能。這里對常用的幾種IRP傳遞及完成的方式進行歸納和總結(jié):
1. 在本層驅(qū)動中完成1.1 在本層驅(qū)動中以
同步方式完成
在本層同步完成一般做完相應(yīng)處理后,設(shè)置Irp->IoStatus.Status和Irp->IoStatus.Information,調(diào)用IoCompleteRequest完成該IRP,return IRP的完成狀態(tài)即可。
1.2 在本層驅(qū)動中以異步方式完成
在本層異步完成一般是得到IRP后將其
入隊/起線程另行處理,同時調(diào)用IoMarkIrpPending
將該IRP標記為Pending,之后即可return STATUS_PENDING。此時該
IRP并未真正完成,需待未決的操作在他處完成后調(diào)用IoCompleteRequest才真正完成。
2. 轉(zhuǎn)發(fā)至下層驅(qū)動2.1 本層不作處理
有時對于某些IRP,本層驅(qū)動不需要做任何處理。此時可調(diào)用
IoSkipCurrentIrpStackLocation跳過當前設(shè)備棧,然后調(diào)用
IoCallDriver將IRP轉(zhuǎn)發(fā)至下層驅(qū)動,并將轉(zhuǎn)發(fā)的結(jié)果直接返回。此種處理方式并
不需要關(guān)心下層驅(qū)動處理IRP的方式究竟是同步還是異步。IRP轉(zhuǎn)發(fā)至下層后就與己無關(guān)了。
2.2 同步轉(zhuǎn)發(fā)方式
有時IRP在本層無法直接處理,需要將其轉(zhuǎn)發(fā)至下層,
待下層處理完后在其結(jié)果上進行修改再將其返回(和上面矛盾?)。這時可以采用同步轉(zhuǎn)發(fā)方式進行處理。首先在相應(yīng)
dispatch routine中初始化一個未激發(fā)的event,調(diào)用
IoCopyCurrentIrpStackLocationToNext將本層設(shè)備棧參數(shù)復(fù)制到下層。然后設(shè)置一個
CompletionRoutine,將剛才
初始化過的event作為context傳給它。之后調(diào)用
IoCallDriver轉(zhuǎn)發(fā)IRP至下層,并判斷
返回值是否為STATUS_PENDING。
是則wait之前的event。
在CompletionRoutine中判斷該IRP是否PendingReturned,是則說明之前IoCallDriver返回了STATUS_PENDING,于是
激發(fā)event。
CompletionRoutine返回STATUS_MORE_PROCESSING_REQUIRED使我們的
dispatch routine重新取得對該IRP的控制權(quán)。本層dispatch等待結(jié)束再次獲得控制權(quán)后,進行相應(yīng)處理,之后需
再次調(diào)用IoCompleteRequest完成該IRP。
同步轉(zhuǎn)發(fā)是驅(qū)動中常用的一種IRP處理方式。一般會將本層dispatch轉(zhuǎn)發(fā)IRP至下層并等待CompletionRoutine激發(fā)event的行為獨立成一個ForwardIrpSynchronous的函數(shù)。幾個dispatch只需一個ForwardIrpSynchronous,代碼相對簡單。
注意不要在本層dispatch中調(diào)用IoMarkIrpPending,因為上層的請求在本層被同步處理了。在同步轉(zhuǎn)發(fā)中,如果下層驅(qū)動也采用同步方式處理,則本層dispatch不會(也不需要)wait,IoCallDriver返回時CompletionRoutine已經(jīng)被調(diào)用,性能上也沒有什么損失。
2.3 異步轉(zhuǎn)發(fā)方式
異步轉(zhuǎn)發(fā)也能在下層驅(qū)動完成IRP時獲得處理的機會,其主要是采用了異步處理機制。首先本層dispatch調(diào)用IoCopyCurrentIrpStackLocationToNext將本層設(shè)備棧參數(shù)復(fù)制到下層,設(shè)置相應(yīng)的CompletionRoutine,然后調(diào)用IoCallDriver將IRP轉(zhuǎn)發(fā)至下層驅(qū)動,并
將轉(zhuǎn)發(fā)的結(jié)果直接return給上層調(diào)用者。在
CompletionRoutine中再判斷該IRP是否PendingReturned,是則需要調(diào)用IoMarkIrpPending。之后可對下層驅(qū)動處理該IRP的結(jié)果進行相應(yīng)操作。
最后返回STATUS_CONTINUE_COMPLETION(同STATUS_SUCCESS)。異步轉(zhuǎn)發(fā)在異步處理時性能最佳,但處理的邏輯放在了CompletionRoutine中,因此多個dispatch需要編寫多個CompletionRoutine。而同步轉(zhuǎn)發(fā)往往幾個dispatch只需一個ForwardIrpSynchronous即可,代碼相對簡單。
值得注意的是,各個dispatch routine運行的IRQL是由調(diào)用關(guān)系決定的。如果上層調(diào)用者有運行在DISPATCH_LEVEL的可能,則本層的dispatch也需要按照運行在DISPATCH_LEVEL來設(shè)計。比如傳遞至本層dispatch的IRP是在上層驅(qū)動的StartIO例程中轉(zhuǎn)發(fā)的,則本層處理該類IRP的代碼就可能運行在DISPATCH_LEVEL。