1 /* Provide a replacement for the POSIX nanosleep function.
3 Copyright (C) 1999-2000, 2002, 2004-2010 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* written by Jim Meyering */
25 #include "sig-handler.h"
30 #include <sys/types.h>
31 #include <sys/select.h>
40 enum { BILLION = 1000 * 1000 * 1000 };
42 #if HAVE_BUG_BIG_NANOSLEEP
45 nanosleep (const struct timespec *requested_delay,
46 struct timespec *remaining_delay)
49 /* nanosleep mishandles large sleeps due to internal overflow
50 problems. The worst known case of this is cygwin 1.5.x, which
51 can't sleep more than 49.7 days (2**32 milliseconds). Solve this
52 by breaking the sleep up into smaller chunks. Verify that time_t
54 verify (TYPE_MAXIMUM (time_t) / 49 / 24 / 60 / 60);
55 const time_t limit = 49 * 24 * 60 * 60;
56 time_t seconds = requested_delay->tv_sec;
57 struct timespec intermediate;
58 intermediate.tv_nsec = 0;
60 while (limit < seconds)
63 intermediate.tv_sec = limit;
64 result = nanosleep (&intermediate, remaining_delay);
70 remaining_delay->tv_sec += seconds;
71 remaining_delay->tv_nsec += requested_delay->tv_nsec;
72 if (BILLION <= requested_delay->tv_nsec)
74 remaining_delay->tv_sec++;
75 remaining_delay->tv_nsec -= BILLION;
81 intermediate.tv_sec = seconds;
82 intermediate.tv_nsec = requested_delay->tv_nsec;
83 return nanosleep (&intermediate, remaining_delay);
88 /* Some systems (MSDOS) don't have SIGCONT.
89 Using SIGTERM here turns the signal-handling code below
90 into a no-op on such systems. */
92 # define SIGCONT SIGTERM
95 static sig_atomic_t volatile suspended;
105 /* Suspend execution for at least *TS_DELAY seconds. */
108 my_usleep (const struct timespec *ts_delay)
110 struct timeval tv_delay;
111 tv_delay.tv_sec = ts_delay->tv_sec;
112 tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
113 if (tv_delay.tv_usec == 1000000)
115 time_t t1 = tv_delay.tv_sec + 1;
116 if (t1 < tv_delay.tv_sec)
117 tv_delay.tv_usec = 1000000 - 1; /* close enough */
120 tv_delay.tv_sec = t1;
121 tv_delay.tv_usec = 0;
124 select (0, NULL, NULL, NULL, &tv_delay);
127 /* Suspend execution for at least *REQUESTED_DELAY seconds. The
128 *REMAINING_DELAY part isn't implemented yet. */
131 nanosleep (const struct timespec *requested_delay,
132 struct timespec *remaining_delay)
134 static bool initialized;
136 if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
142 /* set up sig handler */
145 struct sigaction oldact;
147 sigaction (SIGCONT, NULL, &oldact);
148 if (get_handler (&oldact) != SIG_IGN)
150 struct sigaction newact;
152 newact.sa_handler = sighandler;
153 sigemptyset (&newact.sa_mask);
155 sigaction (SIGCONT, &newact, NULL);
162 my_usleep (requested_delay);
166 /* Calculate time remaining. */
167 /* FIXME: the code in sleep doesn't use this, so there's no
168 rush to implement it. */
173 /* FIXME: Restore sig handler? */