diff -urN 2.3.48pre1aa1/arch/alpha/kernel/time.c nanosleep/arch/alpha/kernel/time.c --- 2.3.48pre1aa1/arch/alpha/kernel/time.c Thu Feb 24 18:31:49 2000 +++ nanosleep/arch/alpha/kernel/time.c Thu Feb 24 18:32:30 2000 @@ -287,6 +287,8 @@ /* Startup the timer source. */ alpha_mv.init_rtc(); + + do_get_fast_time = do_gettimeofday; } /* @@ -337,13 +339,11 @@ #endif usec += delta_usec; - if (usec >= 1000000) { - sec += 1; - usec -= 1000000; - } tv->tv_sec = sec; tv->tv_usec = usec; + + timeval_normalize(tv); } void diff -urN 2.3.48pre1aa1/arch/i386/kernel/time.c nanosleep/arch/i386/kernel/time.c --- 2.3.48pre1aa1/arch/i386/kernel/time.c Sun Jan 30 15:43:27 2000 +++ nanosleep/arch/i386/kernel/time.c Thu Feb 24 18:32:07 2000 @@ -253,13 +253,10 @@ usec += xtime.tv_usec; read_unlock_irqrestore(&xtime_lock, flags); - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } - tv->tv_sec = sec; tv->tv_usec = usec; + + timeval_normalize(tv); } void do_settimeofday(struct timeval *tv) diff -urN 2.3.48pre1aa1/arch/ppc/kernel/time.c nanosleep/arch/ppc/kernel/time.c --- 2.3.48pre1aa1/arch/ppc/kernel/time.c Thu Jan 13 05:17:19 2000 +++ nanosleep/arch/ppc/kernel/time.c Thu Feb 24 18:32:07 2000 @@ -158,10 +158,7 @@ #ifndef __SMP__ tv->tv_usec += (decrementer_count - get_dec()) * count_period_num / count_period_den; - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; - } + timeval_normalize(tv); #endif restore_flags(flags); } diff -urN 2.3.48pre1aa1/include/linux/time.h nanosleep/include/linux/time.h --- 2.3.48pre1aa1/include/linux/time.h Thu Feb 24 03:21:47 2000 +++ nanosleep/include/linux/time.h Thu Feb 24 18:35:40 2000 @@ -46,10 +46,66 @@ value->tv_sec = jiffies / HZ; } +static __inline__ int +timespec_before(struct timespec a, struct timespec b) +{ + if (a.tv_sec == b.tv_sec) + return a.tv_nsec < b.tv_nsec; + return a.tv_sec < b.tv_sec; +} + +/* computes `a - b' and write the result in `result', assumes `a >= b' */ +static inline void +timespec_less(struct timespec a, struct timespec b, struct timespec * result) +{ + if (a.tv_nsec < b.tv_nsec) + { + a.tv_sec--; + a.tv_nsec += 1000000000; + } + + result->tv_sec = a.tv_sec - b.tv_sec; + result->tv_nsec = a.tv_nsec - b.tv_nsec; +} + struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ }; + +static inline void +timeval_normalize(struct timeval * tv) +{ + time_t __sec; + + __sec = tv->tv_usec / 1000000; + if (__sec) + { + tv->tv_usec %= 1000000; + tv->tv_sec += __sec; + } +} + +/* computes `a - b' and write the result in `result', assumes `a >= b' */ +static inline void +timeval_less(struct timeval a, struct timeval b, struct timeval * result) +{ + if (a.tv_usec < b.tv_usec) + { + a.tv_sec--; + a.tv_usec += 1000000; + } + + result->tv_sec = a.tv_sec - b.tv_sec; + result->tv_usec = a.tv_usec - b.tv_usec; +} + +static __inline__ void +timeval_to_timespec(struct timeval tv, struct timespec * ts) +{ + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = (long) tv.tv_usec * 1000; +} struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ diff -urN 2.3.48pre1aa1/kernel/timer.c nanosleep/kernel/timer.c --- 2.3.48pre1aa1/kernel/timer.c Thu Feb 24 18:31:49 2000 +++ nanosleep/kernel/timer.c Thu Feb 24 18:34:42 2000 @@ -807,6 +807,7 @@ { struct timespec t; unsigned long expire; + struct timeval before, after; if(copy_from_user(&t, rqtp, sizeof(struct timespec))) return -EFAULT; @@ -831,11 +832,20 @@ expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); current->state = TASK_INTERRUPTIBLE; + get_fast_time(&before); expire = schedule_timeout(expire); + get_fast_time(&after); if (expire) { if (rmtp) { - jiffies_to_timespec(expire, &t); + struct timespec elapsed; + + timeval_less(after, before, &after); + timeval_to_timespec(after, &elapsed); + if (timespec_before(elapsed, t)) + timespec_less(t, elapsed, &t); + else + t.tv_nsec = t.tv_sec = 0; if (copy_to_user(rmtp, &t, sizeof(struct timespec))) return -EFAULT; }