Subject: race in sleep.
To: None <pk@cs.few.eur.nl>
From: Gordon W. Ross <gwr@mc.com>
List: tech-kern
Date: 10/16/1995 17:13:27
> From: Paul Kranenburg <pk@cs.few.eur.nl>
> Date: Mon, 16 Oct 1995 20:29:50 +0100 (MET)

> I just changed libc/gen/[u]sleep.c to be less susceptible to SIGALRMs
> coming in too late when other signal handlers are also active.
> 
> I also realized that the change makes another race possible:
> a previous SIGALRM handler might now miss a signal because the sihnal mask
> is reset earlier. I can't see a way out of this without adding one more
> system call (to the eight which are already there as smartly pointed out
> by th eman-page).
> 
> Thoughts?
> 
> -pk

Well, maybe longer term we could provide some of the system calls
that would be needed if we did realtime signals, in this case:

extern int sigtimedwait(const sigset_t *want, siginfo_t *info,
			const struct timespec *tmo);

which lets you synchronously wait for any signal, either blocked
or not.  Unblocked signals wake you as with sleep, but you can
ask for sigtimedwait to return if any blocked signal in "want"
becomes pending as well (interesting, but not needed here).

I haven't looked carefully at the POSIX definition of sleep(), but
if any unblocked signal is supposed to end your sleep, then the
implementation of sleep() using sigtimedwait is trivial:
(Just one system call, I think.)

unsigned int
sleep(seconds)
	unsigned int seconds;
{
	struct timespec sleep_time;
	sigset_t blocked_wake;

	/*
	 * Any signals in this set will wake us even if blocked.
	 * None are set, because sleep is ends only when an
	 * unblocked signal occurs, or the timeout expires.
	 */
	sigemptyset(&blocked_wake);

	sleep_time.tv_sec = seconds;
	sleep_time.tv_nsec = 0;

	sigtimedwait(&blocked_wake, NULL, &sleep_time);
}