核心延時的N種方法
阿新 • • 發佈:2019-01-27
方法一:NdisMSleep
VOID NdisMSleep(
IN ULONG MicrosecondsToSleep
);
直接呼叫NdisMSleep,它的引數是微秒數量級。不過這裡一定要注意
呼叫環境:
- KeGetCurrentIrql < DISPATCH_LEVEL
方法二:NdisStallExecution
VOID NdisStallExecution(
IN UINT MicrosecondsToStall
);
這裡也是直接呼叫,引數是微秒級,但是最好不要用它延時超過50個微秒。
呼叫環境:
- Any IRQL
- MicrosecondsToStall <= 50
方法三:KeDelayExecutionThread
NTSTATUS KeDelayExecutionThread(
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval
);
該函式將當前執行執行緒置於等待狀態,當時間過後被喚醒。
呼叫環境:
- KeGetCurrentIrql <= APC_LEVEL
參考程式碼:
LARGE_INTEGER liTime;
delay = delay * 10000;
// Negative value means relative time, not absolute
liTime =RtlConvertLongToLargeInteger(-(LONG)delay);
//Callers of KeDelayExecutionThread must be running at IRQL <= APC_LEVEL.
DbgPrint("KeGetCurrentIrql = %d\n", KeGetCurrentIrql());
KeDelayExecutionThread( KernelMode, TRUE , &liTime);
方法四:KeWaitForSingleObject
NTSTATUS KeWaitForSingleObject(
IN PVOID Object,
IN KWAIT_REASON WaitReason,
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout OPTIONAL
);
該函式等待訊號的到來,如果在所設時間之內沒有訊號,則返回TimeOut。
呼叫環境:
- KeGetCurrentIrql <= PASSIVE_LEVEL
參考程式碼:
LARGE_INTEGER TimeoutTimer;
TimeoutTimer = RtlConvertLongToLargeInteger(-(LONG)(delay * 10000));
//sleep,waiting (TimeoutWait) singaled
DbgPrint("KeGetCurrentIrql = %d\n", KeGetCurrentIrql());
status = KeWaitForSingleObject(
&TimeoutWait,
Executive,
KernelMode,
FALSE,
&TimeoutTimer);
方法五:空迴圈
呼叫環境:
任何情況下都可使用。
參考程式碼:
LARGE_INTEGER liTime, startTime, currentTime;
delay = delay * 10000;
KeQuerySystemTime(&startTime);
while(1){
KeQuerySystemTime(¤tTime);
liTime.QuadPart = currentTime.QuadPart - startTime.QuadPart;
if(liTime.QuadPart >= delay) break;
}
以上方法中前面四種不佔用CPU時鐘,第五種方法會佔用CPU時鐘,在迫不得已的情況下使用。