|
|
|
The sleep() and usleep() C Api
The sleep and usleep api's basically allow our programs to pause for some
amount of time before resuming. The sleep api allows us to sleep for a number of
seconds. The usleep allows us to sleep for a number of microseconds. Here
is the the prototype for sleep():
d TIME_Sleep pr 10u 0 ExtProc('sleep')You might notice that I name the prototype TIME_sleep. The reason for this is that I like to standardize my procedure and function names to include a prefix, an underscore, and then a meaningful name for the procedure / function. The prefix TIME tells me that the prototypes are located in a member called TIME_p. So if I want to use the TIME_Sleep in an application, I also need to copy the TIME_p member so that my program has a copy of the prototype. Another reason for using a different name than the actual api is so to eliminate name "collisions" that can occur. If there are more than one procedure named sleep that I need to reference, then I will have a naming collision. By using the TIME_ prefix, I keep this from happening, while having a naming standard that allows me to quickly reference the correct member for copying the prototypes into the applications.
If we want our program to sleep for 2 seconds, then we could simply make a call that looks like the following:
Time_Sleep( 2 );
If we want our program to sleep for less than a second, we use the usleep() api. Although we can simply code a prototype that looks like the sleep, there is a problem if we do this. Here's the prototype:
d TIME_uSleep pr 10u 0 ExtProc('usleep')If we call this function and pass it 250000, then it will successfully sleep for a quarter of a second. ( 250,000 microseconds = .25 seconds)
But here's the problem. If we want to sleep for 1.25 seconds, we should simply be able to pass the api 1250000. However, the api will not sleep at all if we pass it a parameter greater than 1000000, it will error out and return immediately.
To get around this, we need to write a procedure that traps this condition so that we can call the prototype and pass it any value for microseconds, even those well over a million. To do this, we need a prototype for the usleep api. We can use the one we coded above call TIME_uSleep. This will call the usleep() api.
Now, we need a second prototype, which I call TIME_MicroSleep.
d TIME_MicroSleep...
d pr
d SleepTime 10u 0 const
Now, we need to create a procedure.
p TIME_MicroSleep...
p b export
d TIME_MicroSleep...
d pi
d MicroSeconds 10u 0 const
d Seconds s like(MicroSeconds)
d RemainingTime s like(MicroSeconds)
/free
if MicroSeconds => 1000000;
Seconds = Microseconds/1000000;
RemainingTime = MicroSeconds - (Seconds * 1000000);
TIME_Sleep(Seconds);
TIME_usleep(RemainingTime);
else;
TIME_uSleep(MicroSeconds);
endif;
return;
/end-free
p e
Notice that we test the passed parameter, which should be the number of microseconds we want to sleep, to 1,000,000. If it's greater than or equal to one million, then we need to get the number of whole seconds into a field called Seconds, and perform a regular TIME_Sleep for that number of seconds. Then we remove the number of whole seconds from the MicroSecond field and place this amount in RemainingTime, which will be in microseconds. The we perform the usleep() api for the number of microseconds remaining in the RemainingTime field.
Basically what happens when we call the TIME_MicroSleep function is that we check to see if the number of micrseconds to sleep is greater than or equal to 1 million. If it is not, we simply usleep for the number of microseconds. If the number of microseconds is greater than one million, then we perform a regular sleep for the number of whole seconds, and then a usleep for the remaining microseconds.
Let's use this function to sleep for a quarter of a second:
TIME_MicroSleep( 250000 );
Notice how 250,000 microseconds is the same as a quarter of a second.
The slep calls are preferable over the DLYJOB command. First, the look of the code is much cleaner with the sleep functions versus the Delay Job. Second, by using the usleep API, we can sleep for a much shorter duration than is possible with the delay job.
Because the sleep and usleep apis are "C" library functions, you must bind to the QC2LE binding directory in the programs which use them. I created a service program that contains these functions which binds to QC2LE, and then simply bind any program that uses these functions to the binding directory that contains my service program. I also know to copy the TIME_p member into any program that uses these functions ni order to get a copy of the prototypes.
For an example of a program which uses the api's, you can refer to the TIME_DelayJobUntil procedure.