Messages in this thread Patch in this message | | | Date | Sun, 11 Jul 1999 23:58:36 +0200 (MEST) | From | Bernd Paysan <> | Subject | Re: [Patch] Re: usleep granularity |
| |
Oops, I forgot one assignment for the Alpha code (lost = lost_ticks). This is the fixed patch.
Bernd Paysan "If you want it done right, you have to do it yourself" http://www.jwdt.com/~paysan/ --- linux-2.3.9/arch/alpha/kernel/time.c.orig Sat Jul 10 13:49:32 1999 +++ linux-2.3.9/arch/alpha/kernel/time.c Sat Jul 10 13:57:57 1999 @@ -323,6 +323,44 @@ panic("Could not allocate timer IRQ!"); } +unsigned long gettimeoffset(void) +{ + unsigned long lost, delta_cycles, delta_usec, partial_tick; + +#ifdef __SMP__ + /* Until and unless we figure out how to get cpu cycle counters + in sync and keep them there, we can't use the rpcc tricks. */ + delta_usec = 1000000L / HZ - 1; +#else + /* + * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks) + * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks) + * = cycles * (s_t_p_c) * 15625 / (2**42 * ticks) + * + * which, given a 600MHz cycle and a 1024Hz tick, has a + * dynamic range of about 1.7e17, which is less than the + * 1.8e19 in an unsigned long, so we are safe from overflow. + * + * Round, but with .5 up always, since .5 to even is harder + * with no clear gain. + */ + + delta_cycles = rpcc() - state.last_time; + partial_tick = state.partial_tick; + lost = lost_ticks; + + delta_usec = (delta_cycles * state.scaled_ticks_per_cycle + + partial_tick + + (lost << FIX_SHIFT)) * 15625; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; +#endif + + return delta_usec; +} + /* * Use the cycle counter to estimate an displacement from the last time * tick. Unfortunately the Alpha designers made only the low 32-bits of --- linux-2.3.9/arch/sparc/kernel/time.c.orig Sat Jul 10 13:49:32 1999 +++ linux-2.3.9/arch/sparc/kernel/time.c Sat Jul 10 13:52:28 1999 @@ -441,6 +441,11 @@ return offset + count; } +unsigned long gettimeoffset(void) +{ + return do_gettimeoffset(); +} + /* This need not obtain the xtime_lock as it is coded in * an implicitly SMP safe way already. */ --- linux-2.3.9/arch/mips/kernel/time.c.orig Sat Jul 10 13:49:32 1999 +++ linux-2.3.9/arch/mips/kernel/time.c Sat Jul 10 14:01:00 1999 @@ -212,6 +212,15 @@ static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; /* + * This is the exported gettimeoffset() function -- Bernd Paysan + */ + +unsigned long gettimeoffset(void) +{ + return do_gettimeoffset(); +} + +/* * This version of gettimeofday has near microsecond resolution. */ void do_gettimeofday(struct timeval *tv) --- linux-2.3.9/arch/ppc/kernel/time.c.orig Sat Jul 10 13:49:32 1999 +++ linux-2.3.9/arch/ppc/kernel/time.c Sat Jul 10 14:00:22 1999 @@ -132,6 +132,16 @@ hardirq_exit(cpu); } +unsigned long gettimeoffset(void) +{ +#ifndef __SMP__ + return (decrementer_count - get_dec()) + * count_period_num / count_period_den; +#else + return 1000000L / HZ - 1; +#endif +} + /* * This version of gettimeofday has microsecond resolution. */ --- linux-2.3.9/arch/m68k/kernel/time.c.orig Sat Jul 10 13:49:32 1999 +++ linux-2.3.9/arch/m68k/kernel/time.c Sat Jul 10 14:02:44 1999 @@ -153,6 +153,22 @@ extern rwlock_t xtime_lock; /* + * This is the exported gettimeoffset() function -- Bernd Paysan + */ + +unsigned long gettimeoffset(void) +{ + unsigned long usec, lost; + + usec = mach_gettimeoffset(); + lost = lost_ticks; + if (lost) + usec += lost * (1000000/HZ); + + return usec; +} + +/* * This version of gettimeofday has near microsecond resolution. */ void do_gettimeofday(struct timeval *tv) --- linux-2.3.9/arch/sparc64/kernel/time.c.orig Sat Jul 10 13:49:32 1999 +++ linux-2.3.9/arch/sparc64/kernel/time.c Sat Jul 10 13:52:43 1999 @@ -411,6 +411,11 @@ return ticks / timer_ticks_per_usec; } +unsigned long gettimeoffset(void) +{ + return do_gettimeoffset(); +} + /* This need not obtain the xtime_lock as it is coded in * an implicitly SMP safe way already. */ --- linux-2.3.9/fs/select.c.orig Thu Jul 8 21:12:43 1999 +++ linux-2.3.9/fs/select.c Thu Jul 8 22:16:33 1999 @@ -14,6 +14,7 @@ #include <linux/smp_lock.h> #include <linux/poll.h> #include <linux/file.h> +#include <linux/time.h> #include <asm/uaccess.h> @@ -231,6 +232,17 @@ * * Update: ERESTARTSYS breaks at least the xview clock binary, so * I'm trying ERESTARTNOHAND which restart only when you want to. + * + * Update: the previous code had a sleep time between 10 and 20 ms + * at least - it wasn't possible to sleep between 0 and 10 ms. The + * new code doesn't consider worst-case szenarios, and instead + * uses gettimeoffset() to compensate for the time to the current + * jiffie's schedule time. + * + * I also want to use the same code for nanosleep() as for select(). + * + * -- Bernd Paysan <bernd.paysan@gmx.de> + * */ #define MAX_SELECT_SECONDS \ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) @@ -257,8 +269,12 @@ goto out_nofds; if ((unsigned long) sec < MAX_SELECT_SECONDS) { - timeout = ROUND_UP(usec, 1000000/HZ); - timeout += sec * (unsigned long) HZ; + struct timespec tspec; + + tspec.tv_sec = sec; + tspec.tv_nsec = usec * 1000; + + timeout = timespec_to_jiffies(&tspec); } } --- linux-2.3.9/include/linux/time.h.orig Thu Jul 8 21:34:34 1999 +++ linux-2.3.9/include/linux/time.h Sat Jul 10 14:15:30 1999 @@ -23,20 +23,60 @@ * to wait "jiffies+1" in order to guarantee that we wait * at _least_ "jiffies" - so "jiffies+1" had better still * be positive. + * + * Update: timespec_to_jiffies used to round up worst case, + * instead of just adding the current offset to the ns delay. + * CAVEAT: this really should include jiffies in the calculation, + * since jiffies could overflow between the call off gettimeoffset() + * and the addition of jiffies in the underlying code. + * + * The timer code in arch/<machine>/kernel/time.c must export gettimeoffset(), + * which should return 1000000L / HZ - 1 (worst case) if unknown. + * -- Bernd Paysan <bernd.paysan@gmx.de> */ #define MAX_JIFFY_OFFSET ((~0UL >> 1)-1) +#ifdef __KERNEL__ +#ifdef CONFIG_ARM +#include <asm/arch/time.h> +#else +extern unsigned long gettimeoffset(void); +#endif +#endif + static __inline__ unsigned long timespec_to_jiffies(struct timespec *value) { unsigned long sec = value->tv_sec; long nsec = value->tv_nsec; + long offset; +#ifdef T2J_WITH_JIFFIES + long jiffies1; +#endif if (sec >= (MAX_JIFFY_OFFSET / HZ)) +#ifdef T2J_WITH_JIFFIES + return jiffies + MAX_JIFFY_OFFSET; +#else return MAX_JIFFY_OFFSET; - nsec += 1000000000L / HZ - 1; +#endif + +#ifdef T2J_WITH_JIFFIES + do { + jiffies1 = jiffies; +#endif + offset = gettimeoffset(); +#ifdef T2J_WITH_JIFFIES + } while (jiffies1 != jiffies); +#endif + + nsec += offset * 1000; nsec /= 1000000000L / HZ; - return HZ * sec + nsec; + return HZ * sec + nsec +#ifdef T2J_WITH_JIFFIES + + jiffies +#endif + ; } static __inline__ void | |