aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2014-06-21 19:29:14 -0400
committerThomas Gleixner <tglx@linutronix.de>2014-06-23 05:23:47 -0400
commit9f6d9baaa8ca94b48aea495261cadaf2967c7784 (patch)
treefec9f1a108808a1716ec72f3c40a4da72a396a08 /kernel
parentd6f93829811a3e74f58e3c3823d507411eed651a (diff)
timer: Kick dynticks targets on mod_timer*() calls
When a timer is enqueued or modified on a dynticks target, that CPU must re-evaluate the next tick to service that timer. The tick re-evaluation is performed by an IPI kick on the target. Now while we correctly call wake_up_nohz_cpu() from add_timer_on(), the mod_timer*() API family doesn't support so well dynticks targets. The reason for this is likely that __mod_timer() isn't supposed to select an idle target for a timer, unless that target is the current CPU, in which case a dynticks idle kick isn't actually needed. But there is a small race window lurking behind that assumption: the elected target has all the time to turn dynticks idle between the call to get_nohz_timer_target() and the locking of its base. Hence a risk that we enqueue a timer on a dynticks idle destination without kicking it. As a result, the timer might be serviced too late in the future. Also a target elected by __mod_timer() can be in full dynticks mode and thus require to be kicked as well. And unlike idle dynticks, this concern both local and remote targets. To fix this whole issue, lets centralize the dynticks kick to internal_add_timer() so that it is well handled for all sort of timer enqueue. Even timer migration is concerned so that a full dynticks target is correctly kicked as needed when timers are migrating to it. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Link: http://lkml.kernel.org/r/1403393357-2070-3-git-send-email-fweisbec@gmail.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/timer.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 9e5f4f25dcc0..aca5dfe2fa3d 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -410,6 +410,22 @@ static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
410 base->next_timer = timer->expires; 410 base->next_timer = timer->expires;
411 } 411 }
412 base->all_timers++; 412 base->all_timers++;
413
414 /*
415 * Check whether the other CPU is in dynticks mode and needs
416 * to be triggered to reevaluate the timer wheel.
417 * We are protected against the other CPU fiddling
418 * with the timer by holding the timer base lock. This also
419 * makes sure that a CPU on the way to stop its tick can not
420 * evaluate the timer wheel.
421 *
422 * Spare the IPI for deferrable timers on idle targets though.
423 * The next busy ticks will take care of it. Except full dynticks
424 * require special care against races with idle_cpu(), lets deal
425 * with that later.
426 */
427 if (!tbase_get_deferrable(base) || tick_nohz_full_cpu(base->cpu))
428 wake_up_nohz_cpu(base->cpu);
413} 429}
414 430
415#ifdef CONFIG_TIMER_STATS 431#ifdef CONFIG_TIMER_STATS
@@ -949,22 +965,6 @@ void add_timer_on(struct timer_list *timer, int cpu)
949 timer_set_base(timer, base); 965 timer_set_base(timer, base);
950 debug_activate(timer, timer->expires); 966 debug_activate(timer, timer->expires);
951 internal_add_timer(base, timer); 967 internal_add_timer(base, timer);
952 /*
953 * Check whether the other CPU is in dynticks mode and needs
954 * to be triggered to reevaluate the timer wheel.
955 * We are protected against the other CPU fiddling
956 * with the timer by holding the timer base lock. This also
957 * makes sure that a CPU on the way to stop its tick can not
958 * evaluate the timer wheel.
959 *
960 * Spare the IPI for deferrable timers on idle targets though.
961 * The next busy ticks will take care of it. Except full dynticks
962 * require special care against races with idle_cpu(), lets deal
963 * with that later.
964 */
965 if (!tbase_get_deferrable(timer->base) || tick_nohz_full_cpu(cpu))
966 wake_up_nohz_cpu(cpu);
967
968 spin_unlock_irqrestore(&base->lock, flags); 968 spin_unlock_irqrestore(&base->lock, flags);
969} 969}
970EXPORT_SYMBOL_GPL(add_timer_on); 970EXPORT_SYMBOL_GPL(add_timer_on);