diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-02-16 04:27:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:58 -0500 |
commit | 303e967ff90a9d19ad3f8c9028ccbfa7f408fbb3 (patch) | |
tree | cd8c057e98b57896ffbbe4d98a4264393a652204 /kernel/hrtimer.c | |
parent | 3c8aa39d7c445ae2612b6b626f76f077e7a7ab0d (diff) |
[PATCH] hrtimers; add state tracking
Reintroduce ktimers feature "optimized away" by the ktimers review process:
multiple hrtimer states to enable the running of hrtimers without holding the
cpu-base-lock.
(The "optimized" rbtree hack carried only 2 states worth of information and we
need 4 for high resolution timers and dynamic ticks.)
No functional changes.
Build-fixes-from: Andrew Morton <akpm@osdl.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: Roman Zippel <zippel@linux-m68k.org>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r-- | kernel/hrtimer.c | 40 |
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 | */ | ||
155 | static 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 | */ | ||
164 | static 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 | */ |
404 | static void __remove_hrtimer(struct hrtimer *timer, | 426 | static 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, | |||
420 | static inline int | 443 | static inline int |
421 | remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) | 444 | remove_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 | } |
603 | EXPORT_SYMBOL_GPL(hrtimer_init); | 625 | EXPORT_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 | } |