Back to index

glibc  2.9
sleep.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <signal.h>
00020 #include <time.h>
00021 #include <unistd.h>
00022 #include <errno.h>
00023 
00024 
00025 /* SIGALRM signal handler for `sleep'.  This does nothing but return,
00026    but SIG_IGN isn't supposed to break `pause'.  */
00027 static void
00028 sleep_handler (int sig)
00029 {
00030   return;
00031 }
00032 
00033 /* Make the process sleep for SECONDS seconds, or until a signal arrives
00034    and is not ignored.  The function returns the number of seconds less
00035    than SECONDS which it actually slept (zero if it slept the full time).
00036    If a signal handler does a `longjmp' or modifies the handling of the
00037    SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
00038    signal afterwards is undefined.  There is no return value to indicate
00039    error, but if `sleep' returns SECONDS, it probably didn't work.  */
00040 unsigned int
00041 __sleep (unsigned int seconds)
00042 {
00043   unsigned int remaining, slept;
00044   time_t before, after;
00045   sigset_t set, oset;
00046   struct sigaction act, oact;
00047   int save = errno;
00048 
00049   if (seconds == 0)
00050     return 0;
00051 
00052   /* Block SIGALRM signals while frobbing the handler.  */
00053   if (sigemptyset (&set) < 0 ||
00054       sigaddset (&set, SIGALRM) < 0 ||
00055       sigprocmask (SIG_BLOCK, &set, &oset))
00056     return seconds;
00057 
00058   act.sa_handler = sleep_handler;
00059   act.sa_flags = 0;
00060   act.sa_mask = oset;       /* execute handler with original mask */
00061   if (sigaction (SIGALRM, &act, &oact) < 0)
00062     return seconds;
00063 
00064   before = time ((time_t *) NULL);
00065   remaining = alarm (seconds);
00066 
00067   if (remaining > 0 && remaining < seconds)
00068     {
00069       /* The user's alarm will expire before our own would.
00070         Restore the user's signal action state and let his alarm happen.  */
00071       (void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
00072       alarm (remaining);    /* Restore sooner alarm.  */
00073       sigsuspend (&oset);   /* Wait for it to go off.  */
00074       after = time ((time_t *) NULL);
00075     }
00076   else
00077     {
00078       /* Atomically restore the old signal mask
00079         (which had better not block SIGALRM),
00080         and wait for a signal to arrive.  */
00081       sigsuspend (&oset);
00082 
00083       after = time ((time_t *) NULL);
00084 
00085       /* Restore the old signal action state.  */
00086       (void) sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
00087     }
00088 
00089   /* Notice how long we actually slept.  */
00090   slept = after - before;
00091 
00092   /* Restore the user's alarm if we have not already past it.
00093      If we have, be sure to turn off the alarm in case a signal
00094      other than SIGALRM was what woke us up.  */
00095   (void) alarm (remaining > slept ? remaining - slept : 0);
00096 
00097   /* Restore the original signal mask.  */
00098   (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
00099 
00100   /* Restore the `errno' value we started with.
00101      Some of the calls we made might have failed, but we didn't care.  */
00102   __set_errno (save);
00103 
00104   return slept > seconds ? 0 : seconds - slept;
00105 }
00106 weak_alias (__sleep, sleep)