Windows Driver Model >> Pascal >> Synchronization

Semaphore


參考資訊:
1. Source Code

Semaphore可以想像成是集成多個Mutex的機制,Semaphore可以設定取得Lock的數量,不像Mutex只有單一個Lock限制,因此,如果程式區段有執行數量的限制時,Semaphore是一個相當適合的方式,值得注意的是,釋放Semaphore不能超過設定的數量,否則會有STATUS_SEMAPHORE_LIMIT_EXCEEDED,使用步驟如下:
1. KeInitializeSemaphore()
2. KeWaitForSingleObject()
3. KeReleaseSemaphore()

main.pas

unit main;

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

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

implementation
var
  mySemaphore: KSEMAPHORE;
  pNextDevice: PDEVICE_OBJECT;

procedure MyThread(pParam:Pointer); stdcall;
var
  tt: LARGE_INTEGER;
  cc: ULONG;
 
begin
  tt.HighPart:= tt.HighPart or -1;
  tt.LowPart:= ULONG(-10000000);
  DbgPrint('Thread%d, Acquiring Semaphore', [ULONG(pParam)]);
  KeWaitForSingleObject(@mySemaphore, Executive, KernelMode, FALSE, Nil);
  DbgPrint('Thread%d, Acquired Semaphore', [ULONG(pParam)]);
  DbgPrint('Thread%d, Sleeping', [ULONG(pParam)]);
  KeDelayExecutionThread(KernelMode, FALSE, @tt);
  DbgPrint('Thread%d, Releasing Semaphore', [ULONG(pParam)]);
  cc:= KeReadStateSemaphore(@mySemaphore);
  if cc < MAX_SEMA_LIMIT then
    cc:= 1
  else
    cc:= 0;
  KeReleaseSemaphore(@mySemaphore, IO_NO_INCREMENT, cc, FALSE);
  DbgPrint('Thread%d, Released Semaphore', [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;

  KeInitializeSemaphore(@mySemaphore, MAX_SEMA_COUNT, MAX_SEMA_LIMIT);
  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會嘗試取得Semaphore,一旦取得Semaphore後,會延遲一秒後才釋放Semaphore,而Semaphore的數量設定成2,因此,每次最多只能有兩個Thread取得Semaphore

結果


返回上一頁