天天看點

Pnp管理器(2)

    前一篇Pnp管理器(1)提到了總線上裝置變化時,将産生Pnp消息并在Pnp管理器個元件間流動。消息傳遞的最終目的是通知某個元件加載驅動。本文看一下Pnp管理器收到消息後加載驅動的流程。

    當PnpEventThread函數從等待阻塞中傳回,判斷如果是添加裝置則建立一個DeviceInstallParams* Params變量

typedef struct
{
#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
    SLIST_ENTRY ListEntry;
#else
    LIST_ENTRY ListEntry;
#endif
    WCHAR DeviceIds[1];
} DeviceInstallParams;      

    前面裝置樹結構變更時,獲得了裝置的ID,現在将這個ID填入Params變量,并加入DeviceInstallListHead連結清單,然後通知Pnp管理器的DeviceInstallThread核心線程為新裝置安裝驅動。和PnpEventThread一樣DeviceInstallThread也是IO管理器初始化時建立的線程,周而複始的等待事件hDeviceInstallListNotEmpty被觸發。

static VOID CALLBACK
ServiceMain(DWORD argc, LPTSTR *argv)
{
    ...
    hThread = CreateThread(NULL,
                           0,
                           PnpEventThread,
                           NULL,
                           0,
                           &dwThreadId);
    if (hThread != NULL)
        CloseHandle(hThread);

    hThread = CreateThread(NULL,
                           0,
                           DeviceInstallThread,
                           NULL,
                           0,
                           &dwThreadId);
    ...
}      
static DWORD WINAPI
DeviceInstallThread(LPVOID lpParameter)
{
    while (TRUE)
    {
        if ((BOOL)IsListEmpty(&DeviceInstallListHead))
            ListEntry = NULL;
        else
            ListEntry = RemoveHeadList(&DeviceInstallListHead);
        //從DeviceInstallListHead隊列中獲得PnpEventThread線程中加入的DeviceInstallParams項
        //ListEntry 收到通知時從阻塞中傳回将進入到else分支,否則進入if分支
        //繼續等待
        if (ListEntry == NULL)
        {
            SetEvent(hNoPendingInstalls);
            WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
        }
        else
        {
            ResetEvent(hNoPendingInstalls);
            Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
            InstallDevice(Params->DeviceIds, setupActive);
        }
    }
}      

繼續閱讀