Pnp管理器(1)
來源:程序員人生 發布時間:2016-07-13 10:42:36 閱讀次數:3732次
之前寫過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準備為裝備加載驅動~
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