Commit 597d0275 authored by Arun R Bharadwaj's avatar Arun R Bharadwaj Committed by Thomas Gleixner

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: default avatarArun R Bharadwaj <arun@linux.vnet.ibm.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent a0419888
...@@ -30,8 +30,11 @@ struct hrtimer_cpu_base; ...@@ -30,8 +30,11 @@ struct hrtimer_cpu_base;
* Mode arguments of xxx_hrtimer functions: * Mode arguments of xxx_hrtimer functions:
*/ */
enum hrtimer_mode { enum hrtimer_mode {
HRTIMER_MODE_ABS, /* Time value is absolute */ HRTIMER_MODE_ABS = 0x0, /* Time value is absolute */
HRTIMER_MODE_REL, /* Time value is relative to now */ HRTIMER_MODE_REL = 0x1, /* Time value is relative to now */
HRTIMER_MODE_PINNED = 0x02, /* Timer is bound to CPU */
HRTIMER_MODE_ABS_PINNED = 0x02,
HRTIMER_MODE_REL_PINNED = 0x03,
}; };
/* /*
......
...@@ -163,7 +163,10 @@ extern void add_timer_on(struct timer_list *timer, int cpu); ...@@ -163,7 +163,10 @@ extern void add_timer_on(struct timer_list *timer, int cpu);
extern int del_timer(struct timer_list * timer); extern int del_timer(struct timer_list * timer);
extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer(struct timer_list *timer, unsigned long expires);
extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires);
#define TIMER_NOT_PINNED 0
#define TIMER_PINNED 1
/* /*
* The jiffies value which is added to now, when there is no timer * The jiffies value which is added to now, when there is no timer
* in the timer wheel: * in the timer wheel:
......
...@@ -193,7 +193,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, ...@@ -193,7 +193,8 @@ struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
* Switch the timer base to the current CPU when possible. * Switch the timer base to the current CPU when possible.
*/ */
static inline struct hrtimer_clock_base * static inline struct hrtimer_clock_base *
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base) switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
int pinned)
{ {
struct hrtimer_clock_base *new_base; struct hrtimer_clock_base *new_base;
struct hrtimer_cpu_base *new_cpu_base; struct hrtimer_cpu_base *new_cpu_base;
...@@ -907,9 +908,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, ...@@ -907,9 +908,9 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
ret = remove_hrtimer(timer, base); ret = remove_hrtimer(timer, base);
/* Switch the timer base, if necessary: */ /* Switch the timer base, if necessary: */
new_base = switch_hrtimer_base(timer, base); new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED);
if (mode == HRTIMER_MODE_REL) { if (mode & HRTIMER_MODE_REL) {
tim = ktime_add_safe(tim, new_base->get_time()); tim = ktime_add_safe(tim, new_base->get_time());
/* /*
* CONFIG_TIME_LOW_RES is a temporary way for architectures * CONFIG_TIME_LOW_RES is a temporary way for architectures
......
...@@ -604,7 +604,8 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer, ...@@ -604,7 +604,8 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer,
} }
static inline int static inline int
__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) __mod_timer(struct timer_list *timer, unsigned long expires,
bool pending_only, int pinned)
{ {
struct tvec_base *base, *new_base; struct tvec_base *base, *new_base;
unsigned long flags; unsigned long flags;
...@@ -668,7 +669,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) ...@@ -668,7 +669,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
*/ */
int mod_timer_pending(struct timer_list *timer, unsigned long expires) int mod_timer_pending(struct timer_list *timer, unsigned long expires)
{ {
return __mod_timer(timer, expires, true); return __mod_timer(timer, expires, true, TIMER_NOT_PINNED);
} }
EXPORT_SYMBOL(mod_timer_pending); EXPORT_SYMBOL(mod_timer_pending);
...@@ -702,10 +703,32 @@ int mod_timer(struct timer_list *timer, unsigned long expires) ...@@ -702,10 +703,32 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
if (timer->expires == expires && timer_pending(timer)) if (timer->expires == expires && timer_pending(timer))
return 1; return 1;
return __mod_timer(timer, expires, false); return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
} }
EXPORT_SYMBOL(mod_timer); EXPORT_SYMBOL(mod_timer);
/**
* mod_timer_pinned - modify a timer's timeout
* @timer: the timer to be modified
* @expires: new timeout in jiffies
*
* mod_timer_pinned() is a way to update the expire field of an
* active timer (if the timer is inactive it will be activated)
* and not allow the timer to be migrated to a different CPU.
*
* mod_timer_pinned(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
*/
int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
{
if (timer->expires == expires && timer_pending(timer))
return 1;
return __mod_timer(timer, expires, false, TIMER_PINNED);
}
EXPORT_SYMBOL(mod_timer_pinned);
/** /**
* add_timer - start a timer * add_timer - start a timer
* @timer: the timer to be added * @timer: the timer to be added
...@@ -1356,7 +1379,7 @@ signed long __sched schedule_timeout(signed long timeout) ...@@ -1356,7 +1379,7 @@ signed long __sched schedule_timeout(signed long timeout)
expire = timeout + jiffies; expire = timeout + jiffies;
setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
__mod_timer(&timer, expire, false); __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
schedule(); schedule();
del_singleshot_timer_sync(&timer); del_singleshot_timer_sync(&timer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment