diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2014-02-28 05:53:48 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-02-28 05:53:48 -0500 |
commit | bce19369515ff77033d0916cfbc356eca2be9f63 (patch) | |
tree | 7c06f066ee2c117fcbe6ab9744b734d8fe7f4d11 | |
parent | f96a34e27df19335155394a235ea3a096bc52a71 (diff) | |
parent | aea369b959bef10d235cd0714789cd8b0fe170b8 (diff) |
Merge branch 'timers.2014.02.25a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into timers/core
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | kernel/timer.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index b75e7893be14..a71bdfdb51e7 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -81,6 +81,7 @@ struct tvec_base { | |||
81 | unsigned long timer_jiffies; | 81 | unsigned long timer_jiffies; |
82 | unsigned long next_timer; | 82 | unsigned long next_timer; |
83 | unsigned long active_timers; | 83 | unsigned long active_timers; |
84 | unsigned long all_timers; | ||
84 | struct tvec_root tv1; | 85 | struct tvec_root tv1; |
85 | struct tvec tv2; | 86 | struct tvec tv2; |
86 | struct tvec tv3; | 87 | struct tvec tv3; |
@@ -337,6 +338,20 @@ void set_timer_slack(struct timer_list *timer, int slack_hz) | |||
337 | } | 338 | } |
338 | EXPORT_SYMBOL_GPL(set_timer_slack); | 339 | EXPORT_SYMBOL_GPL(set_timer_slack); |
339 | 340 | ||
341 | /* | ||
342 | * If the list is empty, catch up ->timer_jiffies to the current time. | ||
343 | * The caller must hold the tvec_base lock. Returns true if the list | ||
344 | * was empty and therefore ->timer_jiffies was updated. | ||
345 | */ | ||
346 | static bool catchup_timer_jiffies(struct tvec_base *base) | ||
347 | { | ||
348 | if (!base->all_timers) { | ||
349 | base->timer_jiffies = jiffies; | ||
350 | return true; | ||
351 | } | ||
352 | return false; | ||
353 | } | ||
354 | |||
340 | static void | 355 | static void |
341 | __internal_add_timer(struct tvec_base *base, struct timer_list *timer) | 356 | __internal_add_timer(struct tvec_base *base, struct timer_list *timer) |
342 | { | 357 | { |
@@ -383,15 +398,17 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer) | |||
383 | 398 | ||
384 | static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) | 399 | static void internal_add_timer(struct tvec_base *base, struct timer_list *timer) |
385 | { | 400 | { |
401 | (void)catchup_timer_jiffies(base); | ||
386 | __internal_add_timer(base, timer); | 402 | __internal_add_timer(base, timer); |
387 | /* | 403 | /* |
388 | * Update base->active_timers and base->next_timer | 404 | * Update base->active_timers and base->next_timer |
389 | */ | 405 | */ |
390 | if (!tbase_get_deferrable(timer->base)) { | 406 | if (!tbase_get_deferrable(timer->base)) { |
391 | if (time_before(timer->expires, base->next_timer)) | 407 | if (!base->active_timers++ || |
408 | time_before(timer->expires, base->next_timer)) | ||
392 | base->next_timer = timer->expires; | 409 | base->next_timer = timer->expires; |
393 | base->active_timers++; | ||
394 | } | 410 | } |
411 | base->all_timers++; | ||
395 | } | 412 | } |
396 | 413 | ||
397 | #ifdef CONFIG_TIMER_STATS | 414 | #ifdef CONFIG_TIMER_STATS |
@@ -671,6 +688,8 @@ detach_expired_timer(struct timer_list *timer, struct tvec_base *base) | |||
671 | detach_timer(timer, true); | 688 | detach_timer(timer, true); |
672 | if (!tbase_get_deferrable(timer->base)) | 689 | if (!tbase_get_deferrable(timer->base)) |
673 | base->active_timers--; | 690 | base->active_timers--; |
691 | base->all_timers--; | ||
692 | (void)catchup_timer_jiffies(base); | ||
674 | } | 693 | } |
675 | 694 | ||
676 | static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, | 695 | static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, |
@@ -685,6 +704,8 @@ static int detach_if_pending(struct timer_list *timer, struct tvec_base *base, | |||
685 | if (timer->expires == base->next_timer) | 704 | if (timer->expires == base->next_timer) |
686 | base->next_timer = base->timer_jiffies; | 705 | base->next_timer = base->timer_jiffies; |
687 | } | 706 | } |
707 | base->all_timers--; | ||
708 | (void)catchup_timer_jiffies(base); | ||
688 | return 1; | 709 | return 1; |
689 | } | 710 | } |
690 | 711 | ||
@@ -1153,6 +1174,10 @@ static inline void __run_timers(struct tvec_base *base) | |||
1153 | struct timer_list *timer; | 1174 | struct timer_list *timer; |
1154 | 1175 | ||
1155 | spin_lock_irq(&base->lock); | 1176 | spin_lock_irq(&base->lock); |
1177 | if (catchup_timer_jiffies(base)) { | ||
1178 | spin_unlock_irq(&base->lock); | ||
1179 | return; | ||
1180 | } | ||
1156 | while (time_after_eq(jiffies, base->timer_jiffies)) { | 1181 | while (time_after_eq(jiffies, base->timer_jiffies)) { |
1157 | struct list_head work_list; | 1182 | struct list_head work_list; |
1158 | struct list_head *head = &work_list; | 1183 | struct list_head *head = &work_list; |
@@ -1566,6 +1591,7 @@ static int init_timers_cpu(int cpu) | |||
1566 | base->timer_jiffies = jiffies; | 1591 | base->timer_jiffies = jiffies; |
1567 | base->next_timer = base->timer_jiffies; | 1592 | base->next_timer = base->timer_jiffies; |
1568 | base->active_timers = 0; | 1593 | base->active_timers = 0; |
1594 | base->all_timers = 0; | ||
1569 | return 0; | 1595 | return 0; |
1570 | } | 1596 | } |
1571 | 1597 | ||