Messages in this thread Patch in this message | | | Date | Sat, 15 Jul 2000 22:15:32 +1000 | From | Andrew Morton <> | Subject | [patch] timers |
| |
- Moves timer_enter(), timer_exit(), timer_is_running() and timer_synchronize() out of include/linux/timer.h. Also unexports running_timer.
I suggest all this stuff not be exported to the world - it's delicate and will have to be changed if we go for concurrent timer handlers in 2.5.
- Adds an extra `volatile' to the running_timer decl. Right now we're telling the compiler that the timer_list is volatile, not the pointer to it. Future improvements in gcc could cause lockups.
- Implements and exports sync_timers(). This is a quite inefficient function, but Rusty requires it for
"module unload, where module count is decremented by timer; timer must be finished. Also:
`if (!del_timer(timer)) sync_timers();' == del_timer_sync()
for self-destructing timers."
Patch against test5-pre1 is attached.--- linux-2.4.0-test5-pre1/include/linux/timer.h Tue Jul 11 22:21:17 2000 +++ linux-akpm/include/linux/timer.h Sat Jul 15 21:33:11 2000 @@ -24,14 +24,23 @@ void (*function)(unsigned long); }; -extern volatile struct timer_list *running_timer; extern void add_timer(struct timer_list * timer); extern int del_timer(struct timer_list * timer); +#ifdef CONFIG_SMP +extern int del_timer_sync(struct timer_list * timer); +extern void sync_timers(void); +#else +#define del_timer_sync(t) del_timer(t) +#define sync_timers() do { } while (0) +#endif + /* * mod_timer is a more efficient way to update the expire field of an * active timer (if the timer is inactive it will be activated) - * mod_timer(a,b) is equivalent to del_timer(a); a->expires = b; add_timer(a) + * mod_timer(a,b) is equivalent to del_timer(a); a->expires = b; add_timer(a). + * If the timer is known to be not pending (ie, in the handler), mod_timer + * is less efficient than a->expires = b; add_timer(a). */ int mod_timer(struct timer_list *timer, unsigned long expires); @@ -46,20 +55,6 @@ { return timer->list.next != NULL; } - -#ifdef CONFIG_SMP -#define timer_enter(t) do { running_timer = t; mb(); } while (0) -#define timer_exit() do { running_timer = NULL; } while (0) -#define timer_is_running(t) (running_timer == t) -#define timer_synchronize(t) while (timer_is_running(t)) barrier() -extern int del_timer_sync(struct timer_list * timer); -#else -#define timer_enter(t) do { } while (0) -#define timer_exit() do { } while (0) -#define timer_is_running(t) (0) -#define timer_synchronize(t) do { (void)(t); barrier(); } while(0) -#define del_timer_sync(t) del_timer(t) -#endif /* * These inlines deal with timer wrapping correctly. You are --- linux-2.4.0-test5-pre1/kernel/timer.c Sat Jul 15 19:36:09 2000 +++ linux-akpm/kernel/timer.c Sat Jul 15 21:33:11 2000 @@ -162,7 +162,19 @@ /* Initialize both explicitly - let's try to have them in the same cache line */ spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED; -volatile struct timer_list *running_timer = NULL; +volatile struct timer_list * volatile running_timer = NULL; + +#ifdef CONFIG_SMP +#define timer_enter(t) do { running_timer = t; mb(); } while (0) +#define timer_exit() do { running_timer = NULL; } while (0) +#define timer_is_running(t) (running_timer == t) +#define timer_synchronize(t) while (timer_is_running(t)) barrier() +#else +#define timer_enter(t) do { } while (0) +#define timer_exit() do { } while (0) +#define timer_is_running(t) (0) +#define timer_synchronize(t) do { (void)(t); barrier(); } while(0) +#endif void add_timer(struct timer_list *timer) { @@ -216,6 +228,11 @@ } #ifdef CONFIG_SMP +void sync_timers(void) +{ + spin_unlock_wait(&global_bh_lock); +} + /* * SMP specific function to delete periodic timer. * Caller must disable by some means restarting the timer | |