* sysdeps/mach/_strerror.c (__strerror_r): Add libc_hidden_def.
[glibc.git] / sysdeps / unix / sysv / linux / sleep.c
blobb73032263b07ae296dd60f670ed0e598fcb64db2
1 /* Implementation of the POSIX sleep function using nanosleep.
2 Copyright (C) 1996, 1997, 1998, 1999 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 <unistd.h>
26 /* We are going to use the `nanosleep' syscall of the kernel. But the
27 kernel does not implement the sstupid SysV SIGCHLD vs. SIG_IGN
28 behaviour for this syscall. Therefore we have to emulate it here. */
29 unsigned int
30 __sleep (unsigned int seconds)
32 struct timespec ts = { tv_sec: (long int) seconds, tv_nsec: 0 };
33 sigset_t set, oset;
34 unsigned int result;
36 /* This is not necessary but some buggy programs depend on this. */
37 if (seconds == 0)
38 return 0;
40 /* Linux will wake up the system call, nanosleep, when SIGCHLD
41 arrives even if SIGCHLD is ignored. We have to deal with it
42 in libc. We block SIGCHLD first. */
43 if (__sigemptyset (&set) < 0
44 || __sigaddset (&set, SIGCHLD) < 0
45 || __sigprocmask (SIG_BLOCK, &set, &oset))
46 return -1;
48 /* If SIGCHLD is already blocked, we don't have to do anything. */
49 if (!__sigismember (&oset, SIGCHLD))
51 int saved_errno;
52 struct sigaction oact;
54 if (__sigemptyset (&set) < 0 || __sigaddset (&set, SIGCHLD) < 0)
55 return -1;
57 /* We get the signal handler for SIGCHLD. */
58 if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
60 saved_errno = errno;
61 /* Restore the original signal mask. */
62 (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
63 __set_errno (saved_errno);
64 return -1;
67 if (oact.sa_handler == SIG_IGN)
69 /* We should leave SIGCHLD blocked. */
70 result = __nanosleep (&ts, &ts);
72 saved_errno = errno;
73 /* Restore the original signal mask. */
74 (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
75 __set_errno (saved_errno);
77 else
79 /* We should unblock SIGCHLD. Restore the original signal mask. */
80 (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
81 result = __nanosleep (&ts, &ts);
84 else
85 result = __nanosleep (&ts, &ts);
87 if (result != 0)
88 /* Round remaining time. */
89 result = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
91 return result;
93 weak_alias (__sleep, sleep)