aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/hrtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r--kernel/hrtimer.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 89a9f535b4ce..fee18b27252f 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -150,6 +150,23 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
150} 150}
151 151
152/* 152/*
153 * Helper function to check, whether the timer is on one of the queues
154 */
155static inline int hrtimer_is_queued(struct hrtimer *timer)
156{
157 return timer->state & HRTIMER_STATE_ENQUEUED;
158}
159
160/*
161 * Helper function to check, whether the timer is running the callback
162 * function
163 */
164static inline int hrtimer_callback_running(struct hrtimer *timer)
165{
166 return timer->state & HRTIMER_STATE_CALLBACK;
167}
168
169/*
153 * Functions and macros which are different for UP/SMP systems are kept in a 170 * Functions and macros which are different for UP/SMP systems are kept in a
154 * single place 171 * single place
155 */ 172 */
@@ -390,6 +407,11 @@ static void enqueue_hrtimer(struct hrtimer *timer,
390 */ 407 */
391 rb_link_node(&timer->node, parent, link); 408 rb_link_node(&timer->node, parent, link);
392 rb_insert_color(&timer->node, &base->active); 409 rb_insert_color(&timer->node, &base->active);
410 /*
411 * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the
412 * state of a possibly running callback.
413 */
414 timer->state |= HRTIMER_STATE_ENQUEUED;
393 415
394 if (!base->first || timer->expires.tv64 < 416 if (!base->first || timer->expires.tv64 <
395 rb_entry(base->first, struct hrtimer, node)->expires.tv64) 417 rb_entry(base->first, struct hrtimer, node)->expires.tv64)
@@ -402,7 +424,8 @@ static void enqueue_hrtimer(struct hrtimer *timer,
402 * Caller must hold the base lock. 424 * Caller must hold the base lock.
403 */ 425 */
404static void __remove_hrtimer(struct hrtimer *timer, 426static void __remove_hrtimer(struct hrtimer *timer,
405 struct hrtimer_clock_base *base) 427 struct hrtimer_clock_base *base,
428 unsigned long newstate)
406{ 429{
407 /* 430 /*
408 * Remove the timer from the rbtree and replace the 431 * Remove the timer from the rbtree and replace the
@@ -411,7 +434,7 @@ static void __remove_hrtimer(struct hrtimer *timer,
411 if (base->first == &timer->node) 434 if (base->first == &timer->node)
412 base->first = rb_next(&timer->node); 435 base->first = rb_next(&timer->node);
413 rb_erase(&timer->node, &base->active); 436 rb_erase(&timer->node, &base->active);
414 rb_set_parent(&timer->node, &timer->node); 437 timer->state = newstate;
415} 438}
416 439
417/* 440/*
@@ -420,8 +443,8 @@ static void __remove_hrtimer(struct hrtimer *timer,
420static inline int 443static inline int
421remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) 444remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base)
422{ 445{
423 if (hrtimer_active(timer)) { 446 if (hrtimer_is_queued(timer)) {
424 __remove_hrtimer(timer, base); 447 __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE);
425 return 1; 448 return 1;
426 } 449 }
427 return 0; 450 return 0;
@@ -493,7 +516,7 @@ int hrtimer_try_to_cancel(struct hrtimer *timer)
493 516
494 base = lock_hrtimer_base(timer, &flags); 517 base = lock_hrtimer_base(timer, &flags);
495 518
496 if (base->cpu_base->curr_timer != timer) 519 if (!hrtimer_callback_running(timer))
497 ret = remove_hrtimer(timer, base); 520 ret = remove_hrtimer(timer, base);
498 521
499 unlock_hrtimer_base(timer, &flags); 522 unlock_hrtimer_base(timer, &flags);
@@ -598,7 +621,6 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
598 clock_id = CLOCK_MONOTONIC; 621 clock_id = CLOCK_MONOTONIC;
599 622
600 timer->base = &cpu_base->clock_base[clock_id]; 623 timer->base = &cpu_base->clock_base[clock_id];
601 rb_set_parent(&timer->node, &timer->node);
602} 624}
603EXPORT_SYMBOL_GPL(hrtimer_init); 625EXPORT_SYMBOL_GPL(hrtimer_init);
604 626
@@ -649,13 +671,14 @@ static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base,
649 671
650 fn = timer->function; 672 fn = timer->function;
651 set_curr_timer(cpu_base, timer); 673 set_curr_timer(cpu_base, timer);
652 __remove_hrtimer(timer, base); 674 __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK);
653 spin_unlock_irq(&cpu_base->lock); 675 spin_unlock_irq(&cpu_base->lock);
654 676
655 restart = fn(timer); 677 restart = fn(timer);
656 678
657 spin_lock_irq(&cpu_base->lock); 679 spin_lock_irq(&cpu_base->lock);
658 680
681 timer->state &= ~HRTIMER_STATE_CALLBACK;
659 if (restart != HRTIMER_NORESTART) { 682 if (restart != HRTIMER_NORESTART) {
660 BUG_ON(hrtimer_active(timer)); 683 BUG_ON(hrtimer_active(timer));
661 enqueue_hrtimer(timer, base); 684 enqueue_hrtimer(timer, base);
@@ -826,7 +849,8 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
826 849
827 while ((node = rb_first(&old_base->active))) { 850 while ((node = rb_first(&old_base->active))) {
828 timer = rb_entry(node, struct hrtimer, node); 851 timer = rb_entry(node, struct hrtimer, node);
829 __remove_hrtimer(timer, old_base); 852 BUG_ON(timer->state & HRTIMER_STATE_CALLBACK);
853 __remove_hrtimer(timer, old_base, HRTIMER_STATE_INACTIVE);
830 timer->base = new_base; 854 timer->base = new_base;
831 enqueue_hrtimer(timer, new_base); 855 enqueue_hrtimer(timer, new_base);
832 } 856 }