home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * $Source: /unixb/home/unixlib/source/unixlib37/src/signal/c/RCS/sleep,v $
- * $Date: 1996/10/30 22:04:51 $
- * $Revision: 1.1 $
- * $State: Rel $
- * $Author: unixlib $
- *
- * $Log: sleep,v $
- * Revision 1.1 1996/10/30 22:04:51 unixlib
- * Initial revision
- *
- ***************************************************************************/
-
- static const char rcs_id[] = "$Id: sleep,v 1.1 1996/10/30 22:04:51 unixlib Rel $";
-
- /* signal.c.sleep: Written by Nick Burrett, 6 October 1996. */
-
- #include <signal.h>
- #include <time.h>
- #include <unistd.h>
- #include <errno.h>
-
- /* SIGALRM signal handler for `sleep'. This does nothing but return,
- but SIG_IGN isn't supposed to break `pause'. */
- static void sleep_handler (int sig)
- {
- sig = 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). */
- unsigned int sleep (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. */
- sigemptyset (&set);
- if (sigaddset (&set, SIGALRM) || sigprocmask (SIG_BLOCK, &set, &oset))
- return seconds;
-
- act.sa_handler = sleep_handler;
- act.sa_flags = 0;
- sigemptyset (&act.sa_mask);
- if (sigaction (SIGALRM, &act, &oact))
- return seconds;
-
- before = time ((time_t *) NULL);
- remaining = alarm (seconds);
-
- #ifdef DEBUG
- printf ("sleep: Set up an alarm for %d seconds time.\n", seconds);
- #endif
-
- 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. */
- sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
- alarm (remaining); /* Restore sooner alarm. */
- #ifdef DEBUG
- printf ("sleep: A user alarm existed. Wait %d secs for that instead\n", remaining);
- #endif
- sigsuspend (&oset); /* Wait for it to go off. */
- #ifdef DEBUG
- printf ("sleep: Alarm has now gone off. Continuing with execution\n");
- #endif
- 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. */
- #ifdef DEBUG
- printf ("sleep: Waiting for the alarm\n");
- #endif
- sigsuspend (&oset);
- #ifdef DEBUG
- printf ("sleep: Alarm has now gone off. Continuing with execution\n");
- #endif
- after = time ((time_t *) NULL);
-
- /* Restore the old signal action state. */
- sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
- }
-
- /* Notice how long we actually slept. */
- slept = (unsigned int)(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. */
- alarm (remaining > slept ? remaining - slept : 0);
-
- /* Restore the original signal mask. */
- 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 don't care. */
- errno = save;
-
- return slept > seconds ? 0 : seconds - slept;
- }
-