Back to index

glibc  2.9
sleep.c
Go to the documentation of this file.
00001 /* Implementation of the POSIX sleep function using nanosleep.
00002    Copyright (C) 1996,1997,1998,1999,2003,2005 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <time.h>
00023 #include <signal.h>
00024 #include <string.h>  /* For the real memset prototype.  */
00025 #include <unistd.h>
00026 #include <sys/param.h>
00027 
00028 
00029 #if 0
00030 static void
00031 cl (void *arg)
00032 {
00033   (void) __sigprocmask (SIG_SETMASK, arg, (sigset_t *) NULL);
00034 }
00035 #endif
00036 
00037 
00038 /* We are going to use the `nanosleep' syscall of the kernel.  But the
00039    kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
00040    behaviour for this syscall.  Therefore we have to emulate it here.  */
00041 unsigned int
00042 __sleep (unsigned int seconds)
00043 {
00044   const unsigned int max
00045     = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
00046   struct timespec ts;
00047   sigset_t set, oset;
00048   unsigned int result;
00049 
00050   /* This is not necessary but some buggy programs depend on this.  */
00051   if (__builtin_expect (seconds == 0, 0))
00052     {
00053 #ifdef CANCELLATION_P
00054       CANCELLATION_P (THREAD_SELF);
00055 #endif
00056       return 0;
00057     }
00058 
00059   ts.tv_sec = 0;
00060   ts.tv_nsec = 0;
00061  again:
00062   if (sizeof (ts.tv_sec) <= sizeof (seconds))
00063     {
00064       /* Since SECONDS is unsigned assigning the value to .tv_sec can
00065         overflow it.  In this case we have to wait in steps.  */
00066       ts.tv_sec += MIN (seconds, max);
00067       seconds -= (unsigned int) ts.tv_sec;
00068     }
00069   else
00070     {
00071       ts.tv_sec = (time_t) seconds;
00072       seconds = 0;
00073     }
00074 
00075   /* Linux will wake up the system call, nanosleep, when SIGCHLD
00076      arrives even if SIGCHLD is ignored.  We have to deal with it
00077      in libc.  We block SIGCHLD first.  */
00078   __sigemptyset (&set);
00079   __sigaddset (&set, SIGCHLD);
00080   if (__sigprocmask (SIG_BLOCK, &set, &oset))
00081     return -1;
00082 
00083   /* If SIGCHLD is already blocked, we don't have to do anything.  */
00084   if (!__sigismember (&oset, SIGCHLD))
00085     {
00086       int saved_errno;
00087       struct sigaction oact;
00088 
00089       __sigemptyset (&set);
00090       __sigaddset (&set, SIGCHLD);
00091 
00092       /* We get the signal handler for SIGCHLD.  */
00093       if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
00094        {
00095          saved_errno = errno;
00096          /* Restore the original signal mask.  */
00097          (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
00098          __set_errno (saved_errno);
00099          return -1;
00100        }
00101 
00102       /* Note the sleep() is a cancellation point.  But since we call
00103         nanosleep() which itself is a cancellation point we do not
00104         have to do anything here.  */
00105       if (oact.sa_handler == SIG_IGN)
00106        {
00107          //__libc_cleanup_push (cl, &oset);
00108 
00109          /* We should leave SIGCHLD blocked.  */
00110          while (1)
00111            {
00112              result = __nanosleep (&ts, &ts);
00113 
00114              if (result != 0 || seconds == 0)
00115               break;
00116 
00117              if (sizeof (ts.tv_sec) <= sizeof (seconds))
00118               {
00119                 ts.tv_sec = MIN (seconds, max);
00120                 seconds -= (unsigned int) ts.tv_nsec;
00121               }
00122            }
00123 
00124          //__libc_cleanup_pop (0);
00125 
00126          saved_errno = errno;
00127          /* Restore the original signal mask.  */
00128          (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
00129          __set_errno (saved_errno);
00130 
00131          goto out;
00132        }
00133 
00134       /* We should unblock SIGCHLD.  Restore the original signal mask.  */
00135       (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
00136     }
00137 
00138   result = __nanosleep (&ts, &ts);
00139   if (result == 0 && seconds != 0)
00140     goto again;
00141 
00142  out:
00143   if (result != 0)
00144     /* Round remaining time.  */
00145     result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
00146 
00147   return result;
00148 }
00149 weak_alias (__sleep, sleep)