Binary files 2.2.14/ID and 2.2.14-nanosleep/ID differ diff -urN 2.2.14/arch/alpha/kernel/time.c 2.2.14-nanosleep/arch/alpha/kernel/time.c --- 2.2.14/arch/alpha/kernel/time.c Sun Jan 2 18:26:32 2000 +++ 2.2.14-nanosleep/arch/alpha/kernel/time.c Tue Feb 15 18:30:42 2000 @@ -326,6 +326,7 @@ irq_handler = timer_interrupt; if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL)) panic("Could not allocate timer IRQ!"); + do_get_fast_time = do_gettimeofday; } /* @@ -376,10 +377,8 @@ #endif usec += delta_usec; - if (usec >= 1000000) { - sec += 1; - usec -= 1000000; - } + + normalize_timeval(&sec, &usec); tv->tv_sec = sec; tv->tv_usec = usec; diff -urN 2.2.14/arch/i386/kernel/time.c 2.2.14-nanosleep/arch/i386/kernel/time.c --- 2.2.14/arch/i386/kernel/time.c Mon Jan 17 16:44:33 2000 +++ 2.2.14-nanosleep/arch/i386/kernel/time.c Tue Feb 15 18:31:00 2000 @@ -252,10 +252,7 @@ usec += xtime.tv_usec; read_unlock_irqrestore(&xtime_lock, flags); - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } + normalize_timeval(&sec, &usec); tv->tv_sec = sec; tv->tv_usec = usec; diff -urN 2.2.14/include/linux/time.h 2.2.14-nanosleep/include/linux/time.h --- 2.2.14/include/linux/time.h Tue Feb 1 18:24:19 2000 +++ 2.2.14-nanosleep/include/linux/time.h Tue Feb 15 18:34:03 2000 @@ -51,6 +51,52 @@ suseconds_t tv_usec; /* microseconds */ }; +static inline void +normalize_timeval(time_t * sec, suseconds_t * usec) +{ + time_t __sec; + __sec = *usec / 1000000; + if (__sec) + { + *usec %= 1000000; + *sec += __sec; + } +} + +/* computes `a - b' and write the result in `result', assumes `a >= b' */ +static inline void +timeval_less_timeval(struct timeval * a, struct timeval * b, struct timeval * result) +{ + time_t a_sec = a->tv_sec; + suseconds_t a_usec = a->tv_usec; + time_t b_sec = b->tv_sec; + suseconds_t b_usec = b->tv_usec; + + normalize_timeval(&a_sec, &a_usec); + normalize_timeval(&b_sec, &b_usec); + + if (a_usec < b_usec) + { + a_sec--; + a_usec += 1000000; + } + + result->tv_sec = a_sec - b_sec; + result->tv_usec = a_usec - b_usec; +} + +static __inline__ void +timeval_to_timespec(struct timeval * val, struct timespec * spec) +{ + time_t val_sec = val->tv_sec; + suseconds_t val_usec = val->tv_usec; + + normalize_timeval(&val_sec, &val_usec); + + spec->tv_sec = val_sec; + spec->tv_nsec = (long) val_usec * 1000; +} + struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of dst correction */ diff -urN 2.2.14/kernel/sched.c 2.2.14-nanosleep/kernel/sched.c --- 2.2.14/kernel/sched.c Wed Jan 5 14:16:56 2000 +++ 2.2.14-nanosleep/kernel/sched.c Tue Feb 15 18:09:16 2000 @@ -1904,6 +1904,7 @@ { struct timespec t; unsigned long expire; + struct timeval before, after; if(copy_from_user(&t, rqtp, sizeof(struct timespec))) return -EFAULT; @@ -1928,11 +1929,16 @@ 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 timeval retval; + + timeval_less_timeval(&after, &before, &retval); + timeval_to_timespec(&retval, &t); if (copy_to_user(rmtp, &t, sizeof(struct timespec))) return -EFAULT; }