[原创]W2k Driving 学习笔记(一)内核线程及同步
Win32与Kernel交互,从User层向内核发送2个请求:
0 IOCTL_Start_Thread : 从内核新建一个线程,最多建立MAX_THREAD_NUM个线程;
1 IOCTL_Stop_Thread : 关闭刚才建立的所有线程;
每个线程做同样的事,每次将变量Count增加1,使用一个FAST_MUTEX来同步加1操作。
线程过程如下,没什么特别说明的,其中为了照顾偶的眼球眨动频率,特地做了1s的延时。
DDKAPI VOID CountThreadMain(IN PVOID pContext) PDEVICE_EX pDevEx = (PDEVICE_EX)pContext; LARGE_INTEGER dt = RtlConvertLongToLargeInteger(/ -10 * 1000 * 1000); ULONG tid = (ULONG)PsGetCurrentThreadId(); PRINT("[%s]entry new thread[id:%d]",/ __func__,tid); while(!pDevEx- bEXIT_THREADS) ExAcquireFastMutex( pDevEx- FastMtx); ++pDevEx- Count; ExReleaseFastMutex( pDevEx- FastMtx); PRINT("[%s][tid:%d]Now Count is %d/n",/ __func__,tid,pDevEx- Count); if(!NT_SUCCESS(KeDelayExecutionThread(KernelMode,/ false, dt))) PRINT("[%s]err : Delay Failed!/n",__func__); break; PRINT("[%s]exit thread[id:%d]/n",/ __func__,tid); (VOID)PsTerminateSystemThread(STATUS_SUCCESS); }
在退时要注意,在未退出所有线程之前,绝不能Unload Driver,否则线程所在的内存
区将会被Unmap,系统将会发生缺页0x0E异常。我做了一个等待处理:
DDKAPI VOID WaitKillThreads(PDEVICE_OBJECT pDeviceObject) PDEVICE_EX pDevEx = (PDEVICE_EX)pDeviceObject- DeviceExtension; PRINT("[%s]sizeof WAIT_BLOCK is %d/n",__func__,sizeof(KWAIT_BLOCK)); if(pDevEx- CURRENT_THREAD_NUM == 0) return; pDevEx- bEXIT_THREADS = TRUE; PKWAIT_BLOCK pKB = (PKWAIT_BLOCK)ExAllocatePool(/ NonPagedPool,/ sizeof(KWAIT_BLOCK)*pDevEx- CURRENT_THREAD_NUM); if(pKB == NULL) PRINT("[%s]Alloc Mem Failed!/n",__func__); return; if(!NT_SUCCESS(KeWaitForMultipleObjects(/ pDevEx- CURRENT_THREAD_NUM,/ pDevEx- pThreadObjs,WaitAll,/ Executive,KernelMode,TRUE,/ NULL,pKB))) PRINT("[%s]KeWaitForMultipleObjects Failed!/n",/ __func__); ExFreePool((PVOID)pKB); }
原先的WaitKillThreads老是导致系统蓝屏,调试发现只有当建立的线程数超过3个时
才会蓝屏,进一步分析,蓝屏的原因是WaitKillThreads将DrvDispatchControl的
第2个参数pIrp写成了垃圾数据。为什么只有当Thread数大于3时才这样呢?观察
WaitKillThreads中可能会擦写内核栈的只有KeWaitForMultipleObjects的回写操作
(pKB),查阅DDK Helps 之后发现,如果等待的对象 THREAD_WAIT_OBJECTS则,
必须分配 sizeof(KWAIT_BLOCK) * Count 字节的非分页内存让其写入。一查
THREAD_WAIT_OBJECTS大小正好等于3,答案揭晓:
WaitKillThreads在最高优化中是内联编入派遣过程,这意味着它们共用一个函数栈桢,
KWAIT_BLOCK大小为24,则如果线程数大于3则正好溢出覆盖掉pIrp内容,My God!
另外,在编译代码是发现找不到WaitAll或WaitAny的声明,我用的是MinGW(gcc)5.1.4
版本,在winddk.h中发现其将WAIT_TYPE定义成ULONG,将其改为:
typedef enum _WAIT_TYPE WaitAll, WaitAny }WAIT_TYPE;
后建立成功。
带你读《计算机文化》之三:Networks 在全球信息化大潮的推动下,我国的计算机产业发展迅猛,对专业人才的需求日益迫切,而专业教材的建设在教育战略上显得举足轻重,因此,引进一批国外优秀计算机教材将对我国计算机教育事业的发展起到积极的推动作用,也是与世界接轨、建设真正的世界一流大学的必由之路。
第七章--进程调度 本章讨论进程调度(schednling),主要关心什么时候进行进程切换及选择哪一个进程来运行。 一、调度策略 决定什么时候以怎样的方式选择一个新进程运行的这组规则就是所谓的调度策略(scheduling policy)。
第五章--内核同步 内核的各个部分并不是严格按照顺序依次执行的,而是采用交错执行的方式。因此这些请求可能引起竞态条件,而我们必须采用适当的同步机制对这种情况进行控制。 一、内核如何为不同的请求提供服务 把内核看作必须满足两种请求的侍者:一种请求来自顾客,另一种请求来自数量有限的几个不同的老板。
相关文章
- [内核同步]Linux内核同步机制之completion
- [内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析
- Linux - 修改内核启动顺序及删除无用内核
- Linux基础之查看linux发行版以及内核版本
- MySQL内核月报 2015.02-MySQL · 捉虫动态· 变量修改导致binlog错误
- 数据库内核月报 - 2015 / 10-MySQL · 捉虫动态 · start slave crash 诊断分析
- 找对业务G点, 体验酸爽 - PostgreSQL内核扩展指南
- 【华为云技术分享】小熊派IoT开发板华为物联网操作系统LiteOS内核实战教程01-IoT-Studio介绍及安装
- 【Linux 内核】进程管理 task_struct 结构体 ③ ( real_parent 字段 | parent 字段 | group_leader 字段 | real_cred、cred字段 )
- 【Linux 内核】编译 Linux 内核 ⑥ ( 安装 OpenSSL | 安装其它依赖库 | 内核编译完成 )
- LXC linux容器简介——在操作系统层次上为进程提供的虚拟的执行环境,限制其使用的CPU和mem等资源,底层是linux内核资源管理的cgroups子系统
- 【Linux驱动开发100问】如何编译Linux内核?
- 当内核收到了一个网络包