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 | ||
