summaryrefslogtreecommitdiff
path: root/kernel/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/timer.c')
-rw-r--r--kernel/timer.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index 3c19cec3570d..ffc50df1a072 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -69,6 +69,30 @@ static DEFINE_PER_CPU(tvec_base_t, tvec_bases) = { SPIN_LOCK_UNLOCKED };
/* Fake initialization needed to avoid compiler breakage */
static DEFINE_PER_CPU(struct tasklet_struct, timer_tasklet) = { NULL };
+static void check_timer_failed(timer_t *timer)
+{
+ static int whine_count;
+ if (whine_count < 16) {
+ whine_count++;
+ printk("Uninitialised timer!\n");
+ printk("This is just a warning. Your computer is OK\n");
+ printk("function=0x%p, data=0x%lx\n",
+ timer->function, timer->data);
+ dump_stack();
+ }
+ /*
+ * Now fix it up
+ */
+ spin_lock_init(&timer->lock);
+ timer->magic = TIMER_MAGIC;
+}
+
+static inline void check_timer(timer_t *timer)
+{
+ if (timer->magic != TIMER_MAGIC)
+ check_timer_failed(timer);
+}
+
static inline void internal_add_timer(tvec_base_t *base, timer_t *timer)
{
unsigned long expires = timer->expires;
@@ -129,6 +153,8 @@ void add_timer(timer_t *timer)
BUG_ON(timer_pending(timer) || !timer->function);
+ check_timer(timer);
+
spin_lock_irqsave(&base->lock, flags);
internal_add_timer(base, timer);
timer->base = base;
@@ -150,6 +176,8 @@ void add_timer_on(struct timer_list *timer, int cpu)
BUG_ON(timer_pending(timer) || !timer->function);
+ check_timer(timer);
+
spin_lock_irqsave(&base->lock, flags);
internal_add_timer(base, timer);
timer->base = base;
@@ -182,6 +210,9 @@ int mod_timer(timer_t *timer, unsigned long expires)
int ret = 0;
BUG_ON(!timer->function);
+
+ check_timer(timer);
+
/*
* This is a common optimization triggered by the
* networking code - if the timer is re-modified
@@ -190,7 +221,7 @@ int mod_timer(timer_t *timer, unsigned long expires)
if (timer->expires == expires && timer_pending(timer))
return 1;
- local_irq_save(flags);
+ spin_lock_irqsave(&timer->lock, flags);
new_base = &per_cpu(tvec_bases, smp_processor_id());
repeat:
old_base = timer->base;
@@ -207,7 +238,7 @@ repeat:
spin_lock(&new_base->lock);
}
/*
- * The timer base might have changed while we were
+ * The timer base might have been cancelled while we were
* trying to take the lock(s):
*/
if (timer->base != old_base) {
@@ -232,7 +263,8 @@ repeat:
if (old_base && (new_base != old_base))
spin_unlock(&old_base->lock);
- spin_unlock_irqrestore(&new_base->lock, flags);
+ spin_unlock(&new_base->lock);
+ spin_unlock_irqrestore(&timer->lock, flags);
return ret;
}
@@ -253,6 +285,8 @@ int del_timer(timer_t *timer)
unsigned long flags;
tvec_base_t *base;
+ check_timer(timer);
+
repeat:
base = timer->base;
if (!base)
@@ -290,6 +324,8 @@ int del_timer_sync(timer_t *timer)
tvec_base_t *base;
int i, ret = 0;
+ check_timer(timer);
+
del_again:
ret += del_timer(timer);