[comp.lang.c] msleep

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (11/09/87)

/**************************************************************************
 *                                                                        *
 *                        msleep                                          *
 *                                                                        *
 **************************************************************************

   Purpose :   What you all been waiting for -- A sleep that works in
	     microseconds!!!.  Actually it depends on the granularity
	     of the interrupt timer, but at least its better than
	     the second wait.

   Programmer : Eddie Wyatt (orginally written by Paul Allen)
 
   Date : November 1987

   Input :  
	sec - number of seconds to sleep
	msec - number of micro seconds to sleep 

   Output : None

   Locals : 
	off - itimer value to turn off the timer interrupt.
	time - wait time
	oldtime - old itime value
	bob - the old interrupt handler

   Globals : 

 ************************************************************************/

#include <signal.h>
#include <sys/time.h>

/* ARGSUSED */
static int signal_handler(sig,code,scp)
    int sig, code;
    struct sigcontext *scp;
    { 
    return(1);
    }

static struct itimerval off = {{0,0},{0,0}};


void msleep(sec,msec)
    int sec, msec;
    {
    struct itimerval time;
    struct itimerval oldtime;
    int (*bob)();

    if ((sec == 0) && (msec == 0)) return;

	/* note that we have the timer interrupting continously as
	   oppose to just once.  This is because if we were to
	   install the itimer to interrupt just once, there would be a
	   critial section (the space between setitimer and sigpause)
	   where if the interrupt sound then, it would be lost and
	   we would wait forever in sigpause */

    time.it_interval.tv_sec = sec;
    time.it_interval.tv_usec = msec;

    time.it_value.tv_sec = sec;
    time.it_value.tv_usec = msec;

	/* insert my interrupt handler and itimer val (order matters) while
	   saving old values to be re-instated */

    bob = signal(SIGALRM, signal_handler);
    if (setitimer(ITIMER_REAL, &time, &oldtime) < 0)
	perror("setitimer");

	/* wait until an interrupt happens, hopefully a timer interrupt -
	  but it need not be. */
    
    sigpause(0);

	/* turn timer off while returning timer and interrupt handler
	   back to the old state (order matters) */

    if (setitimer(ITIMER_REAL, &off, (struct itimerval *) 0) < 0)
	perror("setitimer");

    if ((int) signal(SIGALRM, bob) == -1)
	perror("signal");

    if (setitimer(ITIMER_REAL, &oldtime, (struct itimerval *) 0))
	perror("setitimer");
    }

-- 
That one looks Jewish -- And that one's a coon -- Who let all this riff raff
into the room -- There's one smoking a joint -- and Anoter with spots -- If
I had my way -- I'd have all of you shot ... Pink Floyd, "In the Flesh"
Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

bader+@andrew.cmu.edu (Miles Bader) (11/10/87)

>   Purpose :   What you all been waiting for -- A sleep that works in
>	     microseconds!!!.  Actually it depends on the granularity

I've always used select(0,0,0,0,&tv) for this; is there anything wrong with
doing this?

					-Miles

ruiu@tic.UUCP (Dragos Ruiu) (11/10/87)

In article <UVZXqQy00UkayG00yf@andrew.cmu.edu>, bader+@andrew.cmu.edu (Miles Bader) writes:
> >   Purpose :   What you all been waiting for -- A sleep that works in
> >	     microseconds!!!.  Actually it depends on the granularity
> I've always used select(0,0,0,0,&tv) for this; is there anything wrong with
> doing this?
> 					-Miles

  It only works if you happen to be using BSD. Some people don't have sockets!



-- 
Dragos Ruiu          Disclaimer: My opinons are my employer's, I'm unemployed!
            UUCP:{ubc-vision,mnetor,vax135,ihnp4}!alberta!edson!tic!dragos!work
(403) 432-0090         #1705, 8515 112th Street, Edmonton, Alta. Canada T6G 1K7 
Never play leapfrog with Unicorns...

