The patch titled hrtimers: state tracking has been added to the -mm tree. Its filename is hrtimers-state-tracking.patch See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this ------------------------------------------------------ Subject: hrtimers: state tracking From: Thomas Gleixner <tglx@xxxxxxxxxxxxx> 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.) Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Signed-off-by: Ingo Molnar <mingo@xxxxxxx> Cc: john stultz <johnstul@xxxxxxxxxx> Cc: Roman Zippel <zippel@xxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- include/linux/hrtimer.h | 36 +++++++++++++++++++++++++++++++++++- kernel/hrtimer.c | 21 ++++++++++++++------- 2 files changed, 49 insertions(+), 8 deletions(-) diff -puN include/linux/hrtimer.h~hrtimers-state-tracking include/linux/hrtimer.h --- a/include/linux/hrtimer.h~hrtimers-state-tracking +++ a/include/linux/hrtimer.h @@ -40,6 +40,34 @@ enum hrtimer_restart { HRTIMER_RESTART, /* Timer must be restarted */ }; +/* + * Bit values to track state of the timer + * + * Possible states: + * + * 0x00 inactive + * 0x01 enqueued into rbtree + * 0x02 callback function running + * 0x03 callback function running and enqueued + * (was requeued on another CPU) + * + * The "callback function running and enqueued" status is only possible on + * SMP. It happens for example when a posix timer expired and the callback + * queued a signal. Between dropping the lock which protects the posix timer + * and reacquiring the base lock of the hrtimer, another CPU can deliver the + * signal and rearm the timer. We have to preserve the callback running state, + * as otherwise the timer could be removed before the softirq code finishes the + * the handling of the timer. + * + * The HRTIMER_STATE_ENQUEUE bit is always or'ed to the current state to + * preserve the HRTIMER_STATE_CALLBACK bit in the above scenario. + * + * All state transitions are protected by cpu_base->lock. + */ +#define HRTIMER_STATE_INACTIVE 0x00 +#define HRTIMER_STATE_ENQUEUED 0x01 +#define HRTIMER_STATE_CALLBACK 0x02 + /** * struct hrtimer - the basic hrtimer structure * @node: red black tree node for time ordered insertion @@ -48,6 +76,7 @@ enum hrtimer_restart { * which the timer is based. * @function: timer expiry callback function * @base: pointer to the timer base (per cpu and per clock) + * @state: state information (See bit values above) * * The hrtimer structure must be initialized by init_hrtimer_#CLOCKTYPE() */ @@ -56,6 +85,7 @@ struct hrtimer { ktime_t expires; enum hrtimer_restart (*function)(struct hrtimer *); struct hrtimer_clock_base *base; + unsigned long state; }; /** @@ -141,9 +171,13 @@ extern int hrtimer_get_res(const clockid extern ktime_t hrtimer_get_next_event(void); #endif +/* + * A timer is active, when it is enqueued into the rbtree or the callback + * function is running. + */ static inline int hrtimer_active(const struct hrtimer *timer) { - return rb_parent(&timer->node) != &timer->node; + return timer->state != HRTIMER_STATE_INACTIVE; } /* Forward a hrtimer so it expires after now: */ diff -puN kernel/hrtimer.c~hrtimers-state-tracking kernel/hrtimer.c --- a/kernel/hrtimer.c~hrtimers-state-tracking +++ a/kernel/hrtimer.c @@ -385,6 +385,11 @@ static void enqueue_hrtimer(struct hrtim */ rb_link_node(&timer->node, parent, link); rb_insert_color(&timer->node, &base->active); + /* + * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the + * state of a possibly running callback. + */ + timer->state |= HRTIMER_STATE_ENQUEUED; if (!base->first || timer->expires.tv64 < rb_entry(base->first, struct hrtimer, node)->expires.tv64) @@ -397,7 +402,8 @@ static void enqueue_hrtimer(struct hrtim * Caller must hold the base lock. */ static void __remove_hrtimer(struct hrtimer *timer, - struct hrtimer_clock_base *base) + struct hrtimer_clock_base *base, + unsigned long newstate) { /* * Remove the timer from the rbtree and replace the @@ -406,7 +412,7 @@ static void __remove_hrtimer(struct hrti if (base->first == &timer->node) base->first = rb_next(&timer->node); rb_erase(&timer->node, &base->active); - rb_set_parent(&timer->node, &timer->node); + timer->state = newstate; } /* @@ -416,7 +422,7 @@ static inline int remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) { if (hrtimer_active(timer)) { - __remove_hrtimer(timer, base); + __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE); return 1; } return 0; @@ -488,7 +494,7 @@ int hrtimer_try_to_cancel(struct hrtimer base = lock_hrtimer_base(timer, &flags); - if (base->cpu_base->curr_timer != timer) + if (!(timer->state & HRTIMER_STATE_CALLBACK)) ret = remove_hrtimer(timer, base); unlock_hrtimer_base(timer, &flags); @@ -593,7 +599,6 @@ void hrtimer_init(struct hrtimer *timer, clock_id = CLOCK_MONOTONIC; timer->base = &cpu_base->clock_base[clock_id]; - rb_set_parent(&timer->node, &timer->node); } EXPORT_SYMBOL_GPL(hrtimer_init); @@ -644,13 +649,14 @@ static inline void run_hrtimer_queue(str fn = timer->function; set_curr_timer(cpu_base, timer); - __remove_hrtimer(timer, base); + __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK); spin_unlock_irq(&cpu_base->lock); restart = fn(timer); spin_lock_irq(&cpu_base->lock); + timer->state &= ~HRTIMER_STATE_CALLBACK; if (restart != HRTIMER_NORESTART) { BUG_ON(hrtimer_active(timer)); enqueue_hrtimer(timer, base); @@ -821,7 +827,8 @@ static void migrate_hrtimer_list(struct while ((node = rb_first(&old_base->active))) { timer = rb_entry(node, struct hrtimer, node); - __remove_hrtimer(timer, old_base); + BUG_ON(timer->state & HRTIMER_CALLBACK); + __remove_hrtimer(timer, old_base, HRTIMER_INACTIVE); timer->base = new_base; enqueue_hrtimer(timer, new_base); } _ Patches currently in -mm which might be from tglx@xxxxxxxxxxxxx are origin.patch genirq-convert-the-x86_64-architecture-to-irq-chips.patch genirq-convert-the-i386-architecture-to-irq-chips.patch genirq-irq-convert-the-move_irq-flag-from-a-32bit-word-to-a-single-bit.patch genirq-irq-add-moved_masked_irq.patch genirq-x86_64-irq-reenable-migrating-irqs-to-other-cpus.patch genirq-msi-simplify-msi-enable-and-disable.patch genirq-msi-make-the-msi-boolean-tests-return-either-0-or-1.patch genirq-msi-implement-helper-functions-read_msi_msg-and-write_msi_msg.patch genirq-msi-refactor-the-msi_ops.patch genirq-msi-simplify-the-msi-irq-limit-policy.patch genirq-irq-add-a-dynamic-irq-creation-api.patch genirq-ia64-irq-dynamic-irq-support.patch genirq-i386-irq-dynamic-irq-support.patch genirq-x86_64-irq-dynamic-irq-support.patch genirq-msi-make-the-msi-code-irq-based-and-not-vector-based.patch genirq-x86_64-irq-move-msi-message-composition-into-io_apicc.patch genirq-i386-irq-move-msi-message-composition-into-io_apicc.patch genirq-msi-only-build-msi-apicc-on-ia64.patch genirq-x86_64-irq-remove-the-msi-assumption-that-irq-==-vector.patch genirq-i386-irq-remove-the-msi-assumption-that-irq-==-vector.patch genirq-irq-remove-msi-hacks.patch genirq-irq-generalize-the-check-for-hardirq_bits.patch genirq-x86_64-irq-make-the-external-irq-handlers-report-their-vector-not-the-irq-number.patch genirq-x86_64-irq-make-vector_irq-per-cpu.patch genirq-x86_64-irq-make-vector_irq-per-cpu-warning-fix.patch genirq-x86_64-irq-kill-gsi_irq_sharing.patch genirq-x86_64-irq-kill-irq-compression.patch msi-simplify-msi-sanity-checks-by-adding-with-generic-irq-code.patch msi-only-use-a-single-irq_chip-for-msi-interrupts.patch msi-refactor-and-move-the-msi-irq_chip-into-the-arch-code.patch msi-move-the-ia64-code-into-arch-ia64.patch htirq-tidy-up-the-htirq-code.patch genirq-clean-up-irq-flow-type-naming.patch gtod-exponential-update_wall_time.patch gtod-persistent-clock-support-core.patch gtod-persistent-clock-support-i386.patch time-uninline-jiffiesh.patch time-fix-msecs_to_jiffies-bug.patch time-fix-timeout-overflow.patch cleanup-uninline-irq_enter-and-move-it-into-a.patch dynticks-extend-next_timer_interrupt-to-use-a.patch hrtimers-namespace-and-enum-cleanup.patch hrtimers-clean-up-locking.patch hrtimers-state-tracking.patch hrtimers-clean-up-callback-tracking.patch hrtimers-move-and-add-documentation.patch clockevents-core.patch clockevents-drivers-for-i386.patch high-res-timers-core.patch high-res-timers-core-fix.patch dynticks-core.patch dyntick-add-nohz-stats-to-proc-stat.patch dynticks-i386-arch-code.patch high-res-timers-dynticks-enable-i386-support.patch debugging-feature-timer-stats.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html