xref: /minix3/minix/lib/libc/sys/nanosleep.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /*	nanosleep() - Sleep for a number of seconds.	Author: Erik van der Kouwe
2*433d6423SLionel Sambuc  *								25 July 2009
3*433d6423SLionel Sambuc  */
4*433d6423SLionel Sambuc 
5*433d6423SLionel Sambuc #include <sys/cdefs.h>
6*433d6423SLionel Sambuc #include "namespace.h"
7*433d6423SLionel Sambuc #include <lib.h>
8*433d6423SLionel Sambuc 
9*433d6423SLionel Sambuc #include <unistd.h>
10*433d6423SLionel Sambuc #include <errno.h>
11*433d6423SLionel Sambuc #include <time.h>
12*433d6423SLionel Sambuc #include <sys/select.h>
13*433d6423SLionel Sambuc #include <sys/time.h>
14*433d6423SLionel Sambuc 
15*433d6423SLionel Sambuc #define MSEC_PER_SEC 1000
16*433d6423SLionel Sambuc #define USEC_PER_MSEC 1000
17*433d6423SLionel Sambuc #define NSEC_PER_USEC 1000
18*433d6423SLionel Sambuc 
19*433d6423SLionel Sambuc #define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC)
20*433d6423SLionel Sambuc #define NSEC_PER_SEC (NSEC_PER_USEC * USEC_PER_SEC)
21*433d6423SLionel Sambuc 
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)22*433d6423SLionel Sambuc int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
23*433d6423SLionel Sambuc {
24*433d6423SLionel Sambuc 	struct timeval timeout, timestart = { 0, 0 }, timeend;
25*433d6423SLionel Sambuc 	int errno_select, r;
26*433d6423SLionel Sambuc 	struct timespec rqt;
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc 	/* check parameters */
29*433d6423SLionel Sambuc 	if (!rqtp) {
30*433d6423SLionel Sambuc 		errno = EFAULT;
31*433d6423SLionel Sambuc 		return -1;
32*433d6423SLionel Sambuc 	}
33*433d6423SLionel Sambuc 
34*433d6423SLionel Sambuc 	if (rqtp->tv_sec < 0 ||
35*433d6423SLionel Sambuc 		rqtp->tv_nsec < 0 ||
36*433d6423SLionel Sambuc 		rqtp->tv_nsec >= NSEC_PER_SEC) {
37*433d6423SLionel Sambuc 		errno = EINVAL;
38*433d6423SLionel Sambuc 		return -1;
39*433d6423SLionel Sambuc 	}
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc 	/* store *rqtp to make sure it is not overwritten */
42*433d6423SLionel Sambuc 	rqt = *rqtp;
43*433d6423SLionel Sambuc 
44*433d6423SLionel Sambuc 	/* keep track of start time if needed */
45*433d6423SLionel Sambuc 	if (rmtp)
46*433d6423SLionel Sambuc 	{
47*433d6423SLionel Sambuc 		rmtp->tv_sec = 0;
48*433d6423SLionel Sambuc 		rmtp->tv_nsec = 0;
49*433d6423SLionel Sambuc 		if (gettimeofday(&timestart, NULL) < 0)
50*433d6423SLionel Sambuc 			return -1;
51*433d6423SLionel Sambuc 	}
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc 	/* use select to wait */
54*433d6423SLionel Sambuc 	timeout.tv_sec = rqt.tv_sec;
55*433d6423SLionel Sambuc 	timeout.tv_usec = (rqt.tv_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC;
56*433d6423SLionel Sambuc 	r = select(0, NULL, NULL, NULL, &timeout);
57*433d6423SLionel Sambuc 
58*433d6423SLionel Sambuc 	/* return remaining time only if requested */
59*433d6423SLionel Sambuc 	/* if select succeeded then we slept all time */
60*433d6423SLionel Sambuc 	if (!rmtp || r >= 0)
61*433d6423SLionel Sambuc 		return r;
62*433d6423SLionel Sambuc 
63*433d6423SLionel Sambuc 	/* measure end time; preserve errno */
64*433d6423SLionel Sambuc 	errno_select = errno;
65*433d6423SLionel Sambuc 	if (gettimeofday(&timeend, NULL) < 0)
66*433d6423SLionel Sambuc 		return -1;
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc 	errno = errno_select;
69*433d6423SLionel Sambuc 
70*433d6423SLionel Sambuc 	/* compute remaining time */
71*433d6423SLionel Sambuc 	rmtp->tv_sec = rqt.tv_sec - (timeend.tv_sec - timestart.tv_sec);
72*433d6423SLionel Sambuc 	rmtp->tv_nsec = rqt.tv_nsec - (timeend.tv_usec - timestart.tv_usec) * NSEC_PER_USEC;
73*433d6423SLionel Sambuc 
74*433d6423SLionel Sambuc 	/* bring remaining time into canonical form */
75*433d6423SLionel Sambuc 	while (rmtp->tv_nsec < 0)
76*433d6423SLionel Sambuc 	{
77*433d6423SLionel Sambuc 		rmtp->tv_sec -= 1;
78*433d6423SLionel Sambuc 		rmtp->tv_nsec += NSEC_PER_SEC;
79*433d6423SLionel Sambuc 	}
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc 	while (rmtp->tv_nsec > NSEC_PER_SEC)
82*433d6423SLionel Sambuc 	{
83*433d6423SLionel Sambuc 		rmtp->tv_sec += 1;
84*433d6423SLionel Sambuc 		rmtp->tv_nsec -= NSEC_PER_SEC;
85*433d6423SLionel Sambuc 	}
86*433d6423SLionel Sambuc 
87*433d6423SLionel Sambuc 	/* remaining time must not be negative */
88*433d6423SLionel Sambuc 	if (rmtp->tv_sec < 0)
89*433d6423SLionel Sambuc 	{
90*433d6423SLionel Sambuc 		rmtp->tv_sec = 0;
91*433d6423SLionel Sambuc 		rmtp->tv_nsec = 0;
92*433d6423SLionel Sambuc 	}
93*433d6423SLionel Sambuc 
94*433d6423SLionel Sambuc 	return r;
95*433d6423SLionel Sambuc }
96*433d6423SLionel Sambuc 
97*433d6423SLionel Sambuc 
98*433d6423SLionel Sambuc #if defined(__minix) && defined(__weak_alias)
99*433d6423SLionel Sambuc __weak_alias(nanosleep, __nanosleep50)
100*433d6423SLionel Sambuc #endif
101