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