chris@mimsy.UUCP (Chris Torek) (11/12/87)

In article <332@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>/**************************************************************************
> *                                                                        *
> *                        msleep                                          *
> *                                                                        *
> **************************************************************************
>
>   Purpose :   What you all been waiting for -- A sleep that works in
>	     microseconds!!!.  Actually it depends on the granularity
>	     of the interrupt timer, but at least its better than
>	     the second wait.

... followed by code that uses setitimer.

0) Only certain 4BSD-based operating systems *have* setitimer.
   (What this *really* means is that if you need a sleep that works
   in milliseconds or microseconds or whatever, using a routine
   like msleep is imperative.  Then the victim, er, user, of your
   code need rewrite only msleep.)

1) you can (and, I think, should) avoid the critical section by using
   sigblock and sigsetmask (see man 2 sigblock).

2) using setitimer is more expensive than calling select with three
   `(fd_set *)0' arguments.  Select does have one problem: like
   sigpause, it is interrupted by signals; unlike sigpause, it does
   not take a signal mask, so it sometimes has unavoidable critical
   sections.  (Yes, I want a sixth argument to select!)

3) The actual granularity of interval timers (including select timers):

	system				granularity
	4.[23]BSD Vax			10 ms
	Sun[23] running SunOS 3.x	20 ms
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (11/17/87)

In article <9310@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> 
> 0) Only certain 4BSD-based operating systems *have* setitimer.
>    (What this *really* means is that if you need a sleep that works
>    in milliseconds or microseconds or whatever, using a routine
>    like msleep is imperative.  Then the victim, er, user, of your
>    code need rewrite only msleep.)
> 
> 1) you can (and, I think, should) avoid the critical section by using
>    sigblock and sigsetmask (see man 2 sigblock).
> 
> 2) using setitimer is more expensive than calling select with three
>    `(fd_set *)0' arguments.  Select does have one problem: like
>    sigpause, it is interrupted by signals; unlike sigpause, it does
>    not take a signal mask, so it sometimes has unavoidable critical
>    sections.  (Yes, I want a sixth argument to select!)
> 
> 3) The actual granularity of interval timers (including select timers):
> 
> 	system				granularity
> 	4.[23]BSD Vax			10 ms
> 	Sun[23] running SunOS 3.x	20 ms
> -- 
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
> Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

   Sorry about #0, I didn't know SYSV doesn't provide itimers.


   #1 Sorry, I think critical section was a misnomer for what I meant.  The
problem that I was describing had to do with setting the itimer up
such that it interrupts only once (the second half of the structure set
to zeros).    If the ONLY timer interrupt was to come during the period
between the call to setitimer and  sigpause, my interrupt handle
would be called and then NOTHING would happen in sigpause to
make sigpause exit.  The only timer interrupt sounded would not have
caused sigpause to exit, since it sounded BEFORE entering into sigpause.
This is the rational behind using continuous interrupts (the second half
of the structure not set to zeros) when at first glance, someone might
think you could get away with just one.

BTW, yes I'm very familiar with the sigblock and sigsetmask functions,
they are not needed to implement this facility, setitimer suffices.


   Point two about setitimer being slower.  Does that really make
sense to complain about how long setitimer takes as compared to 
select!!!  If the interrupt timer's granularity is 10 millisecs, 
both select and msleep will usually time out at the same time (setitimer
has to be in the order of 100 micros per call).  Statistically though,
msleep should have a mean wait time that is a little longer than select.

  Also, don't you consider the use of select as a timer to be an
abuse of the function?  Then again, are you one that argues,
vfork is avid way to get shared mem in BSD. ;-)
-- 
That one looks Jewish -- And that one's a coon -- Who let all this riff raff
into the room -- There's one smoking a joint -- and Anoter with spots -- If
I had my way -- I'd have all of you shot ... Pink Floyd, "In the Flesh"
Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu