OSDN Git Service

test: disable librt shmtest on non-MMU systems
[uclinux-h8/uClibc.git] / libc / unistd / sleep.c
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.
5
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.
10
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.
15
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/>.  */
19
20 #include <errno.h>
21 #include <time.h>
22 #include <signal.h>
23 #include <unistd.h>
24
25
26 /* version perusing nanosleep */
27 #if defined __UCLIBC_HAS_REALTIME__
28
29 /* I am unable to reproduce alleged "Linux quirk".
30  * I used the following test program:
31 #include <unistd.h>
32 #include <time.h>
33 #include <signal.h>
34 static void dummy(int sig) {}
35 int main() {
36     struct timespec t = { 2, 0 };
37     if (fork() == 0) {
38         sleep(1);
39         return 0;
40     }
41     signal(SIGCHLD, SIG_DFL); //
42     signal(SIGCHLD, dummy);   // Pick one
43     signal(SIGCHLD, SIG_IGN); //
44     nanosleep(&t, &t);
45     return 0;
46 }
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 (!):
53  * ----------
54  *  Subject: Re: sleep ignore sigchld
55  *  From: Linus Torvalds <torvalds@transmeta.com>
56  *  Date: Mon, 16 Nov 1998 11:02:15 -0800 (PST)
57  *
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...]
61  *
62  *  No can do.
63  *
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...]
67  * ----------
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.
70  */
71
72 # if 0
73
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)
78 {
79         unsigned int res;
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);
83         return res;
84 }
85
86 # else
87
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)
92 {
93     struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 };
94     sigset_t set;
95     struct sigaction oact;
96     unsigned int result;
97
98     /* This is not necessary but some buggy programs depend on this.  */
99     if (seconds == 0) {
100 #  ifdef CANCELLATION_P
101         int cancelhandling;
102         CANCELLATION_P (THREAD_SELF);
103 #  endif
104         return 0;
105     }
106
107     /* Linux will wake up the system call, nanosleep, when SIGCHLD
108        arrives even if SIGCHLD is ignored.  We have to deal with it
109        in libc.  */
110
111     __sigemptyset (&set);
112     __sigaddset (&set, SIGCHLD);
113
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 */
119     }
120
121     /* Run nanosleep, with SIGCHLD blocked if SIGCHLD is SIG_IGNed.  */
122     result = nanosleep (&ts, &ts);
123     if (result != 0) {
124         /* Got EINTR. Return remaining time.  */
125         result = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
126     }
127
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 */
134     }
135
136     return result;
137 }
138
139 # endif
140
141 #else /* __UCLIBC_HAS_REALTIME__ */
142
143 /* no nanosleep, use signals and alarm() */
144 static void sleep_alarm_handler(int attribute_unused sig)
145 {
146 }
147 unsigned int sleep (unsigned int seconds)
148 {
149     struct sigaction act, oact;
150     sigset_t set, oset;
151     unsigned int result, remaining;
152     time_t before, after;
153     int old_errno = errno;
154
155     /* This is not necessary but some buggy programs depend on this.  */
156     if (seconds == 0)
157         return 0;
158
159     /* block SIGALRM */
160     __sigemptyset (&set);
161     __sigaddset (&set, SIGALRM);
162     sigprocmask (SIG_BLOCK, &set, &oset); /* can't fail */
163
164     act.sa_handler = sleep_alarm_handler;
165     act.sa_flags = 0;
166     act.sa_mask = oset;
167     sigaction(SIGALRM, &act, &oact); /* never fails */
168
169     before = time(NULL);
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 */
175         sigsuspend(&oset);
176         after = time(NULL);
177     } else {
178         sigsuspend (&oset);
179         after = time(NULL);
180         sigaction (SIGALRM, &oact, NULL);
181     }
182     result = after - before;
183     alarm(remaining > result ? remaining - result : 0);
184     sigprocmask (SIG_SETMASK, &oset, NULL);
185
186     __set_errno(old_errno);
187
188     return result > seconds ? 0 : seconds - result;
189 }
190
191 #endif /* __UCLIBC_HAS_REALTIME__ */
192
193 libc_hidden_def(sleep)