Date: Sun, 18 May 1997 11:28:07 +0400 (MSD) From: =?KOI8-R?B?4c7E0sXKIP7F0s7P1w==?= <ache@nagual.pp.ru> To: Peter Wemm <peter@spinner.dialix.com> Cc: Bruce Evans <bde@zeta.org.au>, peter@FreeBSD.ORG, cvs-all@FreeBSD.ORG, cvs-committers@FreeBSD.ORG, cvs-lib@FreeBSD.ORG Subject: Re: cvs commit: src/lib/libc/gen sleep.c Message-ID: <Pine.BSF.3.96.970518105438.711B-100000@nagual.pp.ru> In-Reply-To: <199705180620.OAA04512@spinner.DIALix.COM>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 18 May 1997, Peter Wemm wrote: > The SVR4.0 man page for sleep(3c) says: > ... > The routine is implemented by setting an alarm signal and pausing until > it (or some other signal) occurs. The previous state of the alarm signal > is saved and restored. The calling program may have set up an alarm > signal before calling sleep. [..guff about adjusting alarm(2)..] > ... > > ie: traditional sleep(3) behavior is that any signal interrupts the sleep. Hmm. It looks like SYSVism. SunOS man page for sleep(3b) says: SIGALRM should _n_o_t be blocked or ignored during a call to sleep(). Only a prior call to alarm(2) should generate SIGALRM for the calling process during a call to sleep(). A signal-catching function should _n_o_t interrupt a call to sleep() to call siglongjmp(3C) or longjmp(3C) to restore an environment saved prior to the sleep() call. and old implementation don't pay attention on catched signals too. BTW, I am not shure we should keep it. In any case, _ignored_ signals should not interrupt sleep. There are some other maybe useful notes from the same place: sleep() is implemented by setting an interval timer and pausing until it expires. The previous state of this timer is saved and restored. If the sleep time exceeds the time to the expiration of the previous value of the timer, the process sleeps only until the timer would have expired, and the signal which occurs with the expiration of the timer is sent one second later. I see GNU libc sleep.c does some additional efforts to handle alarms which are set before sleep is started: /* SIGALRM signal handler for `sleep'. This does nothing but return, but SIG_IGN isn't supposed to break `pause'. */ static void sleep_handler (sig) int sig; { return; } /* Make the process sleep for SECONDS seconds, or until a signal arrives and is not ignored. The function returns the number of seconds less than SECONDS which it actually slept (zero if it slept the full time). If a signal handler does a `longjmp' or modifies the handling of the SIGALRM signal while inside `sleep' call, the handling of the SIGALRM signal afterwards is undefined. There is no return value to indicate error, but if `sleep' returns SECONDS, it probably didn't work. */ unsigned int sleep (seconds) unsigned int seconds; { unsigned int remaining, slept; time_t before, after; sigset_t set, oset; struct sigaction act, oact; int save = errno; if (seconds == 0) return 0; /* Block SIGALRM signals while frobbing the handler. */ if (sigemptyset (&set) < 0 || sigaddset (&set, SIGALRM) < 0 || sigprocmask (SIG_BLOCK, &set, &oset)) return seconds; act.sa_handler = sleep_handler; act.sa_flags = 0; act.sa_mask = oset; /* execute handler with original mask */ if (sigaction (SIGALRM, &act, &oact) < 0) return seconds; before = time ((time_t *) NULL); remaining = alarm (seconds); if (remaining > 0 && remaining < seconds) { /* The user's alarm will expire before our own would. Restore the user's signal action state and let his alarm happen. */ (void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL); alarm (remaining); /* Restore sooner alarm. */ sigsuspend (&oset); /* Wait for it to go off. */ after = time ((time_t *) NULL); } else { /* Atomically restore the old signal mask (which had better not block SIGALRM), and wait for a signal to arrive. */ sigsuspend (&oset); after = time ((time_t *) NULL); /* Restore the old signal action state. */ (void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL); } /* Notice how long we actually slept. */ slept = after - before; /* Restore the user's alarm if we have not already past it. If we have, be sure to turn off the alarm in case a signal other than SIGALRM was what woke us up. */ (void) alarm (remaining > slept ? remaining - slept : 0); /* Restore the original signal mask. */ (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL); /* Restore the `errno' value we started with. Some of the calls we made might have failed, but we didn't care. */ __set_errno (save); return slept > seconds ? 0 : seconds - slept; } -- Andrey A. Chernov <ache@null.net> http://www.nagual.pp.ru/~ache/
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.96.970518105438.711B-100000>