[comp.lang.c] Delay for a fraction of a second in C

echarne@orion.cf.uci.edu (Eli B. Charne) (11/02/88)

I am writing a program, in which part of it does a fancy little display
for the user.  However, in order for the user to be able to see it, I need
a delay.

The Unix sleep command will only go in increments of one second.  I was
wondering if someone new of a nice little routine I could use, or has
written one that will let me pause (in the Unix operating system) for
a fraction of a second.  If it could go to 100th of a second, that would
be great!

                                                   Thanks
                                                     -Eli

                                                zecharne@uci.bitnet
                                                echarne@orion.cf.uci.edu

crossgl@ingr.UUCP (Gordon Cross) (11/02/88)

In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
> 
> The Unix sleep command will only go in increments of one second.  I was
> wondering if someone new of a nice little routine I could use, or has
> written one that will let me pause (in the Unix operating system) for
> a fraction of a second.  If it could go to 100th of a second, that would
> be great!

You are not going to be able to do this without coding up some kind of
"delay loop" yourself.  Of course that solution is definitely NOT portable in
any way since the loop would have to be fine tuned to your machines execution
speed.  Remember that in the UNIX kernal, scheduled wakeups occur at fixed
one second intervals.  Thus, unless you are using a non standard kernal, sleeps
of only whole numbers of seconds are possible!


Gordon Cross
Intergraph Corp.  Huntsville, AL

gckaplan@soup.ssl.berkeley.edu (George Kaplan) (11/04/88)

In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
> 
> The Unix sleep command will only go in increments of one second.  I was
> wondering if someone new of a nice little routine I could use, or has
> written one that will let me pause (in the Unix operating system) for
> a fraction of a second.  If it could go to 100th of a second, that would
> be great!

On a Sun (and presumably under bsd 4.x as well) there's a usleep()
function to sleep for a specified number of microseconds:

	void usleep(useconds)
	unsigned useconds;

This actually pauses for _at least_ the specified number of useconds.
The actual delay may be longer depending on other activity in the
system.

- George C. Kaplan		gkaplan@sag4.ssl.berkeley.edu

henry@utzoo.uucp (Henry Spencer) (11/04/88)

In article <1145@orion.cf.uci.edu> echarne@orion.cf.uci.edu (Eli B. Charne) writes:
>The Unix sleep command will only go in increments of one second.  I was
>wondering if someone new of a nice little routine I could use, or has
>written one that will let me pause (in the Unix operating system) for
>a fraction of a second.  If it could go to 100th of a second, that would
>be great!

You are basically out of luck.  There is no standard, portable way of
doing this.  Some Unix systems provide a primitive, sometimes named
"nap", for doing it; some don't.  Even those that do provide it tend to
disagree on what units it works in.
-- 
The Earth is our mother.        |    Henry Spencer at U of Toronto Zoology
Our nine months are up.         |uunet!attcan!utzoo!henry henry@zoo.toronto.edu

davidsen@steinmetz.ge.com (William E. Davidsen Jr) (11/04/88)

There is a system call "nap" in Xenix, which is in ms. My notes on V.4
indicate that it will be there as well. Probably in two years that
feature will have propigated, but in the mean time you are out of luck
as to a portable way to do it.

Even if you have the feature it is granular to the nearest clock tick.
-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

djones@megatest.UUCP (Dave Jones) (11/04/88)

From article <2804@ingr.UUCP>, by crossgl@ingr.UUCP (Gordon Cross):
> In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
>> 
>> The Unix sleep command will only go in increments of one second.  I was
>> wondering if someone new of a nice little routine I could use, or has
>> written one that will let me pause (in the Unix operating system) for
>> a fraction of a second.  If it could go to 100th of a second, that would
>> be great!
> 
> You are not going to be able to do this without coding up some kind of
> "delay loop" yourself.  Of course that solution is definitely NOT portable in
> any way since the loop would have to be fine tuned to your machines execution
> speed.  Remember that in the UNIX kernal, scheduled wakeups occur at fixed
> one second intervals.  Thus, unless you are using a non standard kernal, sleeps
> of only whole numbers of seconds are possible!
> 
> 
> Gordon Cross
> Intergraph Corp.  Huntsville, AL




Mr. Cross, perhaps it is time that *you* should wake up.
You are dreaming up answers.  :-)

