]> Zhao Yanbai Git Server - minix.git/commitdiff
Function nanosleep now checks arguments
authorErik van der Kouwe <erik@minix3.org>
Sun, 16 Aug 2009 12:13:33 +0000 (12:13 +0000)
committerErik van der Kouwe <erik@minix3.org>
Sun, 16 Aug 2009 12:13:33 +0000 (12:13 +0000)
lib/posix/_sleep.c

index e1f721e0f886fb423292b1efa41d25f891fafd0a..21dfc633ce29eae894ed176e0c8832d5586a844c 100755 (executable)
@@ -1,18 +1,97 @@
-/*     sleep() - Sleep for a number of seconds.  Author: Erik van der Kouwe
+/*     sleep() - Sleep for a number of seconds.        Author: Erik van der Kouwe
  *                                                             25 July 2009
+ * (Avoids interfering with alarm/setitimer by using select, like usleep)
  */
 
 #include <lib.h>
 #define sleep _sleep
+#define nanosleep _nanosleep
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
 #include <time.h>
+#include <sys/select.h>
+#include <sys/time.h>
+
+#define MSEC_PER_SEC 1000
+#define USEC_PER_MSEC 1000
+#define NSEC_PER_USEC 1000
+
+#define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC)
+#define NSEC_PER_SEC (NSEC_PER_USEC * USEC_PER_SEC)
+
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+       struct timeval timeout, timestart = { 0, 0 }, timeend;
+       int errno_select, r;
+
+       /* check parameters */
+       if (!rqtp)
+               return EFAULT;
+
+       if (rqtp->tv_sec < 0 || 
+               rqtp->tv_nsec < 0 ||
+               rqtp->tv_nsec >= NSEC_PER_SEC)
+               return EINVAL;
+
+       /* keep track of start time if needed */
+       if (rmtp)
+       {
+               rmtp->tv_sec = 0;
+               rmtp->tv_nsec = 0;
+               if (gettimeofday(&timestart, NULL) < 0)
+                       return -1;
+       }
+
+       /* use select to wait */
+       timeout.tv_sec = rqtp->tv_sec;
+       timeout.tv_usec = (rqtp->tv_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC;
+       r = select(0, NULL, NULL, NULL, &timeout);
+
+       /* return remaining time only if requested */
+       /* if select succeeded then we slept all time */
+       if (!rmtp || r >= 0)
+               return r;
+
+       /* measure end time; preserve errno */
+       errno_select = errno;
+       if (gettimeofday(&timeend, NULL) < 0)
+               return -1;
+
+       errno = errno_select;
+
+       /* compute remaining time */
+       rmtp->tv_sec = rqtp->tv_sec - (timeend.tv_sec - timestart.tv_sec);
+       rmtp->tv_nsec = rqtp->tv_nsec - (timeend.tv_usec - timestart.tv_usec) * NSEC_PER_USEC;
+
+       /* bring remaining time into canonical form */
+       while (rmtp->tv_nsec < 0)
+       {
+               rmtp->tv_sec -= 1;
+               rmtp->tv_nsec += NSEC_PER_SEC;
+       }
+
+       while (rmtp->tv_nsec > NSEC_PER_SEC)
+       {
+               rmtp->tv_sec += 1;
+               rmtp->tv_nsec -= NSEC_PER_SEC;
+       }
+
+       /* remaining time must not be negative */
+       if (rmtp->tv_sec < 0)
+       {
+               rmtp->tv_sec = 0;
+               rmtp->tv_nsec = 0;
+       }
+
+       return r;
+}
 
 unsigned sleep(unsigned sleep_seconds)
 {
        struct timespec rqtp, rmtp;
 
-       /* nanosleep implements this call;
-        * ignore failure, it cannot be reported
-        */
+       /* nanosleep implements this call; ignore failure, it cannot be reported */
        rqtp.tv_sec = sleep_seconds;
        rqtp.tv_nsec = 0;
        nanosleep(&rqtp, &rmtp);