Windows Driver Model

Multi-core上的DISPATCH_LEVEL


Lucas同事最近又開始假認真了!剛好Spencer也來插花,於是再度激起研究討論的熱誠,遇到的問題如下:
在多核CPU上,如果有一個Thread或Function位於DISPATCH_LEVEL時,其餘CPU在幹嘛?

寫過驅動程式的使用者都知道,於DISPATCH_LEVEL(軟體最高LEVEL)時,不會發生Context Switch且也不能存取Pageable Memory,因此,按理推斷,在多核CPU下,其餘CPU理應被Block住才是,不是嗎?不然為何無法做Context Switch?或者其餘CPU只能處理IRQ>=DISPATCH_LEVEL的Thread?還是其餘CPU正常處理其餘(包含PASSIVE_LEVEL)的Thread?

說實話,司徒覺得其它CPU應該被Block住,否則Context Switch是可以發生的,當然這個Block不是說OS已經掛點,因為OS還是會受硬體IRQ觸發,畢竟硬體的IRQ還是高於軟體的IRQ,但是顯然這個觀念僅適用於單核CPU,在過往的驅動程式相關書籍中,也幾乎不提及多核CPU下的實際運作情形為何,畢竟Windows OS還不是全部開源,要摸清這些細節也不是那麼容易,因此,司徒寫了一個Legacy Driver做測試,這個Driver會創造出30個Thread,每個Thread進入後,提高IRQ至DISPATCH_LEVEL,然後透過DbgPrint()列印字串,接著降回原本IRQ LEVEL(PASSIV_LEVE),迴圈次數為20,避免系統GUI無法運作,程式碼如下所示。

main.c

#include <ntddk.h>

VOID ThreadRoutine(PVOID pParam)
{
  KIRQL oldIrql;
  ULONG id=pParam;
  ULONG loop=20, cnt=0;

  DbgPrint("ID(%d): current process: %s", id, (char*)((ULONG)IoGetCurrentProcess() + 0x174));
  while(loop--){
    KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
    DbgPrint("ID:%d(1)\n", id);
    for(cnt=0; cnt<100000000; cnt++);
    DbgPrint("ID:%d(2)\n", id);
    for(cnt=0; cnt<100000000; cnt++);
    DbgPrint("ID:%d(3)\n", id);
    for(cnt=0; cnt<100000000; cnt++);
    DbgPrint("ID:%d(4)\n", id);
    for(cnt=0; cnt<100000000; cnt++);
    DbgPrint("ID:%d(5)\n", id);
    for(cnt=0; cnt<100000000; cnt++);
    KeLowerIrql(oldIrql);
  }
  PsTerminateSystemThread(STATUS_SUCCESS);
}

void Unload(PDRIVER_OBJECT pDriverObj)
{
  if(pDriverObj->DeviceObject != NULL){
    IoDeleteDevice(pDriverObj->DeviceObject);
  }
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath)
{
  ULONG x;
  NTSTATUS status;
  ULONG hThread;
  
  PDEVICE_OBJECT pFunObj=NULL;
  UNICODE_STRING usDeviceName;

  RtlInitUnicodeString(&usDeviceName, L"\\Device\\Test");
  IoCreateDevice(pDriverObj, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pFunObj);
  pDriverObj->DriverUnload = Unload;
 
  for(x=0; x<30; x++){
    PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, -1, NULL, ThreadRoutine, x);
  }
  return STATUS_SUCCESS;
}

測試於WinXP 32Bit、Intel四核CPU


測試於VirtualBox(WinXP 32Bit)、四顆Processor CPU

經由上面的測試可以發現,列印的字串可以被插入(於Intel CPU上),也就代表每顆CPU都是各自運作,不受其它顆CPU影響,同時,提高至DISPATCH_LEVEL時,僅當下CPU無法做Context Switch,其餘CPU都是可以繼續執行PASSIVE_LEVEL的事情,也不須等待其它CPU變回PASSIVE_LEVEL,而上面的測試也發現,在VirtualBox虛擬機下,多核CPU的實作還是跟真實CPU(Intel)有些為不同,當然,經由測試也發現,原本在單核CPU會發生的Dead Lock事件,於多核CPU環境下,有機會消失,因此,遵照Microsoft的規範撰寫驅動程式,基本上可以說是保證沒問題,畢竟那是基於單核CPU的基礎,但是,絕對會發生的問題,目前看來有可能不一樣了!

結論:
1. VirtualBox實作多核CPU,仍然是基於Queue的順序概念實做。
2. 只有當下該顆CPU處於DISPATCH_LEVEL,該顆CPU無法做Context Switch,但是其餘CPU正常運作,也可以正常執行PASSIVE_LEVEL的Thread。
最後,Spencer猜測OS為何不在多核CPU下做Memory Swap的動作,可能的原因是Cost太高!


返回上一頁