The problem with KeStallExecutionProcessor is that it’s actually a “empty
loop”, rather than a “make something else happen”. This is how it can be
fairly precise, but it’s not very “nice” to the rest of the system.
The KeDelayExecutionUnit will use the PC 8254 timer to get an interrupt to
wake the processo, and puts the current process to sleep. This is good for
other processes, but has the drawback that you don’t know for sure that the
current process will be woken “in time”, as there’s nothing to say that your
process will be scheduled at any particyular time.
One solution would be to use the QueryPerformanceCounters interface, which
uses the 8254 counters, and it will give you a precision of about 0.9 usec,
IIRC. Something like this:
void delayUsecs(int uSecs)
{
LARGE_INTEGER Count, Count2, CountWanted;
LARGE_INTEGER Passed;
LARGE_INTEGER uSecsLeft;
LARGE_INTEGER Freq;
Count = KeQueryPerformanceCounter( &Freq );
CountWanted.quad = (uSecs * Freq.quad) / 1000000;
if (uSecs > 20)
{
KeDelayExecutionThread(uSecs - 10);
}
Count2 = KeQuesryPerformanceCounter( NULL );
Passed.quad = Count2.quad - Count.quad;
if (Passed.quad > CountWanted.quad)
return; // We overshot. May want to do
something to debug the problem…
uSecsLeft = uSecs - (Passed.Quad * 1000000) / Freq.Quad);
if (uSecsLeft)
KeStallExecutionProcessor(uSecsLeft);
}
This way you get the best of both worlds.
I had problems with KeDelayExecutionThread however. Apparently, if you call
it at the wrong IRQL, it just returns immediately (and I used it to figure
out the frequency of something else, which meant that both my “before” and
“after” times where the same, so I got a divide by zero
). I wrote my
own “sleep” routine instead. This uses the KeSetTimer() and
KeWaitForSingleObject(). This isn’t a very precise “sleep”, which is fine if
I’m just trying to figure out how many cycles pass on one of my internal
counters in a specified time, but if you want to delay a certain (exact)
amount, it’s not particularly useful.
Note also that as of current, there’s nothing that prevents an interrupt
from taking several microseconds (or milliseconds for that matter), so any
precise timing that isn’t run at IRQL which dissables Interrupts, will mean
that you could have “overshot” your timing. There’s nothing to prevent this
from happening, except making sure that any drivers in the system is
“well-behaved” (including in "special cases, like error handling and other
obscure scenarios. Num-lock key on the keyboard used to be bad when the BIOS
handled it, but I think Windows doesn’t hold interrupts off for the 4.2
milliseconds it takes for everything to happen in a “set numlock LED”).
–
Mats
-----Original Message-----
From: Nikolay [mailto:xxxxx@pisem.net]
Sent: Monday, February 09, 2004 2:11 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] How to delay execution
Hello
I need to delay the code execution
The delay varies from 130 to 1500 usecs. What function should be used?
KeDelayExecutionThread works Ok with delay > 20 msecs, since
inaccuracy can
be 5 msecs (or more)
KeStallExecutionProcessor is more accurate, but DDK
documentation says:
“… Drivers that call this routine should minimize the number of
microseconds they specify (no more than 50)…”,
So I have not use KeStallExecutionProcessor…
How to solve this?
How to implement the delay in case if range is from 50 usecs
to 20 msecs???
Thanx,
Nikolay
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
You are currently subscribed to ntdev as: xxxxx@3dlabs.com
To unsubscribe send a blank email to xxxxx@lists.osr.com