Updated to fedora-glibc-20080802T0809
[glibc/history.git] / sysdeps / unix / sysv / linux / sleep.c
blob0e41a1133812db2ef79e56a53b7b19e8e1b50274
1 /* Implementation of the POSIX sleep function using nanosleep.
2 Copyright (C) 1996,1997,1998,1999,2003,2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <errno.h>
22 #include <time.h>
23 #include <signal.h>
24 #include <string.h> /* For the real memset prototype. */
25 #include <unistd.h>
26 #include <sys/param.h>
29 #if 0
30 static void
31 cl (void *arg)
33 (void) __sigprocmask (SIG_SETMASK, arg, (sigset_t *) NULL);
35 #endif
38 /* We are going to use the `nanosleep' syscall of the kernel. But the
39 kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
40 behaviour for this syscall. Therefore we have to emulate it here. */
41 unsigned int
42 __sleep (unsigned int seconds)
44 const unsigned int max
45 = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
46 struct timespec ts;
47 sigset_t set, oset;
48 unsigned int result;
50 /* This is not necessary but some buggy programs depend on this. */
51 if (__builtin_expect (seconds == 0, 0))
53 #ifdef CANCELLATION_P
54 CANCELLATION_P (THREAD_SELF);
55 #endif
56 return 0;
59 ts.tv_sec = 0;
60 ts.tv_nsec = 0;
61 again:
62 if (sizeof (ts.tv_sec) <= sizeof (seconds))
64 /* Since SECONDS is unsigned assigning the value to .tv_sec can
65 overflow it. In this case we have to wait in steps. */
66 ts.tv_sec += MIN (seconds, max);
67 seconds -= (unsigned int) ts.tv_sec;
69 else
71 ts.tv_sec = (time_t) seconds;
72 seconds = 0;
75 /* Linux will wake up the system call, nanosleep, when SIGCHLD
76 arrives even if SIGCHLD is ignored. We have to deal with it
77 in libc. We block SIGCHLD first. */
78 __sigemptyset (&set);
79 __sigaddset (&set, SIGCHLD);
80 if (__sigprocmask (SIG_BLOCK, &set, &oset))
81 return -1;
83 /* If SIGCHLD is already blocked, we don't have to do anything. */
84 if (!__sigismember (&oset, SIGCHLD))
86 int saved_errno;
87 struct sigaction oact;
89 __sigemptyset (&set);
90 __sigaddset (&set, SIGCHLD);
92 /* We get the signal handler for SIGCHLD. */
93 if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
95 saved_errno = errno;
96 /* Restore the original signal mask. */
97 (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
98 __set_errno (saved_errno);
99 return -1;
102 /* Note the sleep() is a cancellation point. But since we call
103 nanosleep() which itself is a cancellation point we do not
104 have to do anything here. */
105 if (oact.sa_handler == SIG_IGN)
107 //__libc_cleanup_push (cl, &oset);
109 /* We should leave SIGCHLD blocked. */
110 while (1)
112 result = __nanosleep (&ts, &ts);
114 if (result != 0 || seconds == 0)
115 break;
117 if (sizeof (ts.tv_sec) <= sizeof (seconds))
119 ts.tv_sec = MIN (seconds, max);
120 seconds -= (unsigned int) ts.tv_nsec;
124 //__libc_cleanup_pop (0);
126 saved_errno = errno;
127 /* Restore the original signal mask. */
128 (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
129 __set_errno (saved_errno);
131 goto out;
134 /* We should unblock SIGCHLD. Restore the original signal mask. */
135 (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
138 result = __nanosleep (&ts, &ts);
139 if (result == 0 && seconds != 0)
140 goto again;
142 out:
143 if (result != 0)
144 /* Round remaining time. */
145 result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
147 return result;
149 weak_alias (__sleep, sleep)