diff options
-rw-r--r-- | include/linux/timer.h | 4 | ||||
-rw-r--r-- | kernel/timer.c | 53 |
2 files changed, 36 insertions, 21 deletions
diff --git a/include/linux/timer.h b/include/linux/timer.h index 2e78fedfc069..221f81ac2002 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h | |||
@@ -76,9 +76,11 @@ static inline void add_timer(struct timer_list * timer) | |||
76 | } | 76 | } |
77 | 77 | ||
78 | #ifdef CONFIG_SMP | 78 | #ifdef CONFIG_SMP |
79 | extern int try_to_del_timer_sync(struct timer_list *timer); | ||
79 | extern int del_timer_sync(struct timer_list *timer); | 80 | extern int del_timer_sync(struct timer_list *timer); |
80 | #else | 81 | #else |
81 | # define del_timer_sync(t) del_timer(t) | 82 | # define try_to_del_timer_sync(t) del_timer(t) |
83 | # define del_timer_sync(t) del_timer(t) | ||
82 | #endif | 84 | #endif |
83 | 85 | ||
84 | #define del_singleshot_timer_sync(t) del_timer_sync(t) | 86 | #define del_singleshot_timer_sync(t) del_timer_sync(t) |
diff --git a/kernel/timer.c b/kernel/timer.c index 8aadc62efd65..1f986c16d89f 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -365,6 +365,34 @@ int del_timer(struct timer_list *timer) | |||
365 | EXPORT_SYMBOL(del_timer); | 365 | EXPORT_SYMBOL(del_timer); |
366 | 366 | ||
367 | #ifdef CONFIG_SMP | 367 | #ifdef CONFIG_SMP |
368 | /* | ||
369 | * This function tries to deactivate a timer. Upon successful (ret >= 0) | ||
370 | * exit the timer is not queued and the handler is not running on any CPU. | ||
371 | * | ||
372 | * It must not be called from interrupt contexts. | ||
373 | */ | ||
374 | int try_to_del_timer_sync(struct timer_list *timer) | ||
375 | { | ||
376 | timer_base_t *base; | ||
377 | unsigned long flags; | ||
378 | int ret = -1; | ||
379 | |||
380 | base = lock_timer_base(timer, &flags); | ||
381 | |||
382 | if (base->running_timer == timer) | ||
383 | goto out; | ||
384 | |||
385 | ret = 0; | ||
386 | if (timer_pending(timer)) { | ||
387 | detach_timer(timer, 1); | ||
388 | ret = 1; | ||
389 | } | ||
390 | out: | ||
391 | spin_unlock_irqrestore(&base->lock, flags); | ||
392 | |||
393 | return ret; | ||
394 | } | ||
395 | |||
368 | /*** | 396 | /*** |
369 | * del_timer_sync - deactivate a timer and wait for the handler to finish. | 397 | * del_timer_sync - deactivate a timer and wait for the handler to finish. |
370 | * @timer: the timer to be deactivated | 398 | * @timer: the timer to be deactivated |
@@ -384,28 +412,13 @@ EXPORT_SYMBOL(del_timer); | |||
384 | */ | 412 | */ |
385 | int del_timer_sync(struct timer_list *timer) | 413 | int del_timer_sync(struct timer_list *timer) |
386 | { | 414 | { |
387 | timer_base_t *base; | ||
388 | unsigned long flags; | ||
389 | int ret = -1; | ||
390 | |||
391 | check_timer(timer); | 415 | check_timer(timer); |
392 | 416 | ||
393 | do { | 417 | for (;;) { |
394 | base = lock_timer_base(timer, &flags); | 418 | int ret = try_to_del_timer_sync(timer); |
395 | 419 | if (ret >= 0) | |
396 | if (base->running_timer == timer) | 420 | return ret; |
397 | goto unlock; | 421 | } |
398 | |||
399 | ret = 0; | ||
400 | if (timer_pending(timer)) { | ||
401 | detach_timer(timer, 1); | ||
402 | ret = 1; | ||
403 | } | ||
404 | unlock: | ||
405 | spin_unlock_irqrestore(&base->lock, flags); | ||
406 | } while (ret < 0); | ||
407 | |||
408 | return ret; | ||
409 | } | 422 | } |
410 | 423 | ||
411 | EXPORT_SYMBOL(del_timer_sync); | 424 | EXPORT_SYMBOL(del_timer_sync); |