程序员人生 网站导航

Pnp管理器(1)

栏目:综合技术时间:2016-07-13 10:42:36

    之前写过1篇Pnp管理器的文章,感觉写的有点浮浅,因此打算另起1篇写Pnp管理器。Pnp管理器是个大的组件:从内核到用户态都有触及,因此需要分若干篇章分析。本篇立足于Pnp管理器中连接各个模块之间消息流。

    系统引导进程中会初始化IO管理器,由IO管理器调用PnpInit对Pnp管理器进行初始化。跟Pnp消息相干的有两处:

NTSTATUS INIT_FUNCTION IopInitPlugPlayEvents(VOID) { InitializeListHead(&IopPnpEventQueueHead); KeInitializeEvent(&IopPnpNotifyEvent, SynchronizationEvent, FALSE); return STATUS_SUCCESS; }
初始化Pnp消息队列和用于同步Pnp管理器间各个模块的事件。从这段代码可以大致看出Pnp管理器属于生产者-消费者模型:内核把装备相干的动态信息加入到IopPnpEventQueueHead队列中,然后通知其他模块取走消息并处理。

    内核中用树结构来管理装备,在PnpInit中IopRootDriverObject驱动创建1个Pdo作为全部装备树的根对象,当有新装备加入时,就加到连在根装备对象各个总线下,同时产生通知消息。根装备也是装备,所以在PnpInit中,IopRootDriverObject驱动创建Pdo的同时也向才创建不久的IopPnpEventQueueHead队列插入1条消息(第1条消息),通知内核有新装备加入,固然,现在还没组件处理这些消息。

IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &IopRootDeviceNode->InstancePath);
    随着初始化进程的推动,IO管理器终究会创建1个内核线程,循环往复的处理IopPnpEventQueueHead中排队的消息:

hThread = CreateThread(NULL, 0, PnpEventThread, NULL, 0, &dwThreadId);

static DWORD WINAPI PnpEventThread(LPVOID lpParameter) { for (;;) { /* Wait for the next pnp event */ //这是个等待操作,等待PnpEvent有信号 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus)) { InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry); #else InsertTailList(&DeviceInstallListHead, &Params->ListEntry); #endif SetEvent(hDeviceInstallListNotEmpty); }
}

    NtGetPlugPlayEvent函数是个无穷等待函数,直到IopPnpNotifyEvent有事件,才从IopPnpEventQueueHead队列中取出1个元素。Pnp管理器的目的是为装备对象加载驱动,因此当线程从阻塞中返回到PnpEventThread中,PnpEventThread就取得装备信息,然后通知Pnp管理器其他组件部份准备安装驱动

    谁会触发IopPnpNotifyEvent事件?搜索对IopPnpNotifyEvent的调用会发现IopActionInterrogateDeviceStack函数会间接触发IopPnpNotifyEvent事件。

NTSTATUS IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode, PVOID Context) { /* Report the device to the user-mode pnp manager */ IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL, &DeviceNode->InstancePath); }
    每当总线装备枚举到到有新装备加入系统就会IoSynchronousInvalidateDeviceRelations,通知Pnp管理器原来的装备树产生变动,期间调用IopActionInterrogateDeviceStack使得总线上已有的装备重新取得装备信息(DeviceID,Resource等,这像是1个社区人员产生了变动,要通知社区中所有社员1样),变更装备信息后调用IopQueueTargetDeviceEvent准备为装备加载驱动~


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