28、Windows内核编程,IRP的同步(2)

3StartIo例程

1)系统处理的StartIo

StartIo例程能够保证各个并行的IRP顺序执行,即串行化。

DDK提供一个内部队列,并将IRPStartIo例程串行化处理。当设备由忙转入空闲状态时,从队列中抽取一个IRP进行处理,并将状态设为忙。一个新的IRP来时,如果设备为忙,则插入到队列当中,如果为空闲,则直接处理。

OS提供kdevice_queue来实现串行化,队列头保存在pDriverObject->DeviceQueue子域中。插入和删除由OS负责。使用这个队列时,需要提供一个叫做StartIo的例程。

pDriverObject->DriverStartIo = HelloDDKStartIO;

这个StartIo例程运行在DISPATCH_LEVEL,不会线程打断的,所以不可分页。派遣函数加入IoStartPacket,就可以把IRP插入到队列中了,这样把IRP实现串行化。IoStartPacket还可以指定取消例程。一般,队列操作从尾部插入,从首部删除。在StartIo例程结束前,应该调用IoStartNextPacket(从队列中抽取下一个IRP,作为参数调用StartIo例程)。

28、Windows内核编程,IRP的同步(2) 代码
   
     
1 // .cpp
2  
3 #include " Driver.h "
4
5
6   #pragma LOCKEDCODE
7 VOID
8 HelloDDKStartIO(
9 IN PDEVICE_OBJECT DeviceObject,
10 IN PIRP Irp
11 )
12 {
13 KIRQL oldirql;
14 KdPrint(( " Enter HelloDDKStartIO\n " ));
15
16 // 获取cancel自旋锁
17 IoAcquireCancelSpinLock( & oldirql);
18 if (Irp != DeviceObject -> CurrentIrp || Irp -> Cancel)
19 {
20 // 如果当前有正在处理的IRP,则简单的入队列,并直接返回
21 // 入队列的工作由系统完成,在StartIO中不用负责
22 IoReleaseCancelSpinLock(oldirql);
23 KdPrint(( " Leave HelloDDKStartIO\n " ));
24 return ;
25 } else
26 {
27 // 由于正在处理该IRP,所以不允许调用取消例程
28 // 因此将此IRP的取消例程设置为NULL
29 IoSetCancelRoutine(Irp,NULL);
30 IoReleaseCancelSpinLock(oldirql);
31 }
32
33 KEVENT event ;
34 KeInitializeEvent( & event ,NotificationEvent,FALSE);
35
36 // 等3秒
37 LARGE_INTEGER timeout;
38 timeout.QuadPart = - 3 * 1000 * 1000 * 10 ;
39
40 // 定义一个3秒的延时,主要是为了模拟该IRP操作需要大概3秒左右时间
41 KeWaitForSingleObject( & event ,Executive,KernelMode,FALSE, & timeout);
42
43 Irp -> IoStatus.Status = STATUS_SUCCESS;
44 Irp -> IoStatus.Information = 0 ; // no bytes xfered
45 IoCompleteRequest(Irp,IO_NO_INCREMENT);
46
47
48 // 在队列中读取一个IRP,并进行StartIo
49 IoStartNextPacket(DeviceObject,TRUE);
50
51 KdPrint(( " Leave HelloDDKStartIO\n " ));
52 }
53
54 /* ***********************************************************************
55 * 函数名称:DriverEntry
56 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
57 * 参数列表:
58 pDriverObject:从I/O管理器中传进来的驱动对象
59 pRegistryPath:驱动程序在注册表的中的路径
60 * 返回 值:返回初始化驱动状态
61 ************************************************************************ */
62 #pragma INITCODE
63 extern " C " NTSTATUS DriverEntry (
64 IN PDRIVER_OBJECT pDriverObject,
65 IN PUNICODE_STRING pRegistryPath )
66 {
67 NTSTATUS status;
68 KdPrint(( " Enter DriverEntry\n " ));
69
70 // 设置卸载函数
71 pDriverObject -> DriverUnload = HelloDDKUnload;
72
73 // 设置派遣函数
74 pDriverObject -> MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
75 pDriverObject -> MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
76 pDriverObject -> MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
77 pDriverObject -> MajorFunction[IRP_MJ_READ] = HelloDDKRead;
78 pDriverObject -> MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
79 pDriverObject -> MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
80 pDriverObject -> MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
81 pDriverObject -> MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
82 pDriverObject -> MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
83
84 // 设置StartIO例程
85 pDriverObject -> DriverStartIo = HelloDDKStartIO;
86
87 // 创建驱动设备对象
88 status = CreateDevice(pDriverObject);
89
90 KdPrint(( " Leave DriverEntry\n " ));
91 return status;
92 }
93
94 /* ***********************************************************************
95 * 函数名称:CreateDevice
96 * 功能描述:初始化设备对象
97 * 参数列表:
98 pDriverObject:从I/O管理器中传进来的驱动对象
99 * 返回 值:返回初始化状态
100 ************************************************************************ */
101 #pragma INITCODE
102 NTSTATUS CreateDevice (
103 IN PDRIVER_OBJECT pDriverObject)
104 {
105 NTSTATUS status;
106 PDEVICE_OBJECT pDevObj;
107 PDEVICE_EXTENSION pDevExt;
108
109 // 创建设备名称
110 UNICODE_STRING devName;
111 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevice " );
112
113 // 创建设备
114 status = IoCreateDevice( pDriverObject,
115 sizeof (DEVICE_EXTENSION),
116 & (UNICODE_STRING)devName,
117 FILE_DEVICE_UNKNOWN,
118 0 , TRUE,
119 & pDevObj );
120 if ( ! NT_SUCCESS(status))
121 return status;
122
123 pDevObj -> Flags |= DO_BUFFERED_IO;
124 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
125 pDevExt -> pDevice = pDevObj;
126 pDevExt -> ustrDeviceName = devName;
127
128 // 创建符号链接
129 UNICODE_STRING symLinkName;
130 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDK " );
131 pDevExt -> ustrSymLinkName = symLinkName;
132 status = IoCreateSymbolicLink( & symLinkName, & devName );
133 if ( ! NT_SUCCESS(status))
134 {
135 IoDeleteDevice( pDevObj );
136 return status;
137 }
138 return STATUS_SUCCESS;
139 }
140
141 /* ***********************************************************************
142 * 函数名称:HelloDDKUnload
143 * 功能描述:负责驱动程序的卸载操作
144 * 参数列表:
145 pDriverObject:驱动对象
146 * 返回 值:返回状态
147 ************************************************************************ */
148 #pragma PAGEDCODE
149 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
150 {
151 PDEVICE_OBJECT pNextObj;
152 KdPrint(( " Enter DriverUnload\n " ));
153 pNextObj = pDriverObject -> DeviceObject;
154 while (pNextObj != NULL)
155 {
156 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
157 pNextObj -> DeviceExtension;
158
159 // 删除符号链接
160 UNICODE_STRING pLinkName = pDevExt -> ustrSymLinkName;
161 IoDeleteSymbolicLink( & pLinkName);
162
163 pNextObj = pNextObj -> NextDevice;
164 IoDeleteDevice( pDevExt -> pDevice );
165 }
166 }
167
168 /* ***********************************************************************
169 * 函数名称:HelloDDKDispatchRoutin
170 * 功能描述:对读IRP进行处理
171 * 参数列表:
172 pDevObj:功能设备对象
173 pIrp:从IO请求包
174 * 返回 值:返回状态
175 ************************************************************************ */
176 #pragma PAGEDCODE
177 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
178 IN PIRP pIrp)
179 {
180 KdPrint(( " Enter HelloDDKDispatchRoutin\n " ));
181
182 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
183 // 建立一个字符串数组与IRP类型对应起来
184 static char * irpname[] =
185 {
186 " IRP_MJ_CREATE " ,
187 " IRP_MJ_CREATE_NAMED_PIPE " ,
188 " IRP_MJ_CLOSE " ,
189 " IRP_MJ_READ " ,
190 " IRP_MJ_WRITE " ,
191 " IRP_MJ_QUERY_INFORMATION " ,
192 " IRP_MJ_SET_INFORMATION " ,
193 " IRP_MJ_QUERY_EA " ,
194 " IRP_MJ_SET_EA " ,
195 " IRP_MJ_FLUSH_BUFFERS " ,
196 " IRP_MJ_QUERY_VOLUME_INFORMATION " ,
197 " IRP_MJ_SET_VOLUME_INFORMATION " ,
198 " IRP_MJ_DIRECTORY_CONTROL " ,
199 " IRP_MJ_FILE_SYSTEM_CONTROL " ,
200 " IRP_MJ_DEVICE_CONTROL " ,
201 " IRP_MJ_INTERNAL_DEVICE_CONTROL " ,
202 " IRP_MJ_SHUTDOWN " ,
203 " IRP_MJ_LOCK_CONTROL " ,
204 " IRP_MJ_CLEANUP " ,
205 " IRP_MJ_CREATE_MAILSLOT " ,
206 " IRP_MJ_QUERY_SECURITY " ,
207 " IRP_MJ_SET_SECURITY " ,
208 " IRP_MJ_POWER " ,
209 " IRP_MJ_SYSTEM_CONTROL " ,
210 " IRP_MJ_DEVICE_CHANGE " ,
211 " IRP_MJ_QUERY_QUOTA " ,
212 " IRP_MJ_SET_QUOTA " ,
213 " IRP_MJ_PNP " ,
214 };
215
216 UCHAR type = stack -> MajorFunction;
217 if (type >= arraysize(irpname))
218 KdPrint(( " - Unknown IRP, major type %X\n " , type));
219 else
220 KdPrint(( " \t%s\n " , irpname[type]));
221
222
223 // 对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
224 NTSTATUS status = STATUS_SUCCESS;
225 // 完成IRP
226 pIrp -> IoStatus.Status = status;
227 pIrp -> IoStatus.Information = 0 ; // bytes xfered
228 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
229
230 KdPrint(( " Leave HelloDDKDispatchRoutin\n " ));
231
232 return status;
233 }
234
235 VOID
236 OnCancelIRP(
237 IN PDEVICE_OBJECT DeviceObject,
238 IN PIRP Irp
239 )
240 {
241 KdPrint(( " Enter CancelReadIRP\n " ));
242
243 if (Irp == DeviceObject -> CurrentIrp)
244 {
245 // 表明当前正在改由StartIo处理
246 // 但StartIo并没有获取cancel自旋锁之前
247 // 这时候需要
248 KIRQL oldirql = Irp -> CancelIrql;
249
250 // 释放Cancel自旋锁
251 IoReleaseCancelSpinLock(Irp -> CancelIrql);
252
253 IoStartNextPacket(DeviceObject,TRUE);
254
255 KeLowerIrql(oldirql);
256 } else
257 {
258 // 从设备队列中将该IRP抽取出来
259 KeRemoveEntryDeviceQueue( & DeviceObject -> DeviceQueue, & Irp -> Tail.Overlay.DeviceQueueEntry);
260 // 释放Cancel自旋锁
261 IoReleaseCancelSpinLock(Irp -> CancelIrql);
262 }
263
264
265 // 设置完成状态为STATUS_CANCELLED
266 Irp -> IoStatus.Status = STATUS_CANCELLED;
267 Irp -> IoStatus.Information = 0 ; // bytes xfered
268 IoCompleteRequest( Irp, IO_NO_INCREMENT );
269
270 KdPrint(( " Leave CancelReadIRP\n " ));
271 }
272
273
274 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
275 IN PIRP pIrp)
276 {
277 KdPrint(( " Enter HelloDDKRead\n " ));
278
279 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
280 pDevObj -> DeviceExtension;
281
282 // 将IRP设置为挂起
283 IoMarkIrpPending(pIrp);
284
285 // 将IRP插入系统的队列
286 IoStartPacket(pDevObj,pIrp, 0 ,OnCancelIRP);
287
288 KdPrint(( " Leave HelloDDKRead\n " ));
289
290 // 返回pending状态
291 return STATUS_PENDING;
292 }
293
294 // 应用程序
295 #include < windows.h >
296 #include < stdio.h >
297 #include < process.h >
298
299 UINT WINAPI Thread(LPVOID context)
300 {
301 printf( " Enter Thread\n " );
302 // 等待5秒
303 OVERLAPPED overlap = { 0 };
304 overlap.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
305 UCHAR buffer[ 10 ];
306 ULONG ulRead;
307
308 BOOL bRead = ReadFile( * (PHANDLE)context,buffer, 10 , & ulRead, & overlap);
309
310 // 可以试验取消例程
311 // CancelIo(*(PHANDLE)context);
312 WaitForSingleObject(overlap.hEvent,INFINITE);
313 return 0 ;
314 }
315
316 int main()
317 {
318 HANDLE hDevice =
319 CreateFile( " \\\\.\\HelloDDK " ,
320 GENERIC_READ | GENERIC_WRITE,
321 FILE_SHARE_READ,
322 NULL,
323 OPEN_EXISTING,
324 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 此处设置FILE_FLAG_OVERLAPPED
325 NULL );
326
327 if (hDevice == INVALID_HANDLE_VALUE)
328 {
329 printf( " Open Device failed! " );
330 return 1 ;
331 }
332
333 HANDLE hThread[ 2 ];
334 hThread[ 0 ] = (HANDLE) _beginthreadex (NULL, 0 ,Thread, & hDevice, 0 ,NULL);
335 hThread[ 1 ] = (HANDLE) _beginthreadex (NULL, 0 ,Thread, & hDevice, 0 ,NULL);
336
337 // 主线程等待两个子线程结束
338 WaitForMultipleObjects( 2 ,hThread,TRUE,INFINITE);
339
340 // 创建IRP_MJ_CLEANUP IRP
341 CloseHandle(hDevice);
342
343 return 0 ;
344 }

 

