OSDN Git Service

Take the shorcut version, which is good enough for
[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    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include <errno.h>
22 #include <time.h>
23 #include <signal.h>
24 #include <unistd.h>
25
26 #if 1
27 /* This is a quick and dirty, but not 100% compliant with
28  * the stupid SysV SIGCHLD vs. SIG_IGN behaviour.  It is
29  * fine unless you are messing with SIGCHLD...  */
30 unsigned int sleep (unsigned int sec)
31 {
32         struct timespec ts = { 
33             tv_sec:  (long int) sec,
34             tv_nsec: 0 
35         };
36         nanosleep(&ts, &ts);
37         return(sec-ts.tv_sec);
38 }
39
40 #else
41
42 /* We are going to use the `nanosleep' syscall of the kernel.  But the
43    kernel does not implement the sstupid SysV SIGCHLD vs. SIG_IGN
44    behaviour for this syscall.  Therefore we have to emulate it here.  */
45 unsigned int sleep (unsigned int seconds)
46 {
47     struct timespec ts = { tv_sec: (long int) seconds, tv_nsec: 0 };
48     sigset_t set, oset;
49     unsigned int result;
50
51     /* This is not necessary but some buggy programs depend on this.  */
52     if (seconds == 0)
53         return 0;
54
55     /* Linux will wake up the system call, nanosleep, when SIGCHLD
56        arrives even if SIGCHLD is ignored.  We have to deal with it
57        in libc.  We block SIGCHLD first.  */
58     if (__sigemptyset (&set) < 0
59             || __sigaddset (&set, SIGCHLD) < 0
60             || sigprocmask (SIG_BLOCK, &set, &oset))
61         return -1;
62
63     /* If SIGCHLD is already blocked, we don't have to do anything.  */
64     if (!__sigismember (&oset, SIGCHLD))
65     {
66         int saved_errno;
67         struct sigaction oact;
68
69         if (__sigemptyset (&set) < 0 || __sigaddset (&set, SIGCHLD) < 0)
70             return -1;
71
72         /* We get the signal handler for SIGCHLD.  */
73         if (sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
74         {
75             saved_errno = errno;
76             /* Restore the original signal mask.  */
77             (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
78             __set_errno (saved_errno);
79             return -1;
80         }
81
82         if (oact.sa_handler == SIG_IGN)
83         {
84             /* We should leave SIGCHLD blocked.  */
85             result = nanosleep (&ts, &ts);
86
87             saved_errno = errno;
88             /* Restore the original signal mask.  */
89             (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
90             __set_errno (saved_errno);
91         }
92         else
93         {
94             /* We should unblock SIGCHLD.  Restore the original signal mask.  */
95             (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
96             result = nanosleep (&ts, &ts);
97         }
98     }
99     else
100         result = nanosleep (&ts, &ts);
101
102     if (result != 0)
103         /* Round remaining time.  */
104         result = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
105
106     return result;
107 }
108 #endif