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); |
