diff -urN 2.4.4pre3/include/asm-alpha/atomic.h softirq-races/include/asm-alpha/atomic.h --- 2.4.4pre3/include/asm-alpha/atomic.h Tue Nov 28 18:40:01 2000 +++ softirq-races/include/asm-alpha/atomic.h Mon Apr 16 18:23:14 2001 @@ -106,4 +106,9 @@ #define atomic_inc(v) atomic_add(1,(v)) #define atomic_dec(v) atomic_sub(1,(v)) +#define smp_mb__before_atomic_inc() smp_mb() +#define smp_mb__after_atomic_inc() smp_mb() +#define smp_mb__before_atomic_dec() smp_mb() +#define smp_mb__after_atomic_dec() smp_mb() + #endif /* _ALPHA_ATOMIC_H */ diff -urN 2.4.4pre3/include/asm-i386/atomic.h softirq-races/include/asm-i386/atomic.h --- 2.4.4pre3/include/asm-i386/atomic.h Sun Apr 15 18:48:48 2001 +++ softirq-races/include/asm-i386/atomic.h Mon Apr 16 18:23:39 2001 @@ -42,6 +42,15 @@ */ #define atomic_set(v,i) (((v)->counter) = (i)) +/* + * It maybe we need an explicit serialization across inc/dec on + * recent chips, if not then just replace this with a barrier(). + */ +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() + /** * atomic_add - add integer to atomic variable * @i: integer value to add diff -urN 2.4.4pre3/include/linux/interrupt.h softirq-races/include/linux/interrupt.h --- 2.4.4pre3/include/linux/interrupt.h Sun Apr 15 18:57:06 2001 +++ softirq-races/include/linux/interrupt.h Mon Apr 16 18:23:14 2001 @@ -186,16 +186,20 @@ static inline void tasklet_disable_nosync(struct tasklet_struct *t) { atomic_inc(&t->count); + smp_mb__after_atomic_inc(); } static inline void tasklet_disable(struct tasklet_struct *t) { tasklet_disable_nosync(t); tasklet_unlock_wait(t); + /* Make sure not to speculate reads until the tasklet resigns. */ + smp_rmb(); } static inline void tasklet_enable(struct tasklet_struct *t) { + smp_mb__before_atomic_dec(); atomic_dec(&t->count); } diff -urN 2.4.4pre3/kernel/softirq.c softirq-races/kernel/softirq.c --- 2.4.4pre3/kernel/softirq.c Tue Jan 2 17:41:22 2001 +++ softirq-races/kernel/softirq.c Mon Apr 16 18:23:14 2001 @@ -142,9 +142,15 @@ t->func(t->data); /* - * talklet_trylock() uses test_and_set_bit that imply + * talklet_trylock() uses test_and_set_bit that _just_ imply * an mb when it returns zero, thus we need the explicit * mb only here: while closing the critical section. + * + * On UP the barrier() in not necessary because f->func + * cannot be reordered by the compiler anyways because + * of the C language. Unless the compiler is doing something + * stupid dropping the #ifdef wouldn't make any difference in the + * generatd asm though (the #ifdef is mostly a documenetation issue). */ #ifdef CONFIG_SMP smp_mb__before_clear_bit(); @@ -152,6 +158,13 @@ tasklet_unlock(t); continue; } + /* + * NOTE: here we don't need the smb_mb() because the tasklet_unlock() + * write depends on the read of the &t->count that is in turn _the_ + * variable that the lock is serializing. The CPU isn't allowed to + * write to the memory before we checked t->count is not zero and + * by that time we don't need the lock any longer. + */ tasklet_unlock(t); } local_irq_disable(); @@ -186,6 +199,9 @@ clear_bit(TASKLET_STATE_SCHED, &t->state); t->func(t->data); +#ifdef CONFIG_SMP + smp_mb__before_clear_bit(); +#endif tasklet_unlock(t); continue; }