Pour yourself a cup of strong coffee, then try the following:

#include <sys/time.h>

delay(seconds, micro_seconds)
  long seconds;
  long micro_seconds;
{
  struct timeval timev;
  timev.tv_sec = seconds;
  timev.tv_usec = micro_seconds;
  select(0,0,0,0, &timev);
}

Some unixes may name the include-file <time.h> and the structure
"struct time_val", but it comes to the same thing.  Read the 
man-pages on select(), setitimer(), and signal().

Also, please don't code tight spin-loops for delays or for polling.
Particularly if you are on a time-shared system.



		Best regards,

		Dave J.

jas@ernie.Berkeley.EDU (Jim Shankland) (11/04/88)

In article <2804@ingr.UUCP> crossgl@ingr.UUCP (Gordon Cross) writes:
>You are not going to be able to do [sub-second sleeps] without coding
>up some kind of "delay loop" yourself....
>Remember that in the UNIX kernal, scheduled wakeups occur at fixed
>one second intervals.  Thus, unless you are using a non standard kernal, sleeps
>of only whole numbers of seconds are possible!

Never trust statements about the UNIX kernel from people who can't even
spell the word.  Kernel timeouts can occur at 1/HZ second intervals, where HZ
is typically 60 or 100.  The kernel CAN provide a system call to let
processes set alarms at that granularity -- BSD and derivatives do
(setitimer).  SysV-flavored systems just don't bother.  (Or is this
fixed in SysVR3?)

-----
Jim Shankland
jas@ernie.berkeley.edu

"The God I believe in isn't short of cash, MISTER!"

gpasq@picuxa.UUCP (Greg Pasquariello X1190) (11/04/88)

In article <2804@ingr.UUCP> crossgl@ingr.UUCP (Gordon Cross) writes:
>In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
>> 
>> The Unix sleep command will only go in increments of one second.
>> let me pause (in the Unix operating system) for a fraction of a second.
>
>You are not going to be able to do this without coding up some kind of
>"delay loop" yourself. 
>Gordon Cross
                                                                     
                                                                     
                                                                          
Although kludgy, you could do a read with timeout on some file descriptor as-
sociated with a tty.  See the man pages on read(1) and termio(7).
                                                                       
                                                               
                                                                         
==========================================================================
-- 
=========================================================================
"I crush your head!"		Greg Pasquariello   AT&T PMTC
				att!picuxa!gpasq    Parsippany, NJ
=========================================================================

gpasq@picuxa.UUCP (Greg Pasquariello X1190) (11/04/88)

In article <965@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>From article <2804@ingr.UUCP>, by crossgl@ingr.UUCP (Gordon Cross):
>> 
>> You are not going to be able to do this without coding up some kind of
>> "delay loop" yourself. 
>
>Mr. Cross, perhaps it is time that *you* should wake up.
>You are dreaming up answers.  :-)
                                                                           
	Here the select() call is mentioned....
                                                                       
>
>		Dave J.
                                                                          
                                                                        
Select is not available up to (at least) SVR3.  It may be in R4, but I don't 
know for sure.
                                                                            
                                                                              
                                                                             
                                                                            

-- 
=========================================================================
"I crush your head!"		Greg Pasquariello   AT&T PMTC
				att!picuxa!gpasq    Parsippany, NJ
=========================================================================

gee@dretor.dciem.dnd.ca (Tom Gee see wdf) (11/04/88)

>In <28247@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) write:
>>In <1145@orion.cf.uci.edu> echarne@orion.cf.uci.edu (Eli B. Charne) writes:
>>The Unix sleep command will only go in increments of one second.  I was
>>wondering if someone new of a nice little routine I could use, or has
>>written one that will let me pause (in the Unix operating system) for
>>a fraction of a second.

>You are basically out of luck.  There is no standard, portable way of
>doing this.  Some Unix systems provide a primitive, sometimes named
>"nap", for doing it; some don't.  Even those that do provide it tend to
>disagree on what units it works in.

About two weeks ago, a version of nap() for System V.3 was posted to the net
( I think it was comp.sources.unix ).  It is a device driver and interface
written by zeff@b-tech.  If anyone wants a copy, send me a message and I'll
mail it to you.
_________
"If you know what a bubble sort is, |  Thomas Gee
 wipe it from your mind"            |  Aerospace Group
        -- Numerical Methods in C.  |  DCIEM
                                    |  Department of National Defence
               {watmath,utzoo}!dciem!zorac!dretor!gee

