提交 c5f66e99 编写于 作者: T Tejun Heo 提交者: Thomas Gleixner

timer: Implement TIMER_IRQSAFE

Timer internals are protected with irq-safe locks but timer execution
isn't, so a timer being dequeued for execution and its execution
aren't atomic against IRQs.  This makes it impossible to wait for its
completion from IRQ handlers and difficult to shoot down a timer from
IRQ handlers.

This issue caused some issues for delayed_work interface.  Because
there's no way to reliably shoot down delayed_work->timer from IRQ
handlers, __cancel_delayed_work() can't share the logic to steal the
target delayed_work with cancel_delayed_work_sync(), and can only
steal delayed_works which are on queued on timer.  Similarly, the
pending mod_delayed_work() can't be used from IRQ handlers.

This patch adds a new timer flag TIMER_IRQSAFE, which makes the timer
to be executed without enabling IRQ after dequeueing such that its
dequeueing and execution are atomic against IRQ handlers.

This makes it safe to wait for the timer's completion from IRQ
handlers, for example, using del_timer_sync().  It can never be
executing on the local CPU and if executing on other CPUs it won't be
interrupted until done.

This will enable simplifying delayed_work cancel/mod interface.
Signed-off-by: NTejun Heo <tj@kernel.org>
Cc: torvalds@linux-foundation.org
Cc: peterz@infradead.org
Link: http://lkml.kernel.org/r/1344449428-24962-5-git-send-email-tj@kernel.orgSigned-off-by: NThomas Gleixner <tglx@linutronix.de>
上级 fc683995
...@@ -49,18 +49,26 @@ extern struct tvec_base boot_tvec_bases; ...@@ -49,18 +49,26 @@ extern struct tvec_base boot_tvec_bases;
#endif #endif
/* /*
* Note that all tvec_bases are 2 byte aligned and lower bit of * Note that all tvec_bases are at least 4 byte aligned and lower two bits
* base in timer_list is guaranteed to be zero. Use the LSB to * of base in timer_list is guaranteed to be zero. Use them for flags.
* indicate whether the timer is deferrable.
* *
* A deferrable timer will work normally when the system is busy, but * A deferrable timer will work normally when the system is busy, but
* will not cause a CPU to come out of idle just to service it; instead, * will not cause a CPU to come out of idle just to service it; instead,
* the timer will be serviced when the CPU eventually wakes up with a * the timer will be serviced when the CPU eventually wakes up with a
* subsequent non-deferrable timer. * subsequent non-deferrable timer.
*
* An irqsafe timer is executed with IRQ disabled and it's safe to wait for
* the completion of the running instance from IRQ handlers, for example,
* by calling del_timer_sync().
*
* Note: The irq disabled callback execution is a special case for
* workqueue locking issues. It's not meant for executing random crap
* with interrupts disabled. Abuse is monitored!
*/ */
#define TIMER_DEFERRABLE 0x1LU #define TIMER_DEFERRABLE 0x1LU
#define TIMER_IRQSAFE 0x2LU
#define TIMER_FLAG_MASK 0x1LU #define TIMER_FLAG_MASK 0x3LU
#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ #define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
.entry = { .prev = TIMER_ENTRY_STATIC }, \ .entry = { .prev = TIMER_ENTRY_STATIC }, \
......
...@@ -95,6 +95,11 @@ static inline unsigned int tbase_get_deferrable(struct tvec_base *base) ...@@ -95,6 +95,11 @@ static inline unsigned int tbase_get_deferrable(struct tvec_base *base)
return ((unsigned int)(unsigned long)base & TIMER_DEFERRABLE); return ((unsigned int)(unsigned long)base & TIMER_DEFERRABLE);
} }
static inline unsigned int tbase_get_irqsafe(struct tvec_base *base)
{
return ((unsigned int)(unsigned long)base & TIMER_IRQSAFE);
}
static inline struct tvec_base *tbase_get_base(struct tvec_base *base) static inline struct tvec_base *tbase_get_base(struct tvec_base *base)
{ {
return ((struct tvec_base *)((unsigned long)base & ~TIMER_FLAG_MASK)); return ((struct tvec_base *)((unsigned long)base & ~TIMER_FLAG_MASK));
...@@ -1002,14 +1007,14 @@ EXPORT_SYMBOL(try_to_del_timer_sync); ...@@ -1002,14 +1007,14 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
* *
* Synchronization rules: Callers must prevent restarting of the timer, * Synchronization rules: Callers must prevent restarting of the timer,
* otherwise this function is meaningless. It must not be called from * otherwise this function is meaningless. It must not be called from
* interrupt contexts. The caller must not hold locks which would prevent * interrupt contexts unless the timer is an irqsafe one. The caller must
* completion of the timer's handler. The timer's handler must not call * not hold locks which would prevent completion of the timer's
* add_timer_on(). Upon exit the timer is not queued and the handler is * handler. The timer's handler must not call add_timer_on(). Upon exit the
* not running on any CPU. * timer is not queued and the handler is not running on any CPU.
* *
* Note: You must not hold locks that are held in interrupt context * Note: For !irqsafe timers, you must not hold locks that are held in
* while calling this function. Even if the lock has nothing to do * interrupt context while calling this function. Even if the lock has
* with the timer in question. Here's why: * nothing to do with the timer in question. Here's why:
* *
* CPU0 CPU1 * CPU0 CPU1
* ---- ---- * ---- ----
...@@ -1046,7 +1051,7 @@ int del_timer_sync(struct timer_list *timer) ...@@ -1046,7 +1051,7 @@ int del_timer_sync(struct timer_list *timer)
* don't use it in hardirq context, because it * don't use it in hardirq context, because it
* could lead to deadlock. * could lead to deadlock.
*/ */
WARN_ON(in_irq()); WARN_ON(in_irq() && !tbase_get_irqsafe(timer->base));
for (;;) { for (;;) {
int ret = try_to_del_timer_sync(timer); int ret = try_to_del_timer_sync(timer);
if (ret >= 0) if (ret >= 0)
...@@ -1153,19 +1158,27 @@ static inline void __run_timers(struct tvec_base *base) ...@@ -1153,19 +1158,27 @@ static inline void __run_timers(struct tvec_base *base)
while (!list_empty(head)) { while (!list_empty(head)) {
void (*fn)(unsigned long); void (*fn)(unsigned long);
unsigned long data; unsigned long data;
bool irqsafe;
timer = list_first_entry(head, struct timer_list,entry); timer = list_first_entry(head, struct timer_list,entry);
fn = timer->function; fn = timer->function;
data = timer->data; data = timer->data;
irqsafe = tbase_get_irqsafe(timer->base);
timer_stats_account_timer(timer); timer_stats_account_timer(timer);
base->running_timer = timer; base->running_timer = timer;
detach_expired_timer(timer, base); detach_expired_timer(timer, base);
spin_unlock_irq(&base->lock); if (irqsafe) {
call_timer_fn(timer, fn, data); spin_unlock(&base->lock);
spin_lock_irq(&base->lock); call_timer_fn(timer, fn, data);
spin_lock(&base->lock);
} else {
spin_unlock_irq(&base->lock);
call_timer_fn(timer, fn, data);
spin_lock_irq(&base->lock);
}
} }
} }
base->running_timer = NULL; base->running_timer = NULL;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册