Messages in this thread Patches in this message | | | Date | Sat, 21 Nov 1998 02:19:49 +0100 (CET) | From | Andrea Arcangeli <> | Subject | arca-26 |
| |
Arca 26 is out:
ftp://e-mind.com/pub/linux/kernel-patches/arca-26...
The differences between arca-25 ares:
o fixed timespec_to_jiffies() wraps, I include the new code here too to allow more people to complain about:
Index: linux/include/linux/time.h diff -u linux/include/linux/time.h:1.1.1.1 linux/include/linux/time.h:1.1.1.1.2.3 --- linux/include/linux/time.h:1.1.1.1 Fri Nov 20 00:01:14 1998 +++ linux/include/linux/time.h Sat Nov 21 01:38:33 1998 @@ -3,6 +3,7 @@ #include <asm/param.h> #include <linux/types.h> +#include <linux/kernel.h> #ifndef _STRUCT_TIMESPEC #define _STRUCT_TIMESPEC @@ -15,22 +16,58 @@ /* * change timeval to jiffies, trying to avoid the * most obvious overflows.. + * Added some overflow fix by Andrea Arcangeli */ -static __inline__ unsigned long -timespec_to_jiffies(struct timespec *value) +static __inline__ long timespec_to_jiffies(struct timespec *value) { - unsigned long sec = value->tv_sec; - long nsec = value->tv_nsec; + unsigned long sec = value->tv_sec, nsec = value->tv_nsec, nsec_tmp; + long retval; - if (sec > ((long)(~0UL >> 1) / HZ)) - return ~0UL >> 1; - nsec += 1000000000L / HZ - 1; - nsec /= 1000000000L / HZ; - return HZ * sec + nsec; + if (sec >= LONG_MAX / HZ) + return LONG_MAX; + sec *= HZ; + + nsec_tmp = nsec + 1000000000UL/HZ - 1; + if (nsec_tmp > nsec) + nsec = nsec_tmp; + nsec /= 1000000000UL/HZ; + if (nsec >= LONG_MAX) + return LONG_MAX; + + retval = nsec + sec; + if (retval < 0) + return LONG_MAX; + return retval; +} + +/* + * change timeval to jiffies plus one if the timespec struct is not null + * by Andrea Arcangeli + */ +static __inline__ long timespec_to_jiffies_plus_one(struct timespec *value) +{ + unsigned long sec = value->tv_sec, nsec = value->tv_nsec, nsec_tmp; + long retval; + + if (sec >= (LONG_MAX-1) / HZ) + return LONG_MAX; + sec *= HZ; + + nsec_tmp = nsec + 1000000000UL/HZ - 1; + if (nsec_tmp > nsec) + nsec = nsec_tmp; + nsec /= 1000000000UL/HZ; + if (nsec >= LONG_MAX-1) + return LONG_MAX; + + retval = nsec + sec + (value->tv_sec || value->tv_nsec); + if (retval < 0) + return LONG_MAX; + return retval; } static __inline__ void -jiffies_to_timespec(unsigned long jiffies, struct timespec *value) +jiffies_to_timespec(long jiffies, struct timespec *value) { value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ); value->tv_sec = jiffies / HZ; Index: linux/kernel/signal.c diff -u linux/kernel/signal.c:1.1.1.1 linux/kernel/signal.c:1.1.1.1.2.2 --- linux/kernel/signal.c:1.1.1.1 Fri Nov 20 00:01:12 1998 +++ linux/kernel/signal.c Fri Nov 20 11:39:11 1998 @@ -742,8 +742,7 @@ timeout = MAX_SCHEDULE_TIMEOUT; if (uts) - timeout = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); + timeout = timespec_to_jiffies_plus_one(&ts); current->state = TASK_INTERRUPTIBLE; timeout = schedule_timeout(timeout); Index: linux/kernel/sched.c diff -u linux/kernel/sched.c:1.1.1.1 linux/kernel/sched.c:1.1.1.1.2.9 --- linux/kernel/sched.c:1.1.1.1 Fri Nov 20 00:01:12 1998 +++ linux/kernel/sched.c Sat Nov 21 01:43:35 1998 @@ -1604,7 +1619,7 @@ asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp) { struct timespec t; - unsigned long expire; + long expire; if(copy_from_user(&t, rqtp, sizeof(struct timespec))) return -EFAULT; @@ -1626,7 +1641,7 @@ return 0; } - expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); + expire = timespec_to_jiffies_plus_one(&t); current->state = TASK_INTERRUPTIBLE; expire = schedule_timeout(expire); o restored the official timer code and fixed the SMP race in itimer using bh_atomic contexts (SMP bug discovered by Linus)
Index: linux/kernel/exit.c diff -u linux/kernel/exit.c:1.1.1.1 linux/kernel/exit.c:1.1.1.1.2.1 --- linux/kernel/exit.c:1.1.1.1 Fri Nov 20 00:01:12 1998 +++ linux/kernel/exit.c Fri Nov 20 00:15:38 1998 @@ -358,7 +358,9 @@ if (!tsk->pid) panic("Attempted to kill the idle task!"); tsk->flags |= PF_EXITING; + start_bh_atomic(); del_timer(&tsk->real_timer); + end_bh_atomic(); lock_kernel(); fake_volatile: Index: linux/kernel/itimer.c diff -u linux/kernel/itimer.c:1.1.1.1 linux/kernel/itimer.c:1.1.1.1.2.3 --- linux/kernel/itimer.c:1.1.1.1 Fri Nov 20 00:01:12 1998 +++ linux/kernel/itimer.c Sat Nov 21 02:05:59 1998 @@ -11,6 +11,7 @@ #include <linux/errno.h> #include <linux/mm.h> #include <linux/smp_lock.h> +#include <linux/interrupt.h> #include <asm/uaccess.h> @@ -47,15 +48,19 @@ register unsigned long val, interval; switch (which) { + int timer_pending; case ITIMER_REAL: interval = current->it_real_incr; val = 0; - if (del_timer(¤t->real_timer)) { + start_bh_atomic(); + timer_pending = del_timer(¤t->real_timer); + end_bh_atomic(); + if (timer_pending) { unsigned long now = jiffies; val = current->real_timer.expires; add_timer(¤t->real_timer); /* look out for negative/zero itimer.. */ - if (val <= now) + if (time_before_eq(val, now)) val = now+1; val -= now; } @@ -117,7 +122,9 @@ return k; switch (which) { case ITIMER_REAL: + start_bh_atomic(); del_timer(¤t->real_timer); + end_bh_atomic(); current->it_real_value = j; current->it_real_incr = i; if (!j) o wchan compile on alpha (and i386 ;-).
Andrea Arcangeli
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |