1. 程式人生 > >核心延時的N種方法

核心延時的N種方法

方法一: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(&currentTime);
    liTime.QuadPart = currentTime.QuadPart - startTime.QuadPart;
    if(liTime.QuadPart >= delay) break;
} 

以上方法中前面四種不佔用CPU時鐘,第五種方法會佔用CPU時鐘,在迫不得已的情況下使用。