Commit 303e967ff90a9d19ad3f8c9028ccbfa7f408fbb3
Committed by
Linus Torvalds
1 parent
3c8aa39d7c
Exists in
master
and in
4 other branches
[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>
Showing 2 changed files with 67 additions and 9 deletions Side-by-side Diff
include/linux/hrtimer.h
... | ... | @@ -40,6 +40,34 @@ |
40 | 40 | HRTIMER_RESTART, /* Timer must be restarted */ |
41 | 41 | }; |
42 | 42 | |
43 | +/* | |
44 | + * Bit values to track state of the timer | |
45 | + * | |
46 | + * Possible states: | |
47 | + * | |
48 | + * 0x00 inactive | |
49 | + * 0x01 enqueued into rbtree | |
50 | + * 0x02 callback function running | |
51 | + * 0x03 callback function running and enqueued | |
52 | + * (was requeued on another CPU) | |
53 | + * | |
54 | + * The "callback function running and enqueued" status is only possible on | |
55 | + * SMP. It happens for example when a posix timer expired and the callback | |
56 | + * queued a signal. Between dropping the lock which protects the posix timer | |
57 | + * and reacquiring the base lock of the hrtimer, another CPU can deliver the | |
58 | + * signal and rearm the timer. We have to preserve the callback running state, | |
59 | + * as otherwise the timer could be removed before the softirq code finishes the | |
60 | + * the handling of the timer. | |
61 | + * | |
62 | + * The HRTIMER_STATE_ENQUEUE bit is always or'ed to the current state to | |
63 | + * preserve the HRTIMER_STATE_CALLBACK bit in the above scenario. | |
64 | + * | |
65 | + * All state transitions are protected by cpu_base->lock. | |
66 | + */ | |
67 | +#define HRTIMER_STATE_INACTIVE 0x00 | |
68 | +#define HRTIMER_STATE_ENQUEUED 0x01 | |
69 | +#define HRTIMER_STATE_CALLBACK 0x02 | |
70 | + | |
43 | 71 | /** |
44 | 72 | * struct hrtimer - the basic hrtimer structure |
45 | 73 | * @node: red black tree node for time ordered insertion |
... | ... | @@ -48,6 +76,7 @@ |
48 | 76 | * which the timer is based. |
49 | 77 | * @function: timer expiry callback function |
50 | 78 | * @base: pointer to the timer base (per cpu and per clock) |
79 | + * @state: state information (See bit values above) | |
51 | 80 | * |
52 | 81 | * The hrtimer structure must be initialized by init_hrtimer_#CLOCKTYPE() |
53 | 82 | */ |
... | ... | @@ -56,6 +85,7 @@ |
56 | 85 | ktime_t expires; |
57 | 86 | enum hrtimer_restart (*function)(struct hrtimer *); |
58 | 87 | struct hrtimer_clock_base *base; |
88 | + unsigned long state; | |
59 | 89 | }; |
60 | 90 | |
61 | 91 | /** |
62 | 92 | |
... | ... | @@ -141,9 +171,13 @@ |
141 | 171 | extern ktime_t hrtimer_get_next_event(void); |
142 | 172 | #endif |
143 | 173 | |
174 | +/* | |
175 | + * A timer is active, when it is enqueued into the rbtree or the callback | |
176 | + * function is running. | |
177 | + */ | |
144 | 178 | static inline int hrtimer_active(const struct hrtimer *timer) |
145 | 179 | { |
146 | - return rb_parent(&timer->node) != &timer->node; | |
180 | + return timer->state != HRTIMER_STATE_INACTIVE; | |
147 | 181 | } |
148 | 182 | |
149 | 183 | /* Forward a hrtimer so it expires after now: */ |
kernel/hrtimer.c
... | ... | @@ -150,6 +150,23 @@ |
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 | 170 | * Functions and macros which are different for UP/SMP systems are kept in a |
154 | 171 | * single place |
155 | 172 | */ |
... | ... | @@ -390,6 +407,11 @@ |
390 | 407 | */ |
391 | 408 | rb_link_node(&timer->node, parent, link); |
392 | 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 | 416 | if (!base->first || timer->expires.tv64 < |
395 | 417 | rb_entry(base->first, struct hrtimer, node)->expires.tv64) |
... | ... | @@ -402,7 +424,8 @@ |
402 | 424 | * Caller must hold the base lock. |
403 | 425 | */ |
404 | 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 | 431 | * Remove the timer from the rbtree and replace the |
... | ... | @@ -411,7 +434,7 @@ |
411 | 434 | if (base->first == &timer->node) |
412 | 435 | base->first = rb_next(&timer->node); |
413 | 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 @@ |
420 | 443 | static inline int |
421 | 444 | remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) |
422 | 445 | { |
423 | - if (hrtimer_active(timer)) { | |
424 | - __remove_hrtimer(timer, base); | |
446 | + if (hrtimer_is_queued(timer)) { | |
447 | + __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE); | |
425 | 448 | return 1; |
426 | 449 | } |
427 | 450 | return 0; |
... | ... | @@ -493,7 +516,7 @@ |
493 | 516 | |
494 | 517 | base = lock_hrtimer_base(timer, &flags); |
495 | 518 | |
496 | - if (base->cpu_base->curr_timer != timer) | |
519 | + if (!hrtimer_callback_running(timer)) | |
497 | 520 | ret = remove_hrtimer(timer, base); |
498 | 521 | |
499 | 522 | unlock_hrtimer_base(timer, &flags); |
... | ... | @@ -598,7 +621,6 @@ |
598 | 621 | clock_id = CLOCK_MONOTONIC; |
599 | 622 | |
600 | 623 | timer->base = &cpu_base->clock_base[clock_id]; |
601 | - rb_set_parent(&timer->node, &timer->node); | |
602 | 624 | } |
603 | 625 | EXPORT_SYMBOL_GPL(hrtimer_init); |
604 | 626 | |
605 | 627 | |
... | ... | @@ -649,13 +671,14 @@ |
649 | 671 | |
650 | 672 | fn = timer->function; |
651 | 673 | set_curr_timer(cpu_base, timer); |
652 | - __remove_hrtimer(timer, base); | |
674 | + __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK); | |
653 | 675 | spin_unlock_irq(&cpu_base->lock); |
654 | 676 | |
655 | 677 | restart = fn(timer); |
656 | 678 | |
657 | 679 | spin_lock_irq(&cpu_base->lock); |
658 | 680 | |
681 | + timer->state &= ~HRTIMER_STATE_CALLBACK; | |
659 | 682 | if (restart != HRTIMER_NORESTART) { |
660 | 683 | BUG_ON(hrtimer_active(timer)); |
661 | 684 | enqueue_hrtimer(timer, base); |
... | ... | @@ -826,7 +849,8 @@ |
826 | 849 | |
827 | 850 | while ((node = rb_first(&old_base->active))) { |
828 | 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 | 854 | timer->base = new_base; |
831 | 855 | enqueue_hrtimer(timer, new_base); |
832 | 856 | } |