Commit d4979c79 authored by Ingo Molnar's avatar Ingo Molnar

[PATCH] timer cleanups

This is my latest timer patchset, it makes del_timer_sync() a bit more
robust wrt.  code that re-adds timers from the timer handler.

Other changes in the patch:

 - clean up cascading a bit.

 - do not save flags in __run_timer_list - we enter from an irqs-enabled
   tasklet.
parent 469d2810
...@@ -266,29 +266,31 @@ int del_timer(timer_t *timer) ...@@ -266,29 +266,31 @@ int del_timer(timer_t *timer)
int del_timer_sync(timer_t *timer) int del_timer_sync(timer_t *timer)
{ {
tvec_base_t *base = tvec_bases; tvec_base_t *base = tvec_bases;
int i, ret; int i, ret = 0;
ret = del_timer(timer); del_again:
ret += del_timer(timer);
for (i = 0; i < NR_CPUS; i++) { for (i = 0; i < NR_CPUS; i++, base++) {
if (!cpu_online(i)) if (!cpu_online(i))
continue; continue;
if (base->running_timer == timer) { if (base->running_timer == timer) {
while (base->running_timer == timer) { while (base->running_timer == timer) {
cpu_relax(); cpu_relax();
preempt_disable(); preempt_check_resched();
preempt_enable();
} }
break; break;
} }
base++;
} }
if (timer_pending(timer))
goto del_again;
return ret; return ret;
} }
#endif #endif
static void cascade(tvec_base_t *base, tvec_t *tv) static int cascade(tvec_base_t *base, tvec_t *tv)
{ {
/* cascade all the timers from tv up one level */ /* cascade all the timers from tv up one level */
struct list_head *head, *curr, *next; struct list_head *head, *curr, *next;
...@@ -310,7 +312,8 @@ static void cascade(tvec_base_t *base, tvec_t *tv) ...@@ -310,7 +312,8 @@ static void cascade(tvec_base_t *base, tvec_t *tv)
curr = next; curr = next;
} }
INIT_LIST_HEAD(head); INIT_LIST_HEAD(head);
tv->index = (tv->index + 1) & TVN_MASK;
return tv->index = (tv->index + 1) & TVN_MASK;
} }
/*** /***
...@@ -322,26 +325,18 @@ static void cascade(tvec_base_t *base, tvec_t *tv) ...@@ -322,26 +325,18 @@ static void cascade(tvec_base_t *base, tvec_t *tv)
*/ */
static inline void __run_timers(tvec_base_t *base) static inline void __run_timers(tvec_base_t *base)
{ {
unsigned long flags; spin_lock_irq(&base->lock);
spin_lock_irqsave(&base->lock, flags);
while ((long)(jiffies - base->timer_jiffies) >= 0) { while ((long)(jiffies - base->timer_jiffies) >= 0) {
struct list_head *head, *curr; struct list_head *head, *curr;
/* /*
* Cascade timers: * Cascade timers:
*/ */
if (!base->tv1.index) { if (!base->tv1.index &&
cascade(base, &base->tv2); (cascade(base, &base->tv2) == 1) &&
if (base->tv2.index == 1) { (cascade(base, &base->tv3) == 1) &&
cascade(base, &base->tv3); cascade(base, &base->tv4) == 1)
if (base->tv3.index == 1) {
cascade(base, &base->tv4);
if (base->tv4.index == 1)
cascade(base, &base->tv5); cascade(base, &base->tv5);
}
}
}
repeat: repeat:
head = base->tv1.vec + base->tv1.index; head = base->tv1.vec + base->tv1.index;
curr = head->next; curr = head->next;
...@@ -360,6 +355,9 @@ static inline void __run_timers(tvec_base_t *base) ...@@ -360,6 +355,9 @@ static inline void __run_timers(tvec_base_t *base)
base->running_timer = timer; base->running_timer = timer;
#endif #endif
spin_unlock_irq(&base->lock); spin_unlock_irq(&base->lock);
if (!fn)
printk("Bad: timer %p has NULL fn. (data: %08lx)\n", timer, data);
else
fn(data); fn(data);
spin_lock_irq(&base->lock); spin_lock_irq(&base->lock);
goto repeat; goto repeat;
...@@ -370,7 +368,7 @@ static inline void __run_timers(tvec_base_t *base) ...@@ -370,7 +368,7 @@ static inline void __run_timers(tvec_base_t *base)
#if CONFIG_SMP #if CONFIG_SMP
base->running_timer = NULL; base->running_timer = NULL;
#endif #endif
spin_unlock_irqrestore(&base->lock, flags); spin_unlock_irq(&base->lock);
} }
/******************************************************************/ /******************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment