--- /dev/null
+/* nanosleep() - Sleep for a number of nanoseconds. Author: Erik van der Kouwe
+ * 25 July 2009
+ */
+
+#include <lib.h>
+#define nanosleep _nanosleep
+#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;
+
+ /* keep track of start time if needed */
+ if (rmtp)
+ {
+ rmtp->tv_sec = 0;
+ rmtp->tv_nsec = 0;
+ if (gettimeofday(×tart, 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;
+}
-/* sleep() - Sleep for a number of seconds. Author: Kees J. Bot
- * 24 Apr 2000
- * (Inspired by the Minix-vmd version of same, except that
- * this implementation doesn't bother to check if all the signal
- * functions succeed. Under Minix that is no problem.)
+/* sleep() - Sleep for a number of seconds. Author: Erik van der Kouwe
+ * 25 July 2009
*/
#include <lib.h>
#define sleep _sleep
-#include <signal.h>
-#include <unistd.h>
#include <time.h>
-static void handler(int sig)
-{
- /* Dummy signal handler. */
-}
-
unsigned sleep(unsigned sleep_seconds)
{
- sigset_t ss_full, ss_orig, ss_alarm;
- struct sigaction action_alarm, action_orig;
- unsigned alarm_seconds, nap_seconds;
-
- if (sleep_seconds == 0) return 0; /* No rest for the wicked */
-
- /* Mask all signals. */
- sigfillset(&ss_full);
- sigprocmask(SIG_BLOCK, &ss_full, &ss_orig);
-
- /* Cancel currently running alarm. */
- alarm_seconds= alarm(0);
-
- /* How long can we nap without interruptions? */
- nap_seconds= sleep_seconds;
- if (alarm_seconds != 0 && alarm_seconds < sleep_seconds) {
- nap_seconds= alarm_seconds;
- }
-
- /* Now sleep. */
- action_alarm.sa_handler= handler;
- sigemptyset(&action_alarm.sa_mask);
- action_alarm.sa_flags= 0;
- sigaction(SIGALRM, &action_alarm, &action_orig);
- alarm(nap_seconds);
-
- /* Wait for a wakeup call, either our alarm, or some other signal. */
- ss_alarm= ss_orig;
- sigdelset(&ss_alarm, SIGALRM);
- sigsuspend(&ss_alarm);
-
- /* Cancel alarm, set mask and stuff back to normal. */
- nap_seconds -= alarm(0);
- sigaction(SIGALRM, &action_orig, NULL);
- sigprocmask(SIG_SETMASK, &ss_orig, NULL);
+ struct timespec rqtp, rmtp;
- /* Restore alarm counter to the time remaining. */
- if (alarm_seconds != 0 && alarm_seconds >= nap_seconds) {
- alarm_seconds -= nap_seconds;
- if (alarm_seconds == 0) {
- raise(SIGALRM); /* Alarm expires now! */
- } else {
- alarm(alarm_seconds); /* Count time remaining. */
- }
- }
+ /* nanosleep implements this call;
+ * ignore failure, it cannot be reported
+ */
+ rqtp.tv_sec = sleep_seconds;
+ rqtp.tv_nsec = 0;
+ nanosleep(&rqtp, &rmtp);
- /* Return time not slept. */
- return sleep_seconds - nap_seconds;
+ /* round remainder up to seconds */
+ return rmtp.tv_sec + ((rmtp.tv_nsec > 0) ? 1 : 0);
}