Subject: Re: usleep and signals
To: maximum entropy <entropy@zippy.bernstein.com>
From: Rick Byers <rickb@iaw.on.ca>
List: current-users
Date: 08/18/1997 11:47:43
On Mon, 18 Aug 1997, maximum entropy wrote:

> >I'm working on a program that will receive an alarm signal once a second.
> >It needs to sleep for a period of time.  How can I do this in a way that
> >is compatable with both -current and 1.2.1?  Using nanosleep (with a loop
> >to watch for the signal) works great under current, but nanosleep doesn't
> >exist under 1.2.1.  usleep works under 1.2.1, but doesn't return how much
> >time is left to sleep when a signal hits it (and the signal doesn't get
> >handled - unlike nanosleep).
> 
> You need to be very careful when mixing usleep() and alarm().  In
> historical systems (including 1.2.1), both use the same interval timer
> to schedule a SIGALRM.  Under POSIXish systems, sleep() makes some
> guarantees about delivery of the signal when mixed with alarm(), but
> usleep() doesn't make any similar guarantees.  This is probably why
> your signal isn't being handled in 1.2.1 -- usleep() is stealing
> SIGALRM for its own purposes.  Under current, both usleep() and
> sleep() are implemented using nanosleep(), most likely to avoid
> stealing alarms from user programs without going through really nasty
> contortions.

Ah, I see.  It looks like sleep operates pretty much the same way.  I
don't think they will clobber the alram (they check to see if the existing
alarm is scheduled before the one for itself and if so, use that), but
they won't call the old handler.  Both sleep and the old usleep do restore
the signal and timer to their previous values upon exit. 

> >Is there any easy way around this?  I'm thinking I'll have to resort to
> >turning off my alarm before the usleep, and turning it back on afterwards.
> >The only problem with this is that it doesn't get processed during the
> >sleep.  I guess I could make a loop of 1 second usleeps (or sleeps for
> >that matter), and call the handler inside the loop.  I assume nanosleep
> >was put in to avoid this kludge ?
> 
> How you deal with this depends on how long your program needs to
> sleep.  If it's a longish period of time, and a granularity of 1
> second is OK, you should be OK if you simply use sleep().  If it's a
> shorter period, your best bet for portability (at least amond BSDish
> systems) is to check the system clock using gettimeofday(), go to
> sleep for your short period using select(), call gettimeofday() when
> select() returns, calculate the remaining time to sleep, and continue
> looping.

Granularity of 1 second is fine.  But after looking at the source (I
didn't feel like thinking at it at 3:00am last night <grin>), I see a
problem.  Sleep will still respond to my timer even though I have set it
to ignore, and since my timer fires once a second, this poses the same
problem as just sleeping for the desired time.  The time difference
returned by sleep when it's interrupted is only accurate to the second.
The obvious work around is to simply dissable my timer, and re-enable it
afterwards.  I don't think I have to worry about changing the signal
handler because sleep does that for me.  Does this sound ok?

Your patch for usleep worked fine.  The nanosleep man page even says it
will return an error if tv_nsec is greater than 1 billion (1 second).  The
usleep man page should be changed to reflect the fact that usleep will
cancel upon receipt of a signal (and will set errno).  Personally, I don't
like this.  It should either ignore signals, or return the unslept time.
We could easily put the nanosleep in a loop and keep sleeping for the
unslept time to ensure usleep sleeps as long as it should.  Or is usleep
expected to return when a signal is delivered?

Thanks for your help!
	Rick 

=========================================================================
Rick Byers                                      Internet Access Worldwide
rickb@iaw.on.ca                                System Admin, Tech Support
Welland, Ontario, Canada                                    (905)714-1400
http://www.iaw.on.ca/rickb/                         http://www.iaw.on.ca/