Loading include/linux/hrtimer.h +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ enum hrtimer_restart { * * 0x00 inactive * 0x01 enqueued into rbtree * 0x02 timer is pinned to a cpu * * The callback state is not part of the timer->state because clearing it would * mean touching the timer after the callback, this makes it impossible to free Loading @@ -92,6 +93,8 @@ enum hrtimer_restart { */ #define HRTIMER_STATE_INACTIVE 0x00 #define HRTIMER_STATE_ENQUEUED 0x01 #define HRTIMER_PINNED_SHIFT 1 #define HRTIMER_STATE_PINNED (1 << HRTIMER_PINNED_SHIFT) /** * struct hrtimer - the basic hrtimer structure Loading Loading @@ -371,6 +374,9 @@ static inline void hrtimer_cancel_wait_running(struct hrtimer *timer) /* Exported timer functions: */ /* To be used from cpusets, only */ extern void hrtimer_quiesce_cpu(void *cpup); /* Initialize timers: */ extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock, enum hrtimer_mode mode); Loading kernel/time/hrtimer.c +59 −16 Original line number Diff line number Diff line Loading @@ -966,7 +966,7 @@ static int enqueue_hrtimer(struct hrtimer *timer, base->cpu_base->active_bases |= 1 << base->index; timer->state = HRTIMER_STATE_ENQUEUED; timer->state |= HRTIMER_STATE_ENQUEUED; return timerqueue_add(&base->active, &timer->node); } Loading @@ -986,11 +986,9 @@ static void __remove_hrtimer(struct hrtimer *timer, u8 newstate, int reprogram) { struct hrtimer_cpu_base *cpu_base = base->cpu_base; u8 state = timer->state; timer->state = newstate; if (!(state & HRTIMER_STATE_ENQUEUED)) return; if (!(timer->state & HRTIMER_STATE_ENQUEUED)) goto out; if (!timerqueue_del(&base->active, &timer->node)) cpu_base->active_bases &= ~(1 << base->index); Loading @@ -1005,6 +1003,13 @@ static void __remove_hrtimer(struct hrtimer *timer, */ if (reprogram && timer == cpu_base->next_timer) hrtimer_force_reprogram(cpu_base, 1); out: /* * We need to preserve PINNED state here, otherwise we may end up * migrating pinned hrtimers as well. */ timer->state = newstate | (timer->state & HRTIMER_STATE_PINNED); } /* Loading Loading @@ -1032,6 +1037,7 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool rest state = HRTIMER_STATE_INACTIVE; __remove_hrtimer(timer, base, state, reprogram); timer->state &= ~HRTIMER_STATE_PINNED; return 1; } return 0; Loading Loading @@ -1097,6 +1103,10 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, /* Switch the timer base, if necessary: */ new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); /* Update pinned state */ timer->state &= ~HRTIMER_STATE_PINNED; timer->state |= (!!(mode & HRTIMER_MODE_PINNED)) << HRTIMER_PINNED_SHIFT; return enqueue_hrtimer(timer, new_base, mode); } Loading Loading @@ -2004,13 +2014,17 @@ int hrtimers_prepare_cpu(unsigned int cpu) return 0; } #ifdef CONFIG_HOTPLUG_CPU #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_CPUSETS) static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, struct hrtimer_clock_base *new_base) struct hrtimer_clock_base *new_base, bool remove_pinned) { struct hrtimer *timer; struct timerqueue_node *node; struct timerqueue_head pinned; int is_pinned; timerqueue_init_head(&pinned); while ((node = timerqueue_getnext(&old_base->active))) { timer = container_of(node, struct hrtimer, node); Loading @@ -2023,6 +2037,13 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, * under us on another CPU */ __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0); is_pinned = timer->state & HRTIMER_STATE_PINNED; if (!remove_pinned && is_pinned) { timerqueue_add(&pinned, &timer->node); continue; } timer->base = new_base; /* * Enqueue the timers on the new cpu. This does not Loading @@ -2034,23 +2055,29 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, */ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); } /* Re-queue pinned timers for non-hotplug usecase */ while ((node = timerqueue_getnext(&pinned))) { timer = container_of(node, struct hrtimer, node); timerqueue_del(&pinned, &timer->node); enqueue_hrtimer(timer, old_base, HRTIMER_MODE_ABS); } } int hrtimers_dead_cpu(unsigned int scpu) static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned) { struct hrtimer_cpu_base *old_base, *new_base; unsigned long flags; int i; BUG_ON(cpu_online(scpu)); tick_cancel_sched_timer(scpu); /* * this BH disable ensures that raise_softirq_irqoff() does * not wakeup ksoftirqd (and acquire the pi-lock) while * holding the cpu_base lock */ local_bh_disable(); local_irq_disable(); local_irq_save(flags); old_base = &per_cpu(hrtimer_bases, scpu); new_base = this_cpu_ptr(&hrtimer_bases); /* Loading @@ -2062,7 +2089,7 @@ int hrtimers_dead_cpu(unsigned int scpu) for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { migrate_hrtimer_list(&old_base->clock_base[i], &new_base->clock_base[i]); &new_base->clock_base[i], remove_pinned); } /* Loading @@ -2076,13 +2103,29 @@ int hrtimers_dead_cpu(unsigned int scpu) /* Check, if we got expired work to do */ __hrtimer_peek_ahead_timers(); local_irq_enable(); local_irq_restore(flags); local_bh_enable(); return 0; } #endif /* CONFIG_HOTPLUG_CPU || CONFIG_CPUSETS */ #ifdef CONFIG_HOTPLUG_CPU int hrtimers_dead_cpu(unsigned int scpu) { BUG_ON(cpu_online(scpu)); tick_cancel_sched_timer(scpu); __migrate_hrtimers(scpu, true); return 0; } #endif /* CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_CPUSETS void hrtimer_quiesce_cpu(void *cpup) { __migrate_hrtimers(*(int *)cpup, false); } #endif /* CONFIG_CPUSETS */ void __init hrtimers_init(void) { hrtimers_prepare_cpu(smp_processor_id()); Loading Loading
include/linux/hrtimer.h +6 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ enum hrtimer_restart { * * 0x00 inactive * 0x01 enqueued into rbtree * 0x02 timer is pinned to a cpu * * The callback state is not part of the timer->state because clearing it would * mean touching the timer after the callback, this makes it impossible to free Loading @@ -92,6 +93,8 @@ enum hrtimer_restart { */ #define HRTIMER_STATE_INACTIVE 0x00 #define HRTIMER_STATE_ENQUEUED 0x01 #define HRTIMER_PINNED_SHIFT 1 #define HRTIMER_STATE_PINNED (1 << HRTIMER_PINNED_SHIFT) /** * struct hrtimer - the basic hrtimer structure Loading Loading @@ -371,6 +374,9 @@ static inline void hrtimer_cancel_wait_running(struct hrtimer *timer) /* Exported timer functions: */ /* To be used from cpusets, only */ extern void hrtimer_quiesce_cpu(void *cpup); /* Initialize timers: */ extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock, enum hrtimer_mode mode); Loading
kernel/time/hrtimer.c +59 −16 Original line number Diff line number Diff line Loading @@ -966,7 +966,7 @@ static int enqueue_hrtimer(struct hrtimer *timer, base->cpu_base->active_bases |= 1 << base->index; timer->state = HRTIMER_STATE_ENQUEUED; timer->state |= HRTIMER_STATE_ENQUEUED; return timerqueue_add(&base->active, &timer->node); } Loading @@ -986,11 +986,9 @@ static void __remove_hrtimer(struct hrtimer *timer, u8 newstate, int reprogram) { struct hrtimer_cpu_base *cpu_base = base->cpu_base; u8 state = timer->state; timer->state = newstate; if (!(state & HRTIMER_STATE_ENQUEUED)) return; if (!(timer->state & HRTIMER_STATE_ENQUEUED)) goto out; if (!timerqueue_del(&base->active, &timer->node)) cpu_base->active_bases &= ~(1 << base->index); Loading @@ -1005,6 +1003,13 @@ static void __remove_hrtimer(struct hrtimer *timer, */ if (reprogram && timer == cpu_base->next_timer) hrtimer_force_reprogram(cpu_base, 1); out: /* * We need to preserve PINNED state here, otherwise we may end up * migrating pinned hrtimers as well. */ timer->state = newstate | (timer->state & HRTIMER_STATE_PINNED); } /* Loading Loading @@ -1032,6 +1037,7 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool rest state = HRTIMER_STATE_INACTIVE; __remove_hrtimer(timer, base, state, reprogram); timer->state &= ~HRTIMER_STATE_PINNED; return 1; } return 0; Loading Loading @@ -1097,6 +1103,10 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, /* Switch the timer base, if necessary: */ new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); /* Update pinned state */ timer->state &= ~HRTIMER_STATE_PINNED; timer->state |= (!!(mode & HRTIMER_MODE_PINNED)) << HRTIMER_PINNED_SHIFT; return enqueue_hrtimer(timer, new_base, mode); } Loading Loading @@ -2004,13 +2014,17 @@ int hrtimers_prepare_cpu(unsigned int cpu) return 0; } #ifdef CONFIG_HOTPLUG_CPU #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_CPUSETS) static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, struct hrtimer_clock_base *new_base) struct hrtimer_clock_base *new_base, bool remove_pinned) { struct hrtimer *timer; struct timerqueue_node *node; struct timerqueue_head pinned; int is_pinned; timerqueue_init_head(&pinned); while ((node = timerqueue_getnext(&old_base->active))) { timer = container_of(node, struct hrtimer, node); Loading @@ -2023,6 +2037,13 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, * under us on another CPU */ __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0); is_pinned = timer->state & HRTIMER_STATE_PINNED; if (!remove_pinned && is_pinned) { timerqueue_add(&pinned, &timer->node); continue; } timer->base = new_base; /* * Enqueue the timers on the new cpu. This does not Loading @@ -2034,23 +2055,29 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, */ enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS); } /* Re-queue pinned timers for non-hotplug usecase */ while ((node = timerqueue_getnext(&pinned))) { timer = container_of(node, struct hrtimer, node); timerqueue_del(&pinned, &timer->node); enqueue_hrtimer(timer, old_base, HRTIMER_MODE_ABS); } } int hrtimers_dead_cpu(unsigned int scpu) static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned) { struct hrtimer_cpu_base *old_base, *new_base; unsigned long flags; int i; BUG_ON(cpu_online(scpu)); tick_cancel_sched_timer(scpu); /* * this BH disable ensures that raise_softirq_irqoff() does * not wakeup ksoftirqd (and acquire the pi-lock) while * holding the cpu_base lock */ local_bh_disable(); local_irq_disable(); local_irq_save(flags); old_base = &per_cpu(hrtimer_bases, scpu); new_base = this_cpu_ptr(&hrtimer_bases); /* Loading @@ -2062,7 +2089,7 @@ int hrtimers_dead_cpu(unsigned int scpu) for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { migrate_hrtimer_list(&old_base->clock_base[i], &new_base->clock_base[i]); &new_base->clock_base[i], remove_pinned); } /* Loading @@ -2076,13 +2103,29 @@ int hrtimers_dead_cpu(unsigned int scpu) /* Check, if we got expired work to do */ __hrtimer_peek_ahead_timers(); local_irq_enable(); local_irq_restore(flags); local_bh_enable(); return 0; } #endif /* CONFIG_HOTPLUG_CPU || CONFIG_CPUSETS */ #ifdef CONFIG_HOTPLUG_CPU int hrtimers_dead_cpu(unsigned int scpu) { BUG_ON(cpu_online(scpu)); tick_cancel_sched_timer(scpu); __migrate_hrtimers(scpu, true); return 0; } #endif /* CONFIG_HOTPLUG_CPU */ #ifdef CONFIG_CPUSETS void hrtimer_quiesce_cpu(void *cpup) { __migrate_hrtimers(*(int *)cpup, false); } #endif /* CONFIG_CPUSETS */ void __init hrtimers_init(void) { hrtimers_prepare_cpu(smp_processor_id()); Loading