aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArun R Bharadwaj <arun@linux.vnet.ibm.com>2009-04-16 02:43:26 -0400
committerThomas Gleixner <tglx@linutronix.de>2009-05-13 10:52:42 -0400
commit597d0275736dad9c3bda6f0a00a1c477dc0f37b1 (patch)
tree7ebbe9f80fb13a3ec34ea997d00c21eecf7699ae
parenta04198887658e1d8ae25f5420035c057cb170e67 (diff)
timers: Framework for identifying pinned timers
* Arun R Bharadwaj <arun@linux.vnet.ibm.com> [2009-04-16 12:11:36]: This patch creates a new framework for identifying cpu-pinned timers and hrtimers. This framework is needed because pinned timers are expected to fire on the same CPU on which they are queued. So it is essential to identify these and not migrate them, in case there are any. For regular timers, the currently existing add_timer_on() can be used queue pinned timers and subsequently mod_timer_pinned() can be used to modify the 'expires' field. For hrtimers, new modes HRTIMER_ABS_PINNED and HRTIMER_REL_PINNED are added to queue cpu-pinned hrtimer. [ tglx: use .._PINNED mode argument instead of creating tons of new functions ] Signed-off-by: Arun R Bharadwaj <arun@linux.vnet.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/hrtimer.h7
-rw-r--r--include/linux/timer.h3
-rw-r--r--kernel/hrtimer.c7
-rw-r--r--kernel/timer.c31
4 files changed, 39 insertions, 9 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 0d2f7c8a33d6..7400900de94a 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -30,8 +30,11 @@ struct hrtimer_cpu_base;
30 * Mode arguments of xxx_hrtimer functions: 30 * Mode arguments of xxx_hrtimer functions:
31 */ 31 */
32enum hrtimer_mode { 32enum hrtimer_mode {
33 HRTIMER_MODE_ABS, /* Time value is absolute */ 33 HRTIMER_MODE_ABS = 0x0, /* Time value is absolute */
34 HRTIMER_MODE_REL, /* Time value is relative to now */ 34 HRTIMER_MODE_REL = 0x1, /* Time value is relative to now */
35 HRTIMER_MODE_PINNED = 0x02, /* Timer is bound to CPU */
36 HRTIMER_MODE_ABS_PINNED = 0x02,
37 HRTIMER_MODE_REL_PINNED = 0x03,
35}; 38};
36 39
37/* 40/*
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 6cdb6f3331f1..ccf882eed8f8 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -163,7 +163,10 @@ extern void add_timer_on(struct timer_list *timer, int cpu);
163extern int del_timer(struct timer_list * timer); 163extern int del_timer(struct timer_list * timer);
164extern int mod_timer(struct timer_list *timer, unsigned long expires); 164extern int mod_timer(struct timer_list *timer, unsigned long expires);
165extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); 165extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
166extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires);
166 167
168#define TIMER_NOT_PINNED 0
169#define TIMER_PINNED 1
167/* 170/*
168 * The jiffies value which is added to now, when there is no timer 171 * The jiffies value which is added to now, when there is no timer
169 * in the timer wheel: 172 * in the timer wheel:
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index cb8a15c19583..c71bcd549241 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -193,7 +193,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
193 * Switch the timer base to the current CPU when possible. 193 * Switch the timer base to the current CPU when possible.
194 */ 194 */
195static inline struct hrtimer_clock_base * 195static inline struct hrtimer_clock_base *
196switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base) 196switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
197 int pinned)
197{ 198{
198 struct hrtimer_clock_base *new_base; 199 struct hrtimer_clock_base *new_base;
199 struct hrtimer_cpu_base *new_cpu_base; 200 struct hrtimer_cpu_base *new_cpu_base;
@@ -907,9 +908,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
907 ret = remove_hrtimer(timer, base); 908 ret = remove_hrtimer(timer, base);
908 909
909 /* Switch the timer base, if necessary: */ 910 /* Switch the timer base, if necessary: */
910 new_base = switch_hrtimer_base(timer, base); 911 new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
911 912
912 if (mode == HRTIMER_MODE_REL) { 913 if (mode & HRTIMER_MODE_REL) {
913 tim = ktime_add_safe(tim, new_base->get_time()); 914 tim = ktime_add_safe(tim, new_base->get_time());
914 /* 915 /*
915 * CONFIG_TIME_LOW_RES is a temporary way for architectures 916 * CONFIG_TIME_LOW_RES is a temporary way for architectures
diff --git a/kernel/timer.c b/kernel/timer.c
index 5c1e84beaf4a..3424dfd11d50 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -604,7 +604,8 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer,
604} 604}
605 605
606static inline int 606static inline int
607__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) 607__mod_timer(struct timer_list *timer, unsigned long expires,
608 bool pending_only, int pinned)
608{ 609{
609 struct tvec_base *base, *new_base; 610 struct tvec_base *base, *new_base;
610 unsigned long flags; 611 unsigned long flags;
@@ -668,7 +669,7 @@ out_unlock:
668 */ 669 */
669int mod_timer_pending(struct timer_list *timer, unsigned long expires) 670int mod_timer_pending(struct timer_list *timer, unsigned long expires)
670{ 671{
671 return __mod_timer(timer, expires, true); 672 return __mod_timer(timer, expires, true, TIMER_NOT_PINNED);
672} 673}
673EXPORT_SYMBOL(mod_timer_pending); 674EXPORT_SYMBOL(mod_timer_pending);
674 675
@@ -702,11 +703,33 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
702 if (timer->expires == expires && timer_pending(timer)) 703 if (timer->expires == expires && timer_pending(timer))
703 return 1; 704 return 1;
704 705
705 return __mod_timer(timer, expires, false); 706 return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
706} 707}
707EXPORT_SYMBOL(mod_timer); 708EXPORT_SYMBOL(mod_timer);
708 709
709/** 710/**
711 * mod_timer_pinned - modify a timer's timeout
712 * @timer: the timer to be modified
713 * @expires: new timeout in jiffies
714 *
715 * mod_timer_pinned() is a way to update the expire field of an
716 * active timer (if the timer is inactive it will be activated)
717 * and not allow the timer to be migrated to a different CPU.
718 *
719 * mod_timer_pinned(timer, expires) is equivalent to:
720 *
721 * del_timer(timer); timer->expires = expires; add_timer(timer);
722 */
723int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
724{
725 if (timer->expires == expires && timer_pending(timer))
726 return 1;
727
728 return __mod_timer(timer, expires, false, TIMER_PINNED);
729}
730EXPORT_SYMBOL(mod_timer_pinned);
731
732/**
710 * add_timer - start a timer 733 * add_timer - start a timer
711 * @timer: the timer to be added 734 * @timer: the timer to be added
712 * 735 *
@@ -1356,7 +1379,7 @@ signed long __sched schedule_timeout(signed long timeout)
1356 expire = timeout + jiffies; 1379 expire = timeout + jiffies;
1357 1380
1358 setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); 1381 setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
1359 __mod_timer(&timer, expire, false); 1382 __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
1360 schedule(); 1383 schedule();
1361 del_singleshot_timer_sync(&timer); 1384 del_singleshot_timer_sync(&timer);
1362 1385