colburn@src.honeywell.COM (Mark H. Colburn) (11/05/88)

In article <2804@ingr.UUCP> crossgl@ingr.UUCP (Gordon Cross) writes:
>In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
#> The Unix sleep command will only go in increments of one second.  I was
#> wondering if someone new of a nice little routine I could use, or has
#> written one that will let me pause (in the Unix operating system) for
#> a fraction of a second.
#> be great!
#You are not going to be able to do this without coding up some kind of
#"delay loop" yourself.

Actually, under System V you can use the VMIN timer on the tty driver,
which will give you granularity of about 1/10 of a second.  As long as your
are going to be doing terminal oriented work, this is fairly easy.  This
does not work on most BSD systems, although there you have higher
granularity sleeps anyways...

guy@auspex.UUCP (Guy Harris) (11/05/88)

>Pour yourself a cup of strong coffee, then try the following:

And watch it fail to compile on many systems.

Unfortunately, neither "select" nor "setitimer" exist on all UNIX
systems.  (They also tend not to exist on non-UNIX systems, which is why
this discussion is getting sent back to comp.unix.questions, where it
belongs.)

However, you can use "poll" instead of "select" on System V Release 3,
so at least there you can block for an amount of time < 1 second
(although there still isn't a way to get a signal delivered after an
interval of < 1 second in vanilla S5R3).

mkhaw@teknowledge-vaxc.ARPA (Mike Khaw) (11/05/88)

> On a Sun (and presumably under bsd 4.x as well) there's a usleep()
> function to sleep for a specified number of microseconds:

It's implemented using setitimer(2), so if you have the latter but not
usleep(3), you should be able to invent your own.

Mike Khaw
-- 
internet: mkhaw@teknowledge.arpa
uucp:	  {uunet|sun|ucbvax|decwrl|ames|hplabs}!mkhaw%teknowledge.arpa
hardcopy: Teknowledge Inc, 1850 Embarcadero Rd, POB 10119, Palo Alto, CA 94303

billd@celerity.UUCP (Bill Davidson) (11/05/88)

In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
> 
> The Unix sleep command will only go in increments of one second.  I was
> wondering if someone new of a nice little routine I could use, or has
> written one that will let me pause (in the Unix operating system) for
> a fraction of a second.  If it could go to 100th of a second, that would
> be great!

