Windows NT 驅動程序開發人員提示 -- 應注意避免的事項

原討論鏈接: http://community.csdn.net/expert/topicview1.asp?id=4738353 所屬論壇: 硬件/系統 審覈組: VC/MFC 提問者: codewarrior 解決者: codewarrior

1. 一定不要在沒有標註 I/O 請求數據包 (IRP) 掛起 (IoMarkIrpPending) 的情況下通過調度例程返回 STATUS_PENDING。  
2. 一定不要通過中斷服務例程 (ISR) 調用 KeSynchronizeExecution。 它會使系統死鎖。  
3. 一定不要將 DeviceObject->Flags 設置爲 DO_BUFFERED_IO 和 DO_DIRECT_IO。 它會擾亂系統並最終導致致命錯誤。 而且,一定不要在 DeviceObject->Flags 中設置 METHOD_BUFFERED、METHOD_NEITHER、METHOD_IN_DIRECT 或 METHOD_OUT_DIRECT,因爲這些值只在定義 IOCTL 時使用。  
4. 一定不要通過頁面緩衝池分配調度程序對象。 如果這樣做,將會偶爾導致系統故障檢測 (Bugcheck)。  
5. 當運行於 IRQL >= DISPATCH_LEVEL 時,一定不要通過頁面緩衝池分配內存,或訪問頁面緩衝池中的內存。 這是一個致命錯誤。  
6. 一定不要在 IRQL >= DISPATCH_LEVEL 上等候核心調度程序對象出現非零間隔。 這是一個致命錯誤。  
7. 在 IRQL >= DISPATCH_LEVEL 上執行時,一定不要調用任何導致調用線程發生直接或間接等待的函數。 這是一個致命錯誤。  
8. 一定不要把中斷請求級別 (IRQL) 降低到低於您的頂級例程被調用的級別。  
9. 如果沒有調用過 KeRaiseIrql(),則一定不要調用 KeLowerIrql()。  
10. 一定不要使處理器 (KeStallExecutionProcessor) 停止運轉的時間超過 50 微秒。  
11. 一定不要使旋轉鎖 (Spin Lock) 保持鎖定狀態的時間超過您的需要。 要使系統獲得更好的總體性能,請不要使任何系統範圍內有效的旋轉鎖的鎖定時間超過 25 微秒。  
12. 當 IRQL 大於 DISPATCH_LEVEL 時,一定不要調用 KeAcquireSpinLock 和 KeReleaseSpinLock,或 KeAcquireSpinLockAtDpcLevel 和 KeReleaseSpinLockFromDpcLevel。  
13. 一定不要通過調用 KeReleaseSpinLockFromDpcLevel 來釋放 KeAcquireSpinLock 所獲取的旋轉鎖,因爲這會使原始 IRQL 無法被還原。  
14. 一定不要在 ISR 或 SynchCritSection 例程中調用 KeAcquireSpinLock 和 KeReleaseSpinLock 或者其它任何使用可執行旋轉鎖的例程。  
15. 當您在例程中而不是在 DriverEntry 中創建設備對象時,一定不要忘記清除 DO_DEVICE_INITIALIZING 標記。  
16. 一定不要同時在不同處理器的多個線程中將延時過程調用 (DPC) 對象添加到隊列中(使用 KeInsertQueueDpc)。 這會導致致命錯誤。  
17. 一定不要通過 CutomerTimerDPC 例程釋放週期定時器。 您可以通過 DPC 例程釋放非週期定時器。  
18. 一定不要將相同的 DPC 指針傳遞給 KeSetTimer,或者 KeSetTimerEx (CustomTimerDpc) 和 KeInsertQueueDpc (CustomDpc),因爲這將導致競爭。  
19. 旋轉鎖鎖定時,一定不要調用 IoStartNextPacket。 這將使系統死鎖。  
20. 旋轉鎖鎖定時,一定不要調用 IoCompleteRequest。 這將使系統死鎖。  
21. 如果您的驅動程序設置了完成例程,那麼一定不要在沒有把完成例程設置爲 NULL 的情況下調用 IoCompleteRequest。  
22. 調用 IoCompleteRequest 之前,一定不要忘記設置 IRP 中的 I/O 狀態區。  
23. 在將 IRP 添加到隊列中或將它發送到另一個驅動程序 (IoCallDriver) 之後,一定不要調用 IoMarkPending。 在驅動程序調用 IoMarkPending 之前,IRP 可能已經完成,由此可能發生故障檢測。 對於包含完成例程的驅動程序,如果設置了 Irp->PendingReturned,則完成例程必須調用 IoMarkPending。  
24. 一定不要在已經對某個 IRP 調用 IoCompleteRequest 之後再去訪問該 IRP。  
25. 一定不要對不屬於您的驅動程序的 IRP 調用 IoCancelIrp,除非您知道該 IRP 還沒有完成。  
26. 在您的調度例程返回到調用者之前,一定不要對您的調度例程正在處理的 IRP 調用 IoCancelIrp。  
27. 一定不要從中間驅動程序調用 IoMakeAssociatedIrp 來爲較低的驅動程序創建 IRP。 在中間驅動程序中所獲得的 IRP 可能是已被關聯的 IRP,而您不能將其它 IRP 關聯到已經被關聯的 IRP。  
28. 一定不要對使用緩衝 I/O 而設置的 IRP 調用 IoMakeAssociatedIrp。  
29. 一定不要簡單地將指向設備 I/O 寄存器的虛擬指針解除引用並訪問這些指針。 始終使用正確的硬件抽象層 (HAL) 函數來訪問設備。  
30. 如果 IRP 或設備對象可能在 DISPATCH 級別被修改,那麼一定不要通過 ISR 來訪問 它。 在對稱多處理器系統中,這會造成數據損壞。  
31. 正在高級 IRQL 中運行時,如果數據可能被低級 IROL 代碼寫入,那麼一定不要修改該數據。 應當使用 KeSynchronizeExecution 例程。  
32. 在獲取系統範圍的取消旋轉鎖 (IoAcquireCancelSpinLock) 之前,一定不要在您的 DispatchCleanup 例程中獲取驅動程序自己的旋轉鎖(如果有的話)。 要避免可能出現的死鎖,一定要在驅動程序中遵循一致的鎖定獲取層次結構。  
33. 一定不要在取消例程中調用 IoAcquireCancelSpinLock,因爲該例程被調用時已經獲取了系統級的取消旋轉鎖。  
34. 在從取消例程返回之前,一定不要忘記調用 IoReleaseCancelSpinLock。  
35. 一定不要使用基於 IRQL 的同步,因爲它只對單處理器系統有效。 提高單處理器上的 IRQL 將不會掩蔽在其它處理器上的中斷。  
36. 一定不要對重疊的內存地址範圍使用 RtlCopyMemory。 應當使用 RtlMoveMemory。  
37. 一定不要假定頁面大小是常量,即使是用於給定的 CPU。 爲了保持可移植性,應當使用 PAGE_SIZE 以及在頭文件中所定義的其它頁面相關常量。  
38. 一定不要從引導\系統初始化階段加載的驅動程序的 DriverEntry 例程中訪問除 Registry\Machine\Hardware 和 Registry\Machine\System 以外的任何註冊表項。  
39. 一定不要爲了加載驅動程序而在驅動程序的註冊表項 (Registry\Machine\System\CurrentControlSet\Services) 下創建 Enum 項。 系統將動態地創建該項。  
40. 如果沒有先在註冊表中申請必需的與總線相關的 I/O 端口、內存範圍、中斷或直接內存訪問 (DMA) 通道/端口等硬件資源,一定不要初始化物理設備。  
41. 一定不要在您的 DriverEntry 例程調用 IoRegisterDriverReinitialization,除非重初始化例程返回了 STATUS_SUCCESS。  
42. IRQL 爲 PASSIVE_LEVEL 時,一定不要從被頁面調度的線程或驅動程序例程中在 Wait 參數被設置爲 TRUE 的情況下調用 KeSetEvent。 如果碰巧在調用 KeSetEvent 和 KeWait..Object(s) 之間您的例程被頁面調度出去,這類調用就會導致致命的頁面錯誤。  
43. 與上例相同的條件下,同樣不能調用 KeReleaseSemaphore 。  

在一般情況下,某事物個體發生具有其特有屬性的負面現象,且無法以科學的角度得到合理有效的解釋。我們 通常稱此類現象爲“人品問題”(RPWT)。
                                               ——摘自《辭海》第314頁

發佈了53 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章