![Windows内核编程](https://wfqqreader-1252317822.image.myqcloud.com/cover/230/32375230/b_32375230.jpg)
6.3 一次性申请
在低资源环境下,内核中申请的资源很有可能失败,对于一些逻辑来说,一旦资源申请失败将无法继续往下执行,或者往下执行一定会蓝屏。请看下面这个例子:
![](https://epubservercos.yuewen.com/C31FF1/17493186507061606/epubprivate/OEBPS/Images/txt007_6.jpg?sign=1739140788-n4Wur8sfRajXh1SUYbW99wa4OC1BYIbX-0-e7fe6b26664ba439b58e9dfbb28256b4)
![](https://epubservercos.yuewen.com/C31FF1/17493186507061606/epubprivate/OEBPS/Images/txt007_7.jpg?sign=1739140788-znIRMKdKaMyzh0zwhMJ3R2saJTEO5B4Y-0-73c3054cb6a476fb9f2b90ff861976b0)
请读者思考一下,当驱动需要卸载的时候,当前驱动所创建的线程是否必须停止呢?答案是肯定的,而很多开发者把停止线程的任务放到了驱动的卸载函数,即DriverUnload函数中,如果读者对此知识点有遗忘,请参考本书前面章节。
驱动卸载函数大概是下面这个样子:
![](https://epubservercos.yuewen.com/C31FF1/17493186507061606/epubprivate/OEBPS/Images/txt007_8.jpg?sign=1739140788-f4K9mYYeQFCIorQcGFtg6oeStgNZuVlF-0-d5aaf430f05e4ca1bb5b7d75a89f70f6)
关键的StopTaskThread实现如下:
![](https://epubservercos.yuewen.com/C31FF1/17493186507061606/epubprivate/OEBPS/Images/txt007_9.jpg?sign=1739140788-zHm2WJfbM9hP6R2o69PP8KhlkjZ263gw-0-9f9e4b42cc4707db6fb4e341bc70910a)
![](https://epubservercos.yuewen.com/C31FF1/17493186507061606/epubprivate/OEBPS/Images/txt007_10.jpg?sign=1739140788-PADnF25kUkMF1Saukv9PvMYGOtIxqOm5-0-83925d7fb1b27a467d3aadece66277a2)
上面的代码在绝大部分环境下工作良好,但是一旦发布此驱动,量级到达千万时,就会陆续收到蓝屏投诉。
观察上面的代码,使用了KeWaitForMultipleObjects函数来等待16个线程退出,而这个等待函数本身需要一个非分页的内存块,即代码中的pWaitBlockArrary,试想一下,一旦在非分页内存紧张的情况下,ExAllocatePoolWithTag函数分配失败,那么StopTaskThread函数实际并没有等待线程退出,而在DriverUnLoad函数中,对失败是不可容忍的,系统一旦调用DriverUnLoad函数,意味着驱动马上要被从内存中卸载,这个行为是不可取消的,如果线程没有退出或退出失败,驱动卸载后一定会发生蓝屏。
对于上面的例子,较好的解决方法是在DriverEntry中把KeWaitForMultipleObjects所需要的资源申请好,即“一次性申请”到位。通俗来讲,就是需要把这类情况全部梳理出来,这些内存或资源对于自身驱动来说是“性命攸关”的资源,应该放在DriverEntry中申请,一旦申请失败,驱动DriverEntry也应返回失败。
上面关于内存的例子是一个特例,请读者放眼于所有资源,因为对于系统来说,所有资源的申请都存在失败的概率。