This is a function I wrote almost 2 years ago.  (It comes back to haunt me
now and then).  It works on Celerity 1200, 1230, 1260D and the new FPS
Model 500 and should be relatively portable to BSD systems.  I was kind of
new at using signals when I wrote it, so it could probably be improved a
bit.  I really don't want to spend any time thinking about it.  This is, of
course, not guaranteed to do anything useful.  It's not even guaranteed to
not trash your system (although I can't imagine how it could :-).  Every
architecture is going to generate timer interrupts at different intervals.
Also, there's no guarantee that you'll get the right amount of time even
given the correct intervals because in UNIX, you may be waiting to get
swapped in.  I should probably test it on our VAX but I'm too lazy.

------------------------------ cut here ----------------------------------

/*******************************************************************************
*
*	FSLEEP.C - Fine sleep.  This function allows you to sleep for
*	smaller intervals of time than 1 second.
*
*	SYNOPISIS
*		void fsleep( secs, usecs )
*		long secs, usecs;
*
*	secs is the number of seconds.
*	usecs is the number of milleseconds.
*
*	LIBRARY FUNCTIONS
*		setitimer(2)
*		signal(3C)
*		sigsetmask(2)
*		sigpause(2)
*
*	The number of milliseconds is misleading.  It is limited by the
*	resolution of the actual timers which is 10 milleseconds on an
*	Accel.
*
*	Note that the manual page incorrectly identifies the timer
*	intervals as being setable to microseconds.  It really meant
*	milleseconds (either that, or whoever set up setitimer on our
*	machine made a mistake).  When I first tried it (naively
*	believing the manual) I used 500000 for usecs thinking it
*	would be half a second instead of 500 seconds which is what
*	it was.
*
*******************************************************************************/

#include <stdio.h>
#include <time.h>
#include <signal.h>

#define	valsec	it_value.tv_sec
#define	valusec	it_value.tv_usec
#define	intsec	it_interval.tv_sec
#define	intusec	it_interval.tv_usec

static void fsleeptrap()
{
	/* Zen function */
}

void fsleep( secs, usecs )
unsigned long secs, usecs;
{
    int  omask, (*osig)();
    struct itimerval tval[2];

    osig = signal( SIGALRM, fsleeptrap );	/* set the trap */

    if ( usecs >= 1000L ){			/* fix the interval */
	secs += usecs / 1000L;
	usecs %= 1000L;
    }
    tval[1].intsec  = tval[1].intusec = 0L;
    tval[1].valsec  = secs;
    tval[1].valusec = usecs;

    omask = sigsetmask( ( 1 << (SIGALRM-1) ) );
    setitimer( 0, &tval[1], &tval[0] );
    sigpause( 0 );				/* wait for the timer */

    signal( SIGALRM, osig );			/* reset the old trap */
    setitimer( 0, &tval[0], &tval[1] );
    sigsetmask( omask );

    return;
}

------------------------------ cut here --------------------------------

Ever notice how much more you enjoy sleeping as you get older?

Bill Davidson			.....!ucsd!celerity!billd

daveb@gonzo.UUCP (Dave Brower) (11/05/88)

In article <2804@ingr.UUCP> crossgl@ingr.UUCP (Gordon Cross) writes:
>In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
>>
>> The Unix sleep command will only go in increments of one second.  I was
>> wondering if someone new of a nice little routine I could use, or has
>> written one that will let me pause (in the Unix operating system) for
>> a fraction of a second.  If it could go to 100th of a second, that would
>> be great!
>
>You are not going to be able to do this without coding up some kind of
>"delay loop" yourself...

Unless you are:

	* on a BSD machine, with setitimer()

	* on most any machine with select(), where you can do a sub-second
		timeout value.

	* on a V.3 machine with poll(), which _i think_ has a sub-second
		timeout value.  (I'm sure I'll be corrected if wrong :-)

-dB

robert@pvab.UUCP (Robert Claeson) (11/06/88)

In article <12514@steinmetz.ge.com>, davidsen@steinmetz.ge.com (William E. Davidsen Jr) writes:

> There is a system call "nap" in Xenix, which is in ms. My notes on V.4
> indicate that it will be there as well.

In fact, the nap() system call is there in System V, Release 3.2.-- 
Robert Claeson, ERBE DATA AB, P.O. Box 77, S-175 22 Jarfalla, Sweden
Tel: +46 758-202 50   Fax: +46 758-197 20
EUnet: rclaeson@erbe.se   ARPAnet: rclaeson%erbe.se@uunet.uu.net

mikef@wyn386.UUCP (Mike Faber) (11/07/88)

If you wanted to be fancy (and don't need type ahead)  you could flush the 
stdin buffer, set term.c_iflag(?) &= ~ICANON, and 
term.c_cc[VTIME] = (# of tenths you wanted tyo wait), and
read from stdin (getchar())..  But only if you didn;t need the type ahead...

IF all else fails, follow plumbers rule #1:

If it dont fit, force it.  If it cbreaks(), it didn't belong there in the 
first place...

Or something like that...


-- 
   _   _                  | My employer and sysop do not think,
  (/  (/  _  _   _   _    | so they cannot share my opinions.
 (/)  /\_(/_(/_/|_)_/ \_/ | Joe C Programmer (mikef@wynalda.uucp)  work
               (|     (|  | Michael Faber    (sleepy@wybbs.uucp)   play

billd@celerity.UUCP (Bill Davidson) (11/08/88)

Well, it seems that I have to flame myself:

In article <191@celerity.UUCP> billd@celerity.UUCP (Bill Davidson) writes:
>In article <1145@orion.cf.uci.edu>, echarne@orion.cf.uci.edu (Eli B. Charne) writes:
>> 
.....
>> a fraction of a second.  If it could go to 100th of a second, that would
>> be great!
>
.....
>given the correct intervals because in UNIX, you may be waiting to get
>swapped in.  I should probably test it on our VAX but I'm too lazy.
>*	FSLEEP.C - Fine sleep.  This function allows you to sleep for
>*	smaller intervals of time than 1 second.
.....
>*	Note that the manual page incorrectly identifies the timer
>*	intervals as being setable to microseconds.  It really meant
>*	milleseconds (either that, or whoever set up setitimer on our
>*	machine made a mistake).  When I first tried it (naively
>*	believing the manual) I used 500000 for usecs thinking it
>*	would be half a second instead of 500 seconds which is what
>*	it was.

A kernel type engineer here informed me that this was fixed a LONG time ago
and that it now works in microseconds on our machine.  Of course, this means
that my program is wrong as well.  This is the part that needs to be changed:

>    if ( usecs >= 1000L ){			/* fix the interval */
>	secs += usecs / 1000L;
>	usecs %= 1000L;
>    }

All of the 1000L's should be changed to 1000000L's to reflect the microseconds.
I should have assumed that other people's setitimer's worked correctly when
I posted anyway.  If anyone picked up my code, then they should make this
change and it *should* work (but as I said before, I don't personally
guarantee anything).  I suppose this really belongs in comp.unix.questions
but this is where the previous things were posted.  There doesn't seem to
be *any* portable way to write a delay function with delays < 1 second.
On UNIX, ANY delay function is going to have an accuracy problem.  Setitimer
could have a smallest interval of 1/100 sec and there would probably be no
functional difference.

As long as I flaming myself, I'll also flame the guy who suggested spinning
delay loops:
	ACK! GAG! BARF! :-(

	--Bill Davidson

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
....!{ucsd|sdcsvax}!celerity!billd

friedl@vsi.COM (Stephen J. Friedl) (11/08/88)

William E. Davidsen Jr. writes:
> There is a system call "nap" in Xenix, which is in ms. My notes on V.4
> indicate that it will be there as well.

Robert Claeson writes:
> In fact, the nap() system call is there in System V, Release 3.2.-- 

Hmmm.  Dollars to donuts that System V Release 3.2 provides nap()
only on the 80286 and 80386 processors; I find it unlikely that 3B2
will have the Xenix migration code.  In any case, none of the AT&T
3B2 C compilers currently shipping include nap() in the C libraries.

     Steve

-- 
Steve Friedl    V-Systems, Inc.  +1 714 545 6442    3B2-kind-of-guy
friedl@vsi.com     {backbones}!vsi.com!friedl    attmail!vsi!friedl
------------Nancy Reagan on the worm: "Just say OH NO!"------------

crossgl@ingr.UUCP (Gordon Cross) (11/09/88)

In article <26678@ucbvax.BERKELEY.EDU>, jas@ernie.Berkeley.EDU (Jim Shankland) writes:
> 
> Never trust statements about the UNIX kernel from people who can't even
> spell the word.

Every so often this sort of thing pops up:  people abusing other people about
spelling errors.  This often (once started) gets out of hand as everyone
begins "flaming" other's spelling and/or punctuation errors swamping the net
with meaningless dribble.  So please if you wish to correct someone on a
spelling error, how about e-mail...

Now down to business...
In a previous article I wrote the following in response to a question regarding
how to sleep for a period of time less than one second in C:
>
> You are not going to be able to do this without coding up some kind of
> "delay loop" yourself.  Of course that solution is definitely NOT portable in
> any way since the loop would have to be fine tuned to your machines execution
> speed.  Remember that in the UNIX kernel, scheduled wakeups occur at fixed
> one second intervals.  Thus, unless you are using a non standard kernel,
> sleeps of only whole numbers of seconds are possible!

I have of course been catching some heat (from the flames :-)) regarding this
response.  And I must say it is well deserved!  In my attempt to keep the
answer as short as possible, I oversimplified the problem.  I also neglected
to mention that I would not actually RECOMMEND a "delay loop" since other
approaches (ie. NOT requiring sleeps of less than one second) are almost always
available.  Several responses to this question mentioned other methods whereby
this could be accomplished.  Each of these solutions rely on mechanisms (such
as BSD's sockets) not available on all UNIX implementations.  I was just
attempting to come up with a method that would be workable (if you absolutly
just HAD to have sub-second waits) on any implementation.  Sorry about the
confusion!


Gordon Cross
Intergraph Corp.  Huntsville, AL