函数的多线程安全性在内核编程中比用户态应用程序的编程更常见。
调用源 | 运行环境 | 原因 |
driverEntry,DriverUnload | 单线程 | 这两个函数由系统进程的单一线程调用,不会出现多线程同时调用 的情况 |
各种分发函数 | 多线程 | 分发函数有可能并发,也可能和DriverUnload并发 |
完成函数 | 多线程 | 完成函数随时可能被未知的线程调用 |
各种NDIS回调函数 | 多线程 | 同上 |
中断级
先简单理解passive级和Dispatch级两种,后者比前者级高,在实际编程中,许多具有比较复杂功能的内核API都要求必须在Passive级执行。
只有比较简单的函数能在Dispatch级执行。调用任何一个内核API之前,必须查看WDK文档,这个内核API的中断级要求。
调用源 | 一般的运行中断级 |
DriverEntry,DriverUnload | Passive |
分发函数 | Passive |
完成函数 | Dispatch |
NDIS回调函数 | Dispatch |
WDK中出现的特殊代码
1.参数说明宏,只是说用来说明参数的一些信息,一般都是空宏,最常见的是IN和OUT。定义如下
#define IN
#define OUT
2.指定函数位置的预编译指令
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,NdisProtUnload)
这个宏仅仅用用来指定某个函数的可执行代码在编译出来后在sys文件中的位置。
PE的文件结构分成节,不同的节被加载到内在中之后处理情况不同,
INIT节的特点是被初始化完毕之后就被释放。也就不再占用内存空间了。函数DriverEntry可以在这个阶段执行一次,因此这个函数一般用#pragma alloc_text(INIT,DriverEntry)使之位于INIT节。
Page节的特点是位于可以分页交换的内存空间,这些空间在内存紧张时可以被交换到硬盘上以节省内存。
如果未用上述的预编译指令处理,则代码默认位于PAGELK节,加载后位于不可分页交换的内存空间。
需要注意的是,放在PAGE节的函数不可以在Dispatch级调用,因为这种函数的调用可能诱发缺页中断,但是缺页中断不能在Dispatch级完成。