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進入執行