Re: My versin of sleep... comments?
From: Michael Kerrisk (michael.kerrisk_at_freenet.de)
Date: 04/29/03
- Next message: xinit: "Re: after strncpy"
- Previous message: Michael Kerrisk: "Re: queued signals, sigwait[info], and sigaction"
- In reply to: Marc Rochkind: "My versin of sleep... comments?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Date: Tue, 29 Apr 2003 08:27:16 +0200
On Mon, 28 Apr 2003 18:55:48 -0600, "Marc Rochkind"
<rochkind@basepath.com> wrote:
>For a book I'm writing, here's my version of sleep that's supposed to
>properly handle interaction with alarm, restoring the signal mask and old
>action for SIGALRM, and eliminate race conditions. I'd appreciate any
>comments about defects.
>
>You may want to know that this function works on Solaris, SuSE Linux, and
>FreeBSD, all with a Gnu compiler.
>
>Two points:
>
>1. It's not supposed to be better than what the Single UNIX Specification
>requires. That document lists lots of ways in which SIGALRM and sleep
>interfere with one another, as well as a few other interactions whose
>behavior is unspecified.
You're aware that many implementations of sleep() avoid alrm
altogether, by making a call to a nanonsleep() system call or similar?
>2. The ec_neg1, EC_FAIL (a goto, in effect), and EC_CLEANUP_* macros are my
>way of handling errors. Please ignore that stuff, as error checking is not
>part of the exercise. (The real sleep doesn't even return errors.)
I think I liked the style in your 1st ed. better...
>There are some other comments at the end of the code.
>
>unsigned my_sleep(unsigned secs)
>{
> sigset_t set, oset;
> struct sigaction act, oact;
> unsigned prev_alarm, slept, unslept, effective_secs;
>
> ec_neg1( sigemptyset(&set) )
> ec_neg1( sigaddset(&set, SIGALRM) )
> ec_neg1( sigprocmask(SIG_BLOCK, &set, &oset) )
> memset(&act, 0, sizeof(act));
> act.sa_handler = slp_handler;
> ec_neg1( sigaction(SIGALRM, &act, &oact) )
> prev_alarm = alarm(0);
> if (prev_alarm < secs)
> effective_secs = secs - prev_alarm;
> else
> effective_secs = secs;
> alarm(effective_secs);
> set = oset;
> ec_neg1( sigdelset(&set, SIGALRM) )
> if (sigsuspend(&set) == -1 && errno != EINTR)
> EC_FAIL
> unslept = alarm(0);
> slept = effective_secs - unslept;
> ec_neg1( sigaction(SIGALRM, &oact, NULL) )
> if (slept >= prev_alarm) {
> if (oact.sa_handler != SIG_IGN && oact.sa_handler != SIG_DFL &&
>oact.sa_handler != NULL)
> (*oact.sa_handler)(SIGALRM);
> }
> else
> alarm(prev_alarm - slept);
> ec_neg1( sigprocmask(SIG_SETMASK, &oset, NULL) )
> return unslept;
>
>EC_CLEANUP_BGN
> EC_FLUSH("aup_sleep")
> return 0;
>EC_CLEANUP_END
>}
>
>static void slp_handler(int signum)
>{
>}
>
>
>Here's what's going on, step-by-step:
>
>1. We block SIGALRM so we can proceed without worrying about one being
>delivered. We save the old signal mask in oset.
>
>2. We install the empty handler and save the old action in oact.
>
>3. We turn off the alarm, in case it's set, and save the remaining time.
>
>4. We calculate how long to sleep, reducing the amount requested if the
>remaining alarm time was less, and set an alarm for that time.
>
>5. We call sigsuspend (instead of pause) so that we can atomically unblock
>SIGALRM. We leave the other bits in the mask the way they were on entry to
>my_sleep.
>
>6. When sigsuspend returns, it's because the alarm went off or because some
>other signal interrupted it. We don't really care which it was. We do need
>the amount remaining on the alarm, which we get when we turn it off.
>
>7. We calculate the amount of time actually slept.
>
>8. We reset the old action for SIGALRM.
>
>9. If the time slept is greater than or equal to the remaining alarm time on
>entry, we have to artificially call the SIGALRM handler that was set on
>entry, if any, because it would have gone off if we hadn't tampered with it.
This is one way of doing things (at least SUSv3 implies that one may
have to do it). An alternative, which I prefer, is in step 2, to only
install your handler if the sleep interval is <= any outstanding alarm
timer.
>10. If the time slept is less than the remaining alarm time on entry, we
>reset the alarm for the new time remaining (some was slept off).
>
>11. We reset the signal mask.
>
>12. We return the unslept time.
Cheers
Michael
- Next message: xinit: "Re: after strncpy"
- Previous message: Michael Kerrisk: "Re: queued signals, sigwait[info], and sigaction"
- In reply to: Marc Rochkind: "My versin of sleep... comments?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
|