diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-01-13 01:03:44 +0100 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-01-13 01:03:44 +0100 |
commit | cc00657854df4e868598b6447ea5599798604da9 (patch) | |
tree | 458e3a04aabf424fed3c7eecdf7980352f030eb1 /xen/common/timer.c | |
parent | c5c75c292628864e2f22c4186f8f16da10fbe6da (diff) | |
download | xen-cc00657854df4e868598b6447ea5599798604da9.tar.gz xen-cc00657854df4e868598b6447ea5599798604da9.tar.bz2 xen-cc00657854df4e868598b6447ea5599798604da9.zip |
Add a new timer operation kill_timer(). Effectively the
'opposite' of init_timer(), it marks the end of a timer's
lifetime. After this call the timer will not be pending,
its callback handler will not be running, and future calls
to set_timer() will silently fail.
Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/common/timer.c')
-rw-r--r-- | xen/common/timer.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/xen/common/timer.c b/xen/common/timer.c index 336b0a15d1..55f39bfa98 100644 --- a/xen/common/timer.c +++ b/xen/common/timer.c @@ -29,6 +29,7 @@ struct timers { spinlock_t lock; struct timer **heap; + struct timer *running; } __cacheline_aligned; struct timers timers[NR_CPUS]; @@ -167,11 +168,11 @@ void set_timer(struct timer *timer, s_time_t expires) unsigned long flags; spin_lock_irqsave(&timers[cpu].lock, flags); - ASSERT(timer != NULL); if ( active_timer(timer) ) __stop_timer(timer); timer->expires = expires; - __add_timer(timer); + if ( likely(!timer->killed) ) + __add_timer(timer); spin_unlock_irqrestore(&timers[cpu].lock, flags); } @@ -182,13 +183,31 @@ void stop_timer(struct timer *timer) unsigned long flags; spin_lock_irqsave(&timers[cpu].lock, flags); - ASSERT(timer != NULL); if ( active_timer(timer) ) __stop_timer(timer); spin_unlock_irqrestore(&timers[cpu].lock, flags); } +void kill_timer(struct timer *timer) +{ + int cpu = timer->cpu; + unsigned long flags; + + BUG_ON(timers[cpu].running == timer); + + spin_lock_irqsave(&timers[cpu].lock, flags); + if ( active_timer(timer) ) + __stop_timer(timer); + timer->killed = 1; + spin_unlock_irqrestore(&timers[cpu].lock, flags); + + for_each_online_cpu ( cpu ) + while ( timers[cpu].running == timer ) + cpu_relax(); +} + + static void timer_softirq_action(void) { int cpu = smp_processor_id(); @@ -208,19 +227,20 @@ static void timer_softirq_action(void) { remove_entry(heap, t); + timers[cpu].running = t; + fn = t->function; data = t->data; - if ( fn != NULL ) - { - spin_unlock_irq(&timers[cpu].lock); - (*fn)(data); - spin_lock_irq(&timers[cpu].lock); - } + spin_unlock_irq(&timers[cpu].lock); + (*fn)(data); + spin_lock_irq(&timers[cpu].lock); /* Heap may have grown while the lock was released. */ heap = timers[cpu].heap; } + + timers[cpu].running = NULL; } while ( !reprogram_timer(GET_HEAP_SIZE(heap) ? heap[1]->expires : 0) ); |