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(×tart, 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