diff options
Diffstat (limited to 'kernel/timer.c')
-rw-r--r-- | kernel/timer.c | 92 |
1 files changed, 38 insertions, 54 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index ab189dd187c..6b812c04737 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -54,7 +54,6 @@ EXPORT_SYMBOL(jiffies_64); /* * per-CPU timer vector definitions: */ - #define TVN_BITS (CONFIG_BASE_SMALL ? 4 : 6) #define TVR_BITS (CONFIG_BASE_SMALL ? 6 : 8) #define TVN_SIZE (1 << TVN_BITS) @@ -62,11 +61,6 @@ EXPORT_SYMBOL(jiffies_64); #define TVN_MASK (TVN_SIZE - 1) #define TVR_MASK (TVR_SIZE - 1) -struct timer_base_s { - spinlock_t lock; - struct timer_list *running_timer; -}; - typedef struct tvec_s { struct list_head vec[TVN_SIZE]; } tvec_t; @@ -76,7 +70,8 @@ typedef struct tvec_root_s { } tvec_root_t; struct tvec_t_base_s { - struct timer_base_s t_base; + spinlock_t lock; + struct timer_list *running_timer; unsigned long timer_jiffies; tvec_root_t tv1; tvec_t tv2; @@ -87,13 +82,14 @@ struct tvec_t_base_s { typedef struct tvec_t_base_s tvec_base_t; static DEFINE_PER_CPU(tvec_base_t *, tvec_bases); -static tvec_base_t boot_tvec_bases; +tvec_base_t boot_tvec_bases; +EXPORT_SYMBOL(boot_tvec_bases); static inline void set_running_timer(tvec_base_t *base, struct timer_list *timer) { #ifdef CONFIG_SMP - base->t_base.running_timer = timer; + base->running_timer = timer; #endif } @@ -139,15 +135,6 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer) list_add_tail(&timer->entry, vec); } -typedef struct timer_base_s timer_base_t; -/* - * Used by TIMER_INITIALIZER, we can't use per_cpu(tvec_bases) - * at compile time, and we need timer->base to lock the timer. - */ -timer_base_t __init_timer_base - ____cacheline_aligned_in_smp = { .lock = SPIN_LOCK_UNLOCKED }; -EXPORT_SYMBOL(__init_timer_base); - /*** * init_timer - initialize a timer. * @timer: the timer to be initialized @@ -158,7 +145,7 @@ EXPORT_SYMBOL(__init_timer_base); void fastcall init_timer(struct timer_list *timer) { timer->entry.next = NULL; - timer->base = &per_cpu(tvec_bases, raw_smp_processor_id())->t_base; + timer->base = per_cpu(tvec_bases, raw_smp_processor_id()); } EXPORT_SYMBOL(init_timer); @@ -174,7 +161,7 @@ static inline void detach_timer(struct timer_list *timer, } /* - * We are using hashed locking: holding per_cpu(tvec_bases).t_base.lock + * We are using hashed locking: holding per_cpu(tvec_bases).lock * means that all timers which are tied to this base via timer->base are * locked, and the base itself is locked too. * @@ -185,10 +172,10 @@ static inline void detach_timer(struct timer_list *timer, * possible to set timer->base = NULL and drop the lock: the timer remains * locked. */ -static timer_base_t *lock_timer_base(struct timer_list *timer, +static tvec_base_t *lock_timer_base(struct timer_list *timer, unsigned long *flags) { - timer_base_t *base; + tvec_base_t *base; for (;;) { base = timer->base; @@ -205,8 +192,7 @@ static timer_base_t *lock_timer_base(struct timer_list *timer, int __mod_timer(struct timer_list *timer, unsigned long expires) { - timer_base_t *base; - tvec_base_t *new_base; + tvec_base_t *base, *new_base; unsigned long flags; int ret = 0; @@ -221,7 +207,7 @@ int __mod_timer(struct timer_list *timer, unsigned long expires) new_base = __get_cpu_var(tvec_bases); - if (base != &new_base->t_base) { + if (base != new_base) { /* * We are trying to schedule the timer on the local CPU. * However we can't change timer's base while it is running, @@ -229,21 +215,19 @@ int __mod_timer(struct timer_list *timer, unsigned long expires) * handler yet has not finished. This also guarantees that * the timer is serialized wrt itself. */ - if (unlikely(base->running_timer == timer)) { - /* The timer remains on a former base */ - new_base = container_of(base, tvec_base_t, t_base); - } else { + if (likely(base->running_timer != timer)) { /* See the comment in lock_timer_base() */ timer->base = NULL; spin_unlock(&base->lock); - spin_lock(&new_base->t_base.lock); - timer->base = &new_base->t_base; + base = new_base; + spin_lock(&base->lock); + timer->base = base; } } timer->expires = expires; - internal_add_timer(new_base, timer); - spin_unlock_irqrestore(&new_base->t_base.lock, flags); + internal_add_timer(base, timer); + spin_unlock_irqrestore(&base->lock, flags); return ret; } @@ -263,10 +247,10 @@ void add_timer_on(struct timer_list *timer, int cpu) unsigned long flags; BUG_ON(timer_pending(timer) || !timer->function); - spin_lock_irqsave(&base->t_base.lock, flags); - timer->base = &base->t_base; + spin_lock_irqsave(&base->lock, flags); + timer->base = base; internal_add_timer(base, timer); - spin_unlock_irqrestore(&base->t_base.lock, flags); + spin_unlock_irqrestore(&base->lock, flags); } @@ -319,7 +303,7 @@ EXPORT_SYMBOL(mod_timer); */ int del_timer(struct timer_list *timer) { - timer_base_t *base; + tvec_base_t *base; unsigned long flags; int ret = 0; @@ -346,7 +330,7 @@ EXPORT_SYMBOL(del_timer); */ int try_to_del_timer_sync(struct timer_list *timer) { - timer_base_t *base; + tvec_base_t *base; unsigned long flags; int ret = -1; @@ -410,7 +394,7 @@ static int cascade(tvec_base_t *base, tvec_t *tv, int index) struct timer_list *tmp; tmp = list_entry(curr, struct timer_list, entry); - BUG_ON(tmp->base != &base->t_base); + BUG_ON(tmp->base != base); curr = curr->next; internal_add_timer(base, tmp); } @@ -432,7 +416,7 @@ static inline void __run_timers(tvec_base_t *base) { struct timer_list *timer; - spin_lock_irq(&base->t_base.lock); + spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->timer_jiffies)) { struct list_head work_list = LIST_HEAD_INIT(work_list); struct list_head *head = &work_list; @@ -458,7 +442,7 @@ static inline void __run_timers(tvec_base_t *base) set_running_timer(base, timer); detach_timer(timer, 1); - spin_unlock_irq(&base->t_base.lock); + spin_unlock_irq(&base->lock); { int preempt_count = preempt_count(); fn(data); @@ -471,11 +455,11 @@ static inline void __run_timers(tvec_base_t *base) BUG(); } } - spin_lock_irq(&base->t_base.lock); + spin_lock_irq(&base->lock); } } set_running_timer(base, NULL); - spin_unlock_irq(&base->t_base.lock); + spin_unlock_irq(&base->lock); } #ifdef CONFIG_NO_IDLE_HZ @@ -506,7 +490,7 @@ unsigned long next_timer_interrupt(void) hr_expires += jiffies; base = __get_cpu_var(tvec_bases); - spin_lock(&base->t_base.lock); + spin_lock(&base->lock); expires = base->timer_jiffies + (LONG_MAX >> 1); list = NULL; @@ -554,7 +538,7 @@ found: expires = nte->expires; } } - spin_unlock(&base->t_base.lock); + spin_unlock(&base->lock); if (time_before(hr_expires, expires)) return hr_expires; @@ -841,7 +825,7 @@ void update_process_times(int user_tick) */ static unsigned long count_active_tasks(void) { - return (nr_running() + nr_uninterruptible()) * FIXED_1; + return nr_active() * FIXED_1; } /* @@ -1262,7 +1246,7 @@ static int __devinit init_timers_cpu(int cpu) } per_cpu(tvec_bases, cpu) = base; } - spin_lock_init(&base->t_base.lock); + spin_lock_init(&base->lock); for (j = 0; j < TVN_SIZE; j++) { INIT_LIST_HEAD(base->tv5.vec + j); INIT_LIST_HEAD(base->tv4.vec + j); @@ -1284,7 +1268,7 @@ static void migrate_timer_list(tvec_base_t *new_base, struct list_head *head) while (!list_empty(head)) { timer = list_entry(head->next, struct timer_list, entry); detach_timer(timer, 0); - timer->base = &new_base->t_base; + timer->base = new_base; internal_add_timer(new_base, timer); } } @@ -1300,11 +1284,11 @@ static void __devinit migrate_timers(int cpu) new_base = get_cpu_var(tvec_bases); local_irq_disable(); - spin_lock(&new_base->t_base.lock); - spin_lock(&old_base->t_base.lock); + spin_lock(&new_base->lock); + spin_lock(&old_base->lock); + + BUG_ON(old_base->running_timer); - if (old_base->t_base.running_timer) - BUG(); for (i = 0; i < TVR_SIZE; i++) migrate_timer_list(new_base, old_base->tv1.vec + i); for (i = 0; i < TVN_SIZE; i++) { @@ -1314,8 +1298,8 @@ static void __devinit migrate_timers(int cpu) migrate_timer_list(new_base, old_base->tv5.vec + i); } - spin_unlock(&old_base->t_base.lock); - spin_unlock(&new_base->t_base.lock); + spin_unlock(&old_base->lock); + spin_unlock(&new_base->lock); local_irq_enable(); put_cpu_var(tvec_bases); } |