示例代码 P267

使用StartIo时,需要IRP的派遣函数返回挂起状态。

2)自定义StartIo

系统提供的StartIo只能使用一个队列,如果想把读,写等操作分开进行串行化,那就要多(2)个队列。需要自定义。我们用DDK提供的 PKDEVICE_QUEUE存储队列,队列中每个元素用PKDEVICE_QUEUE_ENTRY表示。自定义StartIo里,需要我们自已维护“入队”“出队”操作。

初始化队列:KeInitializeDeviceQueue

插入:KeInsertDeviceQueue

删除:KeRemoveDeviceQueue

28、Windows内核编程,IRP的同步(2) 代码
   
     
1 // .h
2 #pragma once
3
4 #ifdef __cplusplus
5 extern " C "
6 {
7 #endif
8 #include < NTDDK.h >
9 #ifdef __cplusplus
10 }
11 #endif
12
13 #define PAGEDCODE code_seg("PAGE")
14 #define LOCKEDCODE code_seg()
15 #define INITCODE code_seg("INIT")
16
17 #define PAGEDDATA data_seg("PAGE")
18 #define LOCKEDDATA data_seg()
19 #define INITDATA data_seg("INIT")
20
21 #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
22
23 typedef struct _DEVICE_EXTENSION {
24 PDEVICE_OBJECT pDevice;
25 UNICODE_STRING ustrDeviceName; // 设备名称
26 UNICODE_STRING ustrSymLinkName; // 符号链接名
27 KDEVICE_QUEUE device_queue; // 设备队列
28 } DEVICE_EXTENSION, * PDEVICE_EXTENSION;
29
30 // 函数声明
31
32 NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject);
33 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject);
34 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
35 IN PIRP pIrp);
36 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
37 IN PIRP pIrp);
38 NTSTATUS HelloDDKCleanUp(IN PDEVICE_OBJECT pDevObj,
39 IN PIRP pIrp);
40 // .cpp
41 #include " Driver.h "
42
43
44 #pragma LOCKEDCODE
45 VOID
46 MyStartIo(
47 IN PDEVICE_OBJECT DeviceObject,
48 IN PIRP pFistIrp
49 )
50 {
51 KdPrint(( " Enter MyStartIo\n " ));
52
53 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
54 DeviceObject -> DeviceExtension;
55
56 PKDEVICE_QUEUE_ENTRY device_entry;
57
58 PIRP Irp = pFistIrp;
59 do
60 {
61 KEVENT event ;
62 KeInitializeEvent( & event ,NotificationEvent,FALSE);
63
64 // 等3秒
65 LARGE_INTEGER timeout;
66 timeout.QuadPart = - 3 * 1000 * 1000 * 10 ;
67
68 // 定义一个3秒的延时,主要是为了模拟该IRP操作需要大概3秒左右时间
69 KeWaitForSingleObject( & event ,Executive,KernelMode,FALSE, & timeout);
70
71 KdPrint(( " Complete a irp:%x\n " ,Irp));
72 Irp -> IoStatus.Status = STATUS_SUCCESS;
73 Irp -> IoStatus.Information = 0 ; // no bytes xfered
74 IoCompleteRequest(Irp,IO_NO_INCREMENT);
75
76 device_entry = KeRemoveDeviceQueue( & pDevExt -> device_queue);
77 KdPrint(( " device_entry:%x\n " ,device_entry));
78 if (device_entry == NULL)
79 {
80 break ;
81 }
82
83 Irp = CONTAINING_RECORD(device_entry, IRP, Tail.Overlay.DeviceQueueEntry);
84 } while ( 1 );
85
86 KdPrint(( " Leave MyStartIo\n " ));
87 }
88
89 /* ***********************************************************************
90 * 函数名称:DriverEntry
91 * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
92 * 参数列表:
93 pDriverObject:从I/O管理器中传进来的驱动对象
94 pRegistryPath:驱动程序在注册表的中的路径
95 * 返回 值:返回初始化驱动状态
96 ************************************************************************ */
97 #pragma INITCODE
98 extern " C " NTSTATUS DriverEntry (
99 IN PDRIVER_OBJECT pDriverObject,
100 IN PUNICODE_STRING pRegistryPath )
101 {
102 NTSTATUS status;
103 KdPrint(( " Enter DriverEntry\n " ));
104
105 // 设置卸载函数
106 pDriverObject -> DriverUnload = HelloDDKUnload;
107
108 // 设置派遣函数
109 pDriverObject -> MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutin;
110 pDriverObject -> MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutin;
111 pDriverObject -> MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutin;
112 pDriverObject -> MajorFunction[IRP_MJ_READ] = HelloDDKRead;
113 pDriverObject -> MajorFunction[IRP_MJ_CLEANUP] = HelloDDKDispatchRoutin;
114 pDriverObject -> MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutin;
115 pDriverObject -> MajorFunction[IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutin;
116 pDriverObject -> MajorFunction[IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutin;
117 pDriverObject -> MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutin;
118
119 // 创建驱动设备对象
120 status = CreateDevice(pDriverObject);
121
122 KdPrint(( " Leave DriverEntry\n " ));
123 return status;
124 }
125
126 /* ***********************************************************************
127 * 函数名称:CreateDevice
128 * 功能描述:初始化设备对象
129 * 参数列表:
130 pDriverObject:从I/O管理器中传进来的驱动对象
131 * 返回 值:返回初始化状态
132 ************************************************************************ */
133 #pragma INITCODE
134 NTSTATUS CreateDevice (
135 IN PDRIVER_OBJECT pDriverObject)
136 {
137 NTSTATUS status;
138 PDEVICE_OBJECT pDevObj;
139 PDEVICE_EXTENSION pDevExt;
140
141 // 创建设备名称
142 UNICODE_STRING devName;
143 RtlInitUnicodeString( & devName,L " \\Device\\MyDDKDevice " );
144
145 // 创建设备
146 status = IoCreateDevice( pDriverObject,
147 sizeof (DEVICE_EXTENSION),
148 & (UNICODE_STRING)devName,
149 FILE_DEVICE_UNKNOWN,
150 0 , TRUE,
151 & pDevObj );
152 if ( ! NT_SUCCESS(status))
153 return status;
154
155 pDevObj -> Flags |= DO_BUFFERED_IO;
156 pDevExt = (PDEVICE_EXTENSION)pDevObj -> DeviceExtension;
157 pDevExt -> pDevice = pDevObj;
158 pDevExt -> ustrDeviceName = devName;
159
160 RtlZeroBytes( & pDevExt -> device_queue, sizeof (pDevExt -> device_queue));
161 KeInitializeDeviceQueue( & pDevExt -> device_queue);
162
163 // 创建符号链接
164 UNICODE_STRING symLinkName;
165 RtlInitUnicodeString( & symLinkName,L " \\??\\HelloDDK " );
166 pDevExt -> ustrSymLinkName = symLinkName;
167 status = IoCreateSymbolicLink( & symLinkName, & devName );
168 if ( ! NT_SUCCESS(status))
169 {
170 IoDeleteDevice( pDevObj );
171 return status;
172 }
173 return STATUS_SUCCESS;
174 }
175
176 /* ***********************************************************************
177 * 函数名称:HelloDDKUnload
178 * 功能描述:负责驱动程序的卸载操作
179 * 参数列表:
180 pDriverObject:驱动对象
181 * 返回 值:返回状态
182 ************************************************************************ */
183 #pragma PAGEDCODE
184 VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
185 {
186 PDEVICE_OBJECT pNextObj;
187 KdPrint(( " Enter DriverUnload\n " ));
188 pNextObj = pDriverObject -> DeviceObject;
189 while (pNextObj != NULL)
190 {
191 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
192 pNextObj -> DeviceExtension;
193
194 // 删除符号链接
195 UNICODE_STRING pLinkName = pDevExt -> ustrSymLinkName;
196 IoDeleteSymbolicLink( & pLinkName);
197
198 pNextObj = pNextObj -> NextDevice;
199 IoDeleteDevice( pDevExt -> pDevice );
200 }
201 }
202
203 /* ***********************************************************************
204 * 函数名称:HelloDDKDispatchRoutin
205 * 功能描述:对读IRP进行处理
206 * 参数列表:
207 pDevObj:功能设备对象
208 pIrp:从IO请求包
209 * 返回 值:返回状态
210 ************************************************************************ */
211 #pragma PAGEDCODE
212 NTSTATUS HelloDDKDispatchRoutin(IN PDEVICE_OBJECT pDevObj,
213 IN PIRP pIrp)
214 {
215 KdPrint(( " Enter HelloDDKDispatchRoutin\n " ));
216
217 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
218 // 建立一个字符串数组与IRP类型对应起来
219 static char * irpname[] =
220 {
221 " IRP_MJ_CREATE " ,
222 " IRP_MJ_CREATE_NAMED_PIPE " ,
223 " IRP_MJ_CLOSE " ,
224 " IRP_MJ_READ " ,
225 " IRP_MJ_WRITE " ,
226 " IRP_MJ_QUERY_INFORMATION " ,
227 " IRP_MJ_SET_INFORMATION " ,
228 " IRP_MJ_QUERY_EA " ,
229 " IRP_MJ_SET_EA " ,
230 " IRP_MJ_FLUSH_BUFFERS " ,
231 " IRP_MJ_QUERY_VOLUME_INFORMATION " ,
232 " IRP_MJ_SET_VOLUME_INFORMATION " ,
233 " IRP_MJ_DIRECTORY_CONTROL " ,
234 " IRP_MJ_FILE_SYSTEM_CONTROL " ,
235 " IRP_MJ_DEVICE_CONTROL " ,
236 " IRP_MJ_INTERNAL_DEVICE_CONTROL " ,
237 " IRP_MJ_SHUTDOWN " ,
238 " IRP_MJ_LOCK_CONTROL " ,
239 " IRP_MJ_CLEANUP " ,
240 " IRP_MJ_CREATE_MAILSLOT " ,
241 " IRP_MJ_QUERY_SECURITY " ,
242 " IRP_MJ_SET_SECURITY " ,
243 " IRP_MJ_POWER " ,
244 " IRP_MJ_SYSTEM_CONTROL " ,
245 " IRP_MJ_DEVICE_CHANGE " ,
246 " IRP_MJ_QUERY_QUOTA " ,
247 " IRP_MJ_SET_QUOTA " ,
248 " IRP_MJ_PNP " ,
249 };
250
251 UCHAR type = stack -> MajorFunction;
252 if (type >= arraysize(irpname))
253 KdPrint(( " - Unknown IRP, major type %X\n " , type));
254 else
255 KdPrint(( " \t%s\n " , irpname[type]));
256
257 // 对一般IRP的简单操作,后面会介绍对IRP更复杂的操作
258 NTSTATUS status = STATUS_SUCCESS;
259 // 完成IRP
260 pIrp -> IoStatus.Status = status;
261 pIrp -> IoStatus.Information = 0 ; // bytes xfered
262 IoCompleteRequest( pIrp, IO_NO_INCREMENT );
263
264 KdPrint(( " Leave HelloDDKDispatchRoutin\n " ));
265
266 return status;
267 }
268
269 VOID
270 OnCancelIRP(
271 IN PDEVICE_OBJECT DeviceObject,
272 IN PIRP Irp
273 )
274 {
275 KdPrint(( " Enter CancelReadIRP\n " ));
276
277 // 释放Cancel自旋锁
278 IoReleaseCancelSpinLock(Irp -> CancelIrql);
279
280 // 设置完成状态为STATUS_CANCELLED
281 Irp -> IoStatus.Status = STATUS_CANCELLED;
282 Irp -> IoStatus.Information = 0 ; // bytes xfered
283 IoCompleteRequest( Irp, IO_NO_INCREMENT );
284
285 KdPrint(( " Leave CancelReadIRP\n " ));
286 }
287
288 NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,
289 IN PIRP pIrp)
290 {
291 KdPrint(( " Enter HelloDDKRead\n " ));
292
293 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
294 pDevObj -> DeviceExtension;
295
296 // 将IRP设置为挂起
297 IoMarkIrpPending(pIrp);
298
299 IoSetCancelRoutine(pIrp,OnCancelIRP);
300
301 KIRQL oldirql;
302 // 提升IRP至DISPATCH_LEVEL
303 KeRaiseIrql(DISPATCH_LEVEL, & oldirql);
304
305 KdPrint(( " HelloDDKRead irp :%x\n " ,pIrp));
306
307 KdPrint(( " DeviceQueueEntry:%x\n " , & pIrp -> Tail.Overlay.DeviceQueueEntry));
308 if ( ! KeInsertDeviceQueue( & pDevExt -> device_queue, & pIrp -> Tail.Overlay.DeviceQueueEntry))
309 MyStartIo(pDevObj,pIrp);
310
311 // 将IRP降至原来IRQL
312 KeLowerIrql(oldirql);
313
314 KdPrint(( " Leave HelloDDKRead\n " ));
315
316 // 返回pending状态
317 return STATUS_PENDING;
318 }
319
320 // 应用程序
321 #include < windows.h >
322 #include < stdio.h >
323 #include < process.h >
324
325 UINT WINAPI Thread(LPVOID context)
326 {
327 printf( " Enter Thread\n " );
328 OVERLAPPED overlap = { 0 };
329 overlap.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
330 UCHAR buffer[ 10 ];
331 ULONG ulRead;
332
333 BOOL bRead = ReadFile( * (PHANDLE)context,buffer, 10 , & ulRead, & overlap);
334
335 WaitForSingleObject(overlap.hEvent,INFINITE);
336 return 0 ;
337 }
338
339 int main()
340 {
341 HANDLE hDevice =
342 CreateFile( " \\\\.\\HelloDDK " ,
343 GENERIC_READ | GENERIC_WRITE,
344 FILE_SHARE_READ,
345 NULL,
346 OPEN_EXISTING,
347 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // 此处设置FILE_FLAG_OVERLAPPED
348 NULL );
349
350 if (hDevice == INVALID_HANDLE_VALUE)
351 {
352 printf( " Open Device failed! " );
353 return 1 ;
354 }
355
356 HANDLE hThread[ 2 ];
357 hThread[ 0 ] = (HANDLE) _beginthreadex (NULL, 0 ,Thread, & hDevice, 0 ,NULL);
358 hThread[ 1 ] = (HANDLE) _beginthreadex (NULL, 0 ,Thread, & hDevice, 0 ,NULL);
359
360 // 主线程等待两个子线程结束
361 WaitForMultipleObjects( 2 ,hThread,TRUE,INFINITE);
362
363 // 创建IRP_MJ_CLEANUP IRP
364 CloseHandle(hDevice);
365
366 return 0 ;
367 }

 

示例代码 P272

4、中断服务例程(ISR)DPC例程

DDK 提供内核函数IoConnectInterrupt把中断对象与ISR联系起来。ISR运行在DIRQL级别,高于普通线程的优先级。派遣函数,StartIo例程随时会被中断服务程序所打断,为了不让ISR打断,可以将IRQL升到相应的DIRQLDDK提供了与ISR函数同步的内核函数

KeSynchronizeExecution。当运行到KeSynchronizeExecution时,ISR不会打断KeSynchronizeExecution提供的同步函数,我们可将同步代码放到KeSynchronizeExecution提供的同步函数中。

DPC(deferred procedure call )例程

ISR处于较高的IRQL,会打断正常运行的线程。DPC处于DISPATCH_LEVEL。所以,一般,ISR中的代码应该尽量少,不太重要的代码放入DPC中。

KeInitializeDpc

你可能感兴趣的:(windows)