Windows Driver Model >> Pascal >> Synchronization

Spin Lock


參考資訊:
1. Source Code

在多核心CPU環境中,可能有些程式區段,每次只能讓一顆CPU進入執行,這時候可以使用Spin Lock機制,Spin Lock一次只能有一個Lock,因此,當有一顆CPU取得Lock後,其餘CPU便無法取得Lock,在無法取得Lock狀況下,這些CPU會不斷嘗試取得Lock,因此,Spin Lock對於CPU資源的開銷是很大的,在寫Spin Lock程式時,必須注意不能Lock太久,否則將導致系統效能下降,同時,在取得Lock後,將會提昇到DISPATCH_LEVEL執行,使用步驟如下:
1. KeInitializeSpinLock()
2. KeAcquireSpinLock()
3. KeReleaseSpinLock()

main.pas

unit main;

interface
  uses
    DDDK;
    
  const
    MAX_THREAD = 3;
    DEV_NAME = '\Device\MyDriver';
    SYM_NAME = '\DosDevices\MyDriver';

  function _DriverEntry(pOurDriver:PDRIVER_OBJECT; pOurRegistry:PUNICODE_STRING):NTSTATUS; stdcall;

implementation
var
  myLock: KSPIN_LOCK;
  pNextDevice: PDEVICE_OBJECT;

procedure RunMe(v:ULONG); stdcall;
var
  c0: ULONG;
  c1: ULONG;
  oldIrql: KIRQL;

begin
  DbgPrint('Thread%d, Locking', [v]);
  KeAcquireSpinLock(@myLock, @oldIrql);
  DbgPrint('Thread%d, Locked', [v]);

  for c0:=0 to 10000 do
    for c1:=0 to 10000 do
      ;

  DbgPrint('Thread%d, Unlocking', [v]);
  KeReleaseSpinLock(@myLock, oldIrql);
  DbgPrint('Thread%d, Unlocked', [v]);
end;

procedure MyThread(pParam:Pointer); stdcall;
var
  tt: LARGE_INTEGER;
 
begin
  tt.HighPart:= tt.HighPart or -1;
  tt.LowPart:= ULONG(-10000000);
  KeDelayExecutionThread(KernelMode, FALSE, @tt);

  RunMe(ULONG(pParam));
  PsTerminateSystemThread(STATUS_SUCCESS);
end;

procedure Unload(pOurDriver:PDRIVER_OBJECT); stdcall;
begin
end;

function IrpPnp(pOurDevice:PDEVICE_OBJECT; pIrp:PIRP):NTSTATUS; stdcall;
var
  psk: PIO_STACK_LOCATION;
  suSymName: UNICODE_STRING;
  
begin
  psk:= IoGetCurrentIrpStackLocation(pIrp);
  if psk^.MinorFunction = IRP_MN_REMOVE_DEVICE then
  begin
    RtlInitUnicodeString(@suSymName, SYM_NAME);
    IoDetachDevice(pNextDevice);
    IoDeleteDevice(pOurDevice);
    IoDeleteSymbolicLink(@suSymName);
  end;
  IoSkipCurrentIrpStackLocation(pIrp);
  Result:= IoCallDriver(pNextDevice, pIrp);
end;

function AddDevice(pOurDriver:PDRIVER_OBJECT; pPhyDevice:PDEVICE_OBJECT):NTSTATUS; stdcall;
var
  suDevName: UNICODE_STRING;
  suSymName: UNICODE_STRING;
  pOurDevice: PDEVICE_OBJECT;
  
begin
  RtlInitUnicodeString(@suDevName, DEV_NAME);
  RtlInitUnicodeString(@suSymName, SYM_NAME);
  IoCreateDevice(pOurDriver, 0, @suDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, pOurDevice);
  pNextDevice:= IoAttachDeviceToDeviceStack(pOurDevice, pPhyDevice);
  pOurDevice^.Flags:= pOurDevice^.Flags or DO_BUFFERED_IO;
  pOurDevice^.Flags:= pOurDevice^.Flags and not DO_DEVICE_INITIALIZING;
  Result:= IoCreateSymbolicLink(@suSymName, @suDevName);
end;

function _DriverEntry(pOurDriver:PDRIVER_OBJECT; pOurRegistry:PUNICODE_STRING):NTSTATUS; stdcall;
var
  cc: ULONG;
  hThread: Handle;
  status: NTSTATUS;

begin
  pOurDriver^.MajorFunction[IRP_MJ_PNP]:= @IrpPnp;
  pOurDriver^.DriverExtension^.AddDevice:=@AddDevice;
  pOurDriver^.DriverUnload:=@Unload;

  KeInitializeSpinLock(@myLock);
  for cc:=0 to (MAX_THREAD-1) do
  begin
    status:= PsCreateSystemThread(@hThread, THREAD_ALL_ACCESS, Nil, Handle(-1), Nil, MyThread, Pointer(cc));
    if NT_SUCCESS(status) then
    begin
      ZwClose(hThread);
    end;
  end;
  Result:=STATUS_SUCCESS;
end;
end.

DriverEntry()產生3個Thread,每個Thread延遲1秒,接著呼叫RunMe(),在RunMe()裡面會進行Spin Lock的動作,確保每次只能有一個CPU進入執行

使用四顆CPU測試


每次只會有一顆CPU進入執行


返回上一頁