zoukankan      html  css  js  c++  java
  • 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例程)。

    代码
    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

    代码
    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

  • 相关阅读:
    计算机网络为什么是这样样子?
    MySQL技术内幕 InnoDB存储引擎 B+树索引的使用 笔记
    后端性能-batch 化的想法
    稳定高效的服务来自于稳定而合理的数据结构
    gRPC 学习了解记录
    Go 进阶训练营 Week02: error 错误处理
    生活小感受
    Nginx 499 排查到docker 中一个进程一直在空转
    方法论和原理总结
    Debug
  • 原文地址:https://www.cnblogs.com/mydomain/p/1873178.html
Copyright © 2011-2022 走看看