25、Windows驱动程序的同步处理(1)

简介: 驱动程序的同步处理 可重入,是指函数的执行结果不和执行顺序有关。同步机制很大程度上依赖于中断请求级。 IRQ编号 设备名称 用途 IRQ0 Tine 计算机系统计时器 IRQ1 KeyBoard 键盘...

驱动程序的同步处理

可重入,是指函数的执行结果不和执行顺序有关。同步机制很大程度上依赖于中断请求级。

IRQ编号

设备名称

用途

IRQ0

Tine

计算机系统计时器

IRQ1

KeyBoard

键盘

IRQ2

RedirectI RQ9

IRQ9相接,MPU-401 MDI使用该IRQ

IRQ3

COM2

串口设备

IRQ4

COM1

串口设备

IRQ5

LPT2

建议声卡使用该IRQ

IRQ6

FDD

软驱传输控制用

IRQ7

LPT1

打印机传输控制用

IRQ8

CMOSAlert

即时时钟

IRQ9

RedirectI RQ2

IRQ2相接。可设定给其他硬件使用

IRQ10

Reversed

建议保留给网卡使用该IRQ

IRQ11

Reversed

建议保留给AGP显卡使用

IRQ12

PS/2 Mouse

PS/2鼠标,若无也可以设定给其他硬件使用

IRQ13

FPU

协处理器用,例如FPU(浮点运算器)

IRQ14

Primary IDE

主硬盘传输控制用

IRQ15

Secondary lde

从硬盘传输控制用

PIC中断向量 P220

APIC 高级PIC(Programmable interrupt controller),共24个中断。

1、中断请求级

1)基本概念

Windows 把中断请求级IRQL分成了32个,02级别为软件中断,331级为硬件中断。031优先级别逐步递增。硬件中断请求级别称为设备中断请求级 DIRQLWindows大部分时间运行在软件中断请求级中。当设备中断来临时,操作系统提升IRQLDIRQL,并运行中断处理函数。当中断处理函数结束后,操作系统把IRQL降到原来的级别。

clip_image001

IRQL P222

用户模式的代码是运行在最低优先级的passive_level;驱动程序的DriveEntry函数,派遣函数,AddDevice等函数一般都运行在PASSIVE_LEVEL级别,在必要时申请进入DISPATCH_LEVEL级别。

Windows 负责线程调度的组件运行在DISPATCH_LEVEL级别。当前线程运行完毕后,系统自动从PASSIVE_LEVEL提升到 DISPATCH_LEVEL级别,当切换完毕后,操作系统又从DISPATCH_LEVEL降回到PASSIVE_LEVEL级别。

驱动程序的StartIO函数和DPC(deferred procedure call)函数,中断服务例程也运行在DISPATCH_LEVEL级别。

线程运行在PASSIVE_LEVEL级别。如果提升到DISPATCH_LEVEL级别,则不会发生线程的切换,这是一种很常见的同步处理机制。

页故障允许在PASSIVE_LEVEL级别(出现页故障时,调用缺页机制,进行物理内存和磁盘文件进行切换),如果在DISPATCH_LEVEL或更高级别,则系统崩溃。对于DISPATCH_LEVEL或更高级别程序必须使用非分页内存。

2)控制IRQL提升与降低

主要用几个函数:

KeGetCurrentIrql

KeRaiseIrql

KeLowerIrql

 

 
 
1 VOID RasieIRQL_Test()
2 {
3 KIRQL oldirql;
4 ASSERT(keGetCurrentIrql() <= DISPATCH_LEVEL);
5 keRaiseIrql(DISPATCH_LEVEL, & oldirql);
6 // ...
7   kelowrIrql(oldirql);
8 }

 

示例程序 P224

2、自旋锁

同步处理机制。不同于线程中的等待事件;操作系统会把等待某一个事件的线程处于休眠状态,CPU运行其它线程;而自旋锁不会切换到其它线程,而是让这个线程一直自旋等待。所谓自旋,就是一直不停的询问:是否可以获取自旋锁。

在单CPU中,获取自旋锁仅仅是将当前的IRQLPASSIVE_LEVEL级别升到DISPATCH_LEVEL级别,多CPU中要复杂一点。驱动程序必须在不大于DISPATCH_LEVEL级别中使用自旋锁。

自旋锁一般作用是为各派遣函数实现间同步。尽量不要把自旋锁放在全局变量中,而应当把自旋锁放在设备扩展里。

示例 参见http://www.cnblogs.com/mydomain/archive/2010/10/18/1855118.html

KeAcquireSpinLock

KeInitializeSpinLock

KeAcquireSpinLockAtDpcLevel

3、用户模式下的同步对象

同步对象包括事件,互斥体,信号灯等。用户模式下的同步对象是对内核模式下的同步对象的再封装。

1)等待

WaitForSingleObject

WaitForMultipleObjects

2)开启多线程

CreateThread

[1]中推荐_beginthread

http://msdn.microsoft.com/en-us/library/kdzttdcb%28VS.80%29.aspx

3)事件

典型的同步对象。

CreateEvent

所有形如CreateXXXWin32 API,如果第一个参数是lpEventAttributes,则这种API内部都会创建一个相应的内核对象;这种API返回一个句柄(32位无符号整数),OS通过这个句柄找到具体的内核对象。

 

#include "windows.h"
#include "process.h"
#include "stddef.h"
#include "conio.h"

UNIT WINAPI Thread1(LPVOID para)
{
	printf("Enter Thread\n");
	HANDLE *phEvent = (HANDLE*)para;
	SetEvent(*phEvent);
	printf("Leave Thread1\n");
	return 0;
}

int main()
{
	HANDLE hEvent = CreateEvent(NULL, 0, FALSE, NULL);
	HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, Thread1, &hEvent, 0, NULL);
	WaitForSingleObject(hEvent, INFINITE);
	return 0;
}

示例代码 P228

4)信号灯

常见的同步对象。

一般同步对象有两种状态:激发状态和未激发状态。

信号灯有个计数器,代表N个灯,只要有一个灯亮着,就说明处于激发状态。

HANDLE CreateSemaphore(

LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD

LONG lInitialCount, // initial count

LONG lMaximumCount, // maximum count

LPCTSTR lpName // object name

);

lInitialCount ,如果初始值大于0,则处理激发状态。

ReleaseSemaphore

对信号灯执行一次等待操作,减少一个读数,相当于熄灭一个灯泡。

 

代码
 
  
1 #include " windows.h "
2 #include " process.h "
3 #include " stdio.h "
4
5 UINT WINAPI Thread1(LPVOID para)
6 {
7 printf( " Enter Thread1\n " );
8 HANDLE * hSemaphore = (HANDLE * )para;
9 Sleep( 5000 );
10 printf( " Leave Thread1\n " );
11 ReleaseSemaphore( * hSemaphore, 1 , NULL);
12 return 0 ;
13 }
14   int main()
15 {
16 HANDLE hSemaphore = CreateSemaphore(NULL, 2 , 2 , NULL);
17 WaitForSingleObject(hSemaphore, INFINITE);
18 WaitForSingleObject(hSemaphore, INFINITE);
19 HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0 , Thread1, & hSemaphore, 0 , NULL);
20 WaitForSingleObject(hSemaphore, INFINITE);
21 }

 

示例代码 P229

5)互斥体

用互斥体来避免多个线程使用一个资源。互斥体类似于同步事件;不同的是同一个线程可以递归获得互斥体,而同步事件不能。

如果线程获得互斥体时,互斥体此时的状态是未激发(nonsignaled),而释放互斥体时,互斥体的状态为激发态。

激发有点拗口,就是signaled,也就是接到了信号了。激发与未激发,都是相对于其它线程而言的。

CreateMutex

 

代码
 
  
1 #include " windows.h "
2 #include " process.h "
3 #include " stdio.h "
4
5 UINT WINAPI Thread1(LPVOID para)
6 {
7 HANDLE * phMutex = (HANDLE * )para;
8 WaitForSingleObject(phMutex, INFINITE);
9 WaitForSingleObject(phMutex, INFINITE); // 对于同一个线程,可以获得多次
10  
11 printf( " Enter Thread1\n " );
12 Sleep( 5000 );
13 printf( " Leave Thread1\n " );
14 ReleaseMutex( * phMutex);
15 return 0 ;
16 }
17
18 UINT WINAPI Thread2(LPVOID para)
19 {
20 HANDLE * phMutex = (HANDLE * )para;
21 WaitForSingleObject(phMutex, INFINITE);
22 WaitForSingleObject(phMutex, INFINITE); // 对于同一个线程,可以获得多次
23  
24 printf( " Enter Thread2\n " );
25 Sleep( 5000 );
26 printf( " Leave Thread2\n " );
27 ReleaseMutex( * phMutex);
28 return 0 ;
29 }
30
31 int main()
32 {
33 HANDLE hMutex = CreateMutex(NULL, NULL, NULL);
34 WaitForSingleObject(hSemaphore, INFINITE);
35 WaitForSingleObject(hSemaphore, INFINITE);
36 HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0 , Thread1, & hMutex, 0 , NULL);
37 HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0 , Thread2, & hMutex, 0 , NULL);
38 Sleep( 5000 );
39 return 0 ;
40 }

 

