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 Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 see <http://www.gnu.org/licenses/>. */
26 /* version perusing nanosleep */
27 #if defined __UCLIBC_HAS_REALTIME__
29 /* I am unable to reproduce alleged "Linux quirk".
30 * I used the following test program:
34 static void dummy(int sig) {}
36 struct timespec t = { 2, 0 };
41 signal(SIGCHLD, SIG_DFL); //
42 signal(SIGCHLD, dummy); // Pick one
43 signal(SIGCHLD, SIG_IGN); //
47 * Testing on 2.4.20 and on 2.6.35-rc4:
48 * With SIG_DFL, nanosleep is not interrupted by SIGCHLD. Ok.
49 * With dummy handler, nanosleep is interrupted by SIGCHLD. Ok.
50 * With SIG_IGN, nanosleep is NOT interrupted by SIGCHLD.
51 * It looks like sleep's workaround for SIG_IGN is no longer needed?
52 * The only emails I can find are from 1998 (!):
54 * Subject: Re: sleep ignore sigchld
55 * From: Linus Torvalds <torvalds@transmeta.com>
56 * Date: Mon, 16 Nov 1998 11:02:15 -0800 (PST)
58 * On Mon, 16 Nov 1998, H. J. Lu wrote:
59 * > That is a kernel bug. SIGCHLD is a special one. Usually it cannot
60 * > be ignored. [snip...]
64 * "nanosleep()" is implemented in a bad way that makes it impossible to
65 * restart it cleanly. It was done that way because glibc wanted it that way,
66 * not because it's a good idea. [snip...]
68 * I assume that in the passed twelve+ years, nanosleep got fixed,
69 * but the hack in sleep to work around broken nanosleep was never removed.
74 /* This is a quick and dirty, but not 100% compliant with
75 * the stupid SysV SIGCHLD vs. SIG_IGN behaviour. It is
76 * fine unless you are messing with SIGCHLD... */
77 unsigned int sleep (unsigned int sec
)
80 struct timespec ts
= { .tv_sec
= (long int) seconds
, .tv_nsec
= 0 };
81 res
= nanosleep(&ts
, &ts
);
82 if (res
) res
= (unsigned int) ts
.tv_sec
+ (ts
.tv_nsec
>= 500000000L);
88 /* We are going to use the `nanosleep' syscall of the kernel. But the
89 kernel does not implement the sstupid SysV SIGCHLD vs. SIG_IGN
90 behaviour for this syscall. Therefore we have to emulate it here. */
91 unsigned int sleep (unsigned int seconds
)
93 struct timespec ts
= { .tv_sec
= (long int) seconds
, .tv_nsec
= 0 };
95 struct sigaction oact
;
98 /* This is not necessary but some buggy programs depend on this. */
100 # ifdef CANCELLATION_P
102 CANCELLATION_P (THREAD_SELF
);
107 /* Linux will wake up the system call, nanosleep, when SIGCHLD
108 arrives even if SIGCHLD is ignored. We have to deal with it
111 __sigemptyset (&set
);
112 __sigaddset (&set
, SIGCHLD
);
114 /* Is SIGCHLD set to SIG_IGN? */
115 sigaction (SIGCHLD
, NULL
, &oact
); /* never fails */
116 if (oact
.sa_handler
== SIG_IGN
) {
117 /* Yes. Block SIGCHLD, save old mask. */
118 sigprocmask (SIG_BLOCK
, &set
, &set
); /* never fails */
121 /* Run nanosleep, with SIGCHLD blocked if SIGCHLD is SIG_IGNed. */
122 result
= nanosleep (&ts
, &ts
);
124 /* Got EINTR. Return remaining time. */
125 result
= (unsigned int) ts
.tv_sec
+ (ts
.tv_nsec
>= 500000000L);
128 if (!__sigismember (&set
, SIGCHLD
)) {
129 /* We did block SIGCHLD, and old mask had no SIGCHLD bit.
130 IOW: we need to unblock SIGCHLD now. Do it. */
131 /* this sigprocmask call never fails, thus never updates errno,
132 and therefore we don't need to save/restore it. */
133 sigprocmask (SIG_SETMASK
, &set
, NULL
); /* never fails */
141 #else /* __UCLIBC_HAS_REALTIME__ */
143 /* no nanosleep, use signals and alarm() */
144 static void sleep_alarm_handler(int attribute_unused sig
)
147 unsigned int sleep (unsigned int seconds
)
149 struct sigaction act
, oact
;
151 unsigned int result
, remaining
;
152 time_t before
, after
;
153 int old_errno
= errno
;
155 /* This is not necessary but some buggy programs depend on this. */
160 __sigemptyset (&set
);
161 __sigaddset (&set
, SIGALRM
);
162 sigprocmask (SIG_BLOCK
, &set
, &oset
); /* can't fail */
164 act
.sa_handler
= sleep_alarm_handler
;
167 sigaction(SIGALRM
, &act
, &oact
); /* never fails */
170 remaining
= alarm(seconds
);
171 if (remaining
&& remaining
> seconds
) {
172 /* restore user's alarm */
173 sigaction(SIGALRM
, &oact
, NULL
);
174 alarm(remaining
); /* restore old alarm */
180 sigaction (SIGALRM
, &oact
, NULL
);
182 result
= after
- before
;
183 alarm(remaining
> result
? remaining
- result
: 0);
184 sigprocmask (SIG_SETMASK
, &oset
, NULL
);
186 __set_errno(old_errno
);
188 return result
> seconds
? 0 : seconds
- result
;
191 #endif /* __UCLIBC_HAS_REALTIME__ */
193 libc_hidden_def(sleep
)