diff options
| -rw-r--r-- | include/linux/timer.h | 10 | ||||
| -rw-r--r-- | kernel/timer.c | 56 |
2 files changed, 65 insertions, 1 deletions
diff --git a/include/linux/timer.h b/include/linux/timer.h index a2d1eb6cb3f0..ea965b857a50 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h | |||
| @@ -10,13 +10,19 @@ | |||
| 10 | struct tvec_base; | 10 | struct tvec_base; |
| 11 | 11 | ||
| 12 | struct timer_list { | 12 | struct timer_list { |
| 13 | /* | ||
| 14 | * All fields that change during normal runtime grouped to the | ||
| 15 | * same cacheline | ||
| 16 | */ | ||
| 13 | struct list_head entry; | 17 | struct list_head entry; |
| 14 | unsigned long expires; | 18 | unsigned long expires; |
| 19 | struct tvec_base *base; | ||
| 15 | 20 | ||
| 16 | void (*function)(unsigned long); | 21 | void (*function)(unsigned long); |
| 17 | unsigned long data; | 22 | unsigned long data; |
| 18 | 23 | ||
| 19 | struct tvec_base *base; | 24 | int slack; |
| 25 | |||
| 20 | #ifdef CONFIG_TIMER_STATS | 26 | #ifdef CONFIG_TIMER_STATS |
| 21 | void *start_site; | 27 | void *start_site; |
| 22 | char start_comm[16]; | 28 | char start_comm[16]; |
| @@ -165,6 +171,8 @@ extern int mod_timer(struct timer_list *timer, unsigned long expires); | |||
| 165 | extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); | 171 | extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); |
| 166 | extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); | 172 | extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); |
| 167 | 173 | ||
| 174 | extern void set_timer_slack(struct timer_list *time, int slack_hz); | ||
| 175 | |||
| 168 | #define TIMER_NOT_PINNED 0 | 176 | #define TIMER_NOT_PINNED 0 |
| 169 | #define TIMER_PINNED 1 | 177 | #define TIMER_PINNED 1 |
| 170 | /* | 178 | /* |
diff --git a/kernel/timer.c b/kernel/timer.c index 7e12e7bc7ce6..49773f38c9bc 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
| @@ -318,6 +318,24 @@ unsigned long round_jiffies_up_relative(unsigned long j) | |||
| 318 | } | 318 | } |
| 319 | EXPORT_SYMBOL_GPL(round_jiffies_up_relative); | 319 | EXPORT_SYMBOL_GPL(round_jiffies_up_relative); |
| 320 | 320 | ||
| 321 | /** | ||
| 322 | * set_timer_slack - set the allowed slack for a timer | ||
| 323 | * @slack_hz: the amount of time (in jiffies) allowed for rounding | ||
| 324 | * | ||
| 325 | * Set the amount of time, in jiffies, that a certain timer has | ||
| 326 | * in terms of slack. By setting this value, the timer subsystem | ||
| 327 | * will schedule the actual timer somewhere between | ||
| 328 | * the time mod_timer() asks for, and that time plus the slack. | ||
| 329 | * | ||
| 330 | * By setting the slack to -1, a percentage of the delay is used | ||
| 331 | * instead. | ||
| 332 | */ | ||
| 333 | void set_timer_slack(struct timer_list *timer, int slack_hz) | ||
| 334 | { | ||
| 335 | timer->slack = slack_hz; | ||
| 336 | } | ||
| 337 | EXPORT_SYMBOL_GPL(set_timer_slack); | ||
| 338 | |||
| 321 | 339 | ||
| 322 | static inline void set_running_timer(struct tvec_base *base, | 340 | static inline void set_running_timer(struct tvec_base *base, |
| 323 | struct timer_list *timer) | 341 | struct timer_list *timer) |
| @@ -549,6 +567,7 @@ static void __init_timer(struct timer_list *timer, | |||
| 549 | { | 567 | { |
| 550 | timer->entry.next = NULL; | 568 | timer->entry.next = NULL; |
| 551 | timer->base = __raw_get_cpu_var(tvec_bases); | 569 | timer->base = __raw_get_cpu_var(tvec_bases); |
| 570 | timer->slack = -1; | ||
| 552 | #ifdef CONFIG_TIMER_STATS | 571 | #ifdef CONFIG_TIMER_STATS |
| 553 | timer->start_site = NULL; | 572 | timer->start_site = NULL; |
| 554 | timer->start_pid = -1; | 573 | timer->start_pid = -1; |
| @@ -714,6 +733,41 @@ int mod_timer_pending(struct timer_list *timer, unsigned long expires) | |||
| 714 | } | 733 | } |
| 715 | EXPORT_SYMBOL(mod_timer_pending); | 734 | EXPORT_SYMBOL(mod_timer_pending); |
| 716 | 735 | ||
| 736 | /* | ||
| 737 | * Decide where to put the timer while taking the slack into account | ||
| 738 | * | ||
| 739 | * Algorithm: | ||
| 740 | * 1) calculate the maximum (absolute) time | ||
| 741 | * 2) calculate the highest bit where the expires and new max are different | ||
| 742 | * 3) use this bit to make a mask | ||
| 743 | * 4) use the bitmask to round down the maximum time, so that all last | ||
| 744 | * bits are zeros | ||
| 745 | */ | ||
| 746 | static inline | ||
| 747 | unsigned long apply_slack(struct timer_list *timer, unsigned long expires) | ||
| 748 | { | ||
| 749 | unsigned long expires_limit, mask; | ||
| 750 | int bit; | ||
| 751 | |||
| 752 | expires_limit = expires + timer->slack; | ||
| 753 | |||
| 754 | if (timer->slack < 0) /* auto slack: use 0.4% */ | ||
| 755 | expires_limit = expires + (expires - jiffies)/256; | ||
| 756 | |||
| 757 | mask = expires ^ expires_limit; | ||
| 758 | |||
| 759 | if (mask == 0) | ||
| 760 | return expires; | ||
| 761 | |||
| 762 | bit = find_last_bit(&mask, BITS_PER_LONG); | ||
| 763 | |||
| 764 | mask = (1 << bit) - 1; | ||
| 765 | |||
| 766 | expires_limit = expires_limit & ~(mask); | ||
| 767 | |||
| 768 | return expires_limit; | ||
| 769 | } | ||
| 770 | |||
| 717 | /** | 771 | /** |
| 718 | * mod_timer - modify a timer's timeout | 772 | * mod_timer - modify a timer's timeout |
| 719 | * @timer: the timer to be modified | 773 | * @timer: the timer to be modified |
| @@ -744,6 +798,8 @@ int mod_timer(struct timer_list *timer, unsigned long expires) | |||
| 744 | if (timer_pending(timer) && timer->expires == expires) | 798 | if (timer_pending(timer) && timer->expires == expires) |
| 745 | return 1; | 799 | return 1; |
| 746 | 800 | ||
| 801 | expires = apply_slack(timer, expires); | ||
| 802 | |||
| 747 | return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); | 803 | return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); |
| 748 | } | 804 | } |
| 749 | EXPORT_SYMBOL(mod_timer); | 805 | EXPORT_SYMBOL(mod_timer); |