示例代码 P230

6)等待线程完成

线程对象。每个对象同样有两种状态:运行之中时为未激发,当终止时为激发状态。

 

代码
 
  
1 #include " windows.h "
2 #include " process.h "
3 #include " stdio.h "
4
5 UINT WINAPI Thread(LPVOID para)
6 {
7 printf( " Enter Thread2\n " );
8 Sleep( 5000 );
9 return 0 ;
10 }
11
12 int main()
13 {
14 HANDLE hThread[ 2 ];
15 WaitForSingleObject(hSemaphore, INFINITE);
16 WaitForSingleObject(hSemaphore, INFINITE);
17 hThread[ 0 ] = (HANDLE)_beginthreadex(NULL, 0 , Thread, & hMutex, 0 , NULL);
18 hThread[ 1 ] = (HANDLE)_beginthreadex(NULL, 0 , Thread, & hMutex, 0 , NULL);
19 WaitForMultipleObjects( 2 , hThread, TRUE, INFINITE);
20 return 0 ;
21 }

 

示例代码 P232

目录
相关文章
|
3月前
|
存储 Shell Windows
安装OSX和Windows双系统以后系统时间不同步的问题
安装OSX和Windows双系统以后系统时间不同步的问题
41 0
|
安全 IDE KVM
[ 云计算相关 ] KVM虚拟化平台windows虚拟机迁移到openstack虚拟化平台(KVM虚拟化环境中Windows虚拟机安装Virtio驱动程序)
KVM虚拟化平台windows虚拟机迁移到openstack虚拟化平台(KVM虚拟化环境中Windows虚拟机安装Virtio驱动程序) 因为这也不是我的本职工作,只是这次恰巧碰到了,帮着解决了以下,我就没深究原理了,问我原理可能我也不知道,只是这个操作步骤吧,亲测有效。
454 0
[ 云计算相关 ] KVM虚拟化平台windows虚拟机迁移到openstack虚拟化平台(KVM虚拟化环境中Windows虚拟机安装Virtio驱动程序)
|
2月前
|
Java 数据库连接 数据库
Windows7 64位 连接Access数据库“未发现数据源名称并且未指定默认驱动程序“的解决办法
Windows7 64位 连接Access数据库“未发现数据源名称并且未指定默认驱动程序“的解决办法
|
6月前
|
缓存 Java 分布式数据库
[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O
[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O
|
9月前
|
Linux API 开发工具
Windows NT 驱动程序的编译、安装、调试
Windows 驱动分为两类,一类是从 Windows NT 遗留下来的驱动模型称为传统的 Windows NT 驱动程序模型,另一类是 Windows 添加了电源管理后的 KMDF (WDM)驱动程序。本文这里首先以最简单的 Windows NT 驱动模型为例介绍 Windows 驱动的简单编写、编译、安装及调试。
168 0
|
10月前
|
缓存 安全 Unix
C/C++使用Windows的API实现共享内存以及同步
C/C++使用Windows的API实现共享内存以及同步
763 0
|
缓存 Java Shell
[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O
Windows核心编程《九》同步设备I/O和异步设备I/O
149 0
[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O
|
API C++ Windows
windows环境下线程编程(C++实现同步与互斥)
Windows系统为我们提供了相关API,我们可以使用他们来进行多线程编程。
成功解决⑧NVIDIA安装程序无法继续 此NVIDL驱动程序与此Windows版本不兼容。 此图形驱动程序无法找到兼吝的图形硬件。
成功解决⑧NVIDIA安装程序无法继续 此NVIDL驱动程序与此Windows版本不兼容。 此图形驱动程序无法找到兼吝的图形硬件。
成功解决⑧NVIDIA安装程序无法继续 此NVIDL驱动程序与此Windows版本不兼容。 此图形驱动程序无法找到兼吝的图形硬件。
|
存储 数据安全/隐私保护 Windows
小技巧 - 同步苹果手机和 Windows 的提醒事项
小技巧 - 同步苹果手机和 Windows 的提醒事项
659 0
小技巧 - 同步苹果手机和 Windows 的提醒事项