#include <linux/cpu.h>
#include <linux/export.h>
#include <linux/percpu.h>
#include <linux/hrtimer.h>
#include <linux/notifier.h>
#include <linux/syscalls.h>
#include <linux/interrupt.h>
#include <linux/tick.h>
#include <linux/err.h>
#include <linux/debugobjects.h>
#include <linux/sched/signal.h>
#include <linux/sched/sysctl.h>
#include <linux/sched/rt.h>
#include <linux/sched/deadline.h>
#include <linux/sched/nohz.h>
#include <linux/sched/debug.h>
#include <linux/sched/isolation.h>
#include <linux/timer.h>
#include <linux/freezer.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
#include <trace/events/timer.h>
#include "tick-internal.h"
#define HRTIMER_STATE_INACTIVE false
#define HRTIMER_STATE_ENQUEUED true
#define HIGH_RES_NSEC 1
#define MASK_SHIFT (HRTIMER_BASE_MONOTONIC_SOFT)
#define HRTIMER_ACTIVE_HARD ((1U << MASK_SHIFT) - 1)
#define HRTIMER_ACTIVE_SOFT (HRTIMER_ACTIVE_HARD << MASK_SHIFT)
#define HRTIMER_ACTIVE_ALL (HRTIMER_ACTIVE_SOFT | HRTIMER_ACTIVE_HARD)
static void retrigger_next_event(void *arg);
static ktime_t __hrtimer_cb_get_time(clockid_t clock_id);
#define BASE_INIT(idx, cid) \
[idx] = { .index = idx, .clockid = cid }
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
.lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
.clock_base = {
BASE_INIT(HRTIMER_BASE_MONOTONIC, CLOCK_MONOTONIC),
BASE_INIT(HRTIMER_BASE_REALTIME, CLOCK_REALTIME),
BASE_INIT(HRTIMER_BASE_BOOTTIME, CLOCK_BOOTTIME),
BASE_INIT(HRTIMER_BASE_TAI, CLOCK_TAI),
BASE_INIT(HRTIMER_BASE_MONOTONIC_SOFT, CLOCK_MONOTONIC),
BASE_INIT(HRTIMER_BASE_REALTIME_SOFT, CLOCK_REALTIME),
BASE_INIT(HRTIMER_BASE_BOOTTIME_SOFT, CLOCK_BOOTTIME),
BASE_INIT(HRTIMER_BASE_TAI_SOFT, CLOCK_TAI),
},
.csd = CSD_INIT(retrigger_next_event, NULL)
};
static inline bool hrtimer_base_is_online(struct hrtimer_cpu_base *base)
{
if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
return true;
else
return likely(base->online);
}
#ifdef CONFIG_HIGH_RES_TIMERS
DEFINE_STATIC_KEY_FALSE(hrtimer_highres_enabled_key);
static void hrtimer_hres_workfn(struct work_struct *work)
{
static_branch_enable(&hrtimer_highres_enabled_key);
}
static DECLARE_WORK(hrtimer_hres_work, hrtimer_hres_workfn);
static inline void hrtimer_schedule_hres_work(void)
{
if (!hrtimer_highres_enabled())
schedule_work(&hrtimer_hres_work);
}
#else
static inline void hrtimer_schedule_hres_work(void) { }
#endif
#ifdef CONFIG_SMP
static struct hrtimer_cpu_base migration_cpu_base = {
.clock_base = {
[0] = {
.cpu_base = &migration_cpu_base,
.seq = SEQCNT_RAW_SPINLOCK_ZERO(migration_cpu_base.seq,
&migration_cpu_base.lock),
},
},
};
#define migration_base migration_cpu_base.clock_base[0]
static struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
unsigned long *flags)
__acquires(&timer->base->lock)
{
for (;;) {
struct hrtimer_clock_base *base = READ_ONCE(timer->base);
if (likely(base != &migration_base)) {
raw_spin_lock_irqsave(&base->cpu_base->lock, *flags);
if (likely(base == timer->base))
return base;
raw_spin_unlock_irqrestore(&base->cpu_base->lock, *flags);
}
cpu_relax();
}
}
static bool hrtimer_suitable_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base,
struct hrtimer_cpu_base *new_cpu_base,
struct hrtimer_cpu_base *this_cpu_base)
{
ktime_t expires;
if (new_cpu_base == this_cpu_base)
return true;
if (!hrtimer_base_is_online(this_cpu_base))
return true;
expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset);
return expires >= new_base->cpu_base->expires_next;
}
static inline struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, bool pinned)
{
if (!hrtimer_base_is_online(base)) {
int cpu = cpumask_any_and(cpu_online_mask, housekeeping_cpumask(HK_TYPE_TIMER));
return &per_cpu(hrtimer_bases, cpu);
}
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
if (static_branch_likely(&timers_migration_enabled) && !pinned)
return &per_cpu(hrtimer_bases, get_nohz_timer_target());
#endif
return base;
}
static inline struct hrtimer_clock_base *
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, bool pinned)
{
struct hrtimer_cpu_base *new_cpu_base, *this_cpu_base;
struct hrtimer_clock_base *new_base;
int basenum = base->index;
this_cpu_base = this_cpu_ptr(&hrtimer_bases);
new_cpu_base = get_target_base(this_cpu_base, pinned);
again:
new_base = &new_cpu_base->clock_base[basenum];
if (base != new_base) {
if (unlikely(hrtimer_callback_running(timer)))
return base;
WRITE_ONCE(timer->base, &migration_base);
raw_spin_unlock(&base->cpu_base->lock);
raw_spin_lock(&new_base->cpu_base->lock);
if (!hrtimer_suitable_target(timer, new_base, new_cpu_base, this_cpu_base)) {
raw_spin_unlock(&new_base->cpu_base->lock);
raw_spin_lock(&base->cpu_base->lock);
new_cpu_base = this_cpu_base;
WRITE_ONCE(timer->base, base);
goto again;
}
WRITE_ONCE(timer->base, new_base);
} else {
if (!hrtimer_suitable_target(timer, new_base, new_cpu_base, this_cpu_base)) {
new_cpu_base = this_cpu_base;
goto again;
}
}
return new_base;
}
#else
static inline struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer,
unsigned long *flags)
__acquires(&timer->base->cpu_base->lock)
{
struct hrtimer_clock_base *base = timer->base;
raw_spin_lock_irqsave(&base->cpu_base->lock, *flags);
return base;
}
# define switch_hrtimer_base(t, b, p) (b)
#endif
#if BITS_PER_LONG < 64
s64 __ktime_divns(const ktime_t kt, s64 div)
{
int sft = 0;
s64 dclc;
u64 tmp;
dclc = ktime_to_ns(kt);
tmp = dclc < 0 ? -dclc : dclc;
while (div >> 32) {
sft++;
div >>= 1;
}
tmp >>= sft;
do_div(tmp, (u32) div);
return dclc < 0 ? -tmp : tmp;
}
EXPORT_SYMBOL_GPL(__ktime_divns);
#endif
ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs)
{
ktime_t res = ktime_add_unsafe(lhs, rhs);
if (res < 0 || res < lhs || res < rhs)
res = ktime_set(KTIME_SEC_MAX, 0);
return res;
}
EXPORT_SYMBOL_GPL(ktime_add_safe);
#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
static const struct debug_obj_descr hrtimer_debug_descr;
static void *hrtimer_debug_hint(void *addr)
{
return ACCESS_PRIVATE((struct hrtimer *)addr, function);
}
static bool hrtimer_fixup_init(void *addr, enum debug_obj_state state)
{
struct hrtimer *timer = addr;
switch (state) {
case ODEBUG_STATE_ACTIVE:
hrtimer_cancel(timer);
debug_object_init(timer, &hrtimer_debug_descr);
return true;
default:
return false;
}
}
static bool hrtimer_fixup_activate(void *addr, enum debug_obj_state state)
{
switch (state) {
case ODEBUG_STATE_ACTIVE:
WARN_ON(1);
fallthrough;
default:
return false;
}
}
static bool hrtimer_fixup_free(void *addr, enum debug_obj_state state)
{
struct hrtimer *timer = addr;
switch (state) {
case ODEBUG_STATE_ACTIVE:
hrtimer_cancel(timer);
debug_object_free(timer, &hrtimer_debug_descr);
return true;
default:
return false;
}
}
static enum hrtimer_restart stub_timer(struct hrtimer *unused)
{
WARN_ON_ONCE(1);
return HRTIMER_NORESTART;
}
static bool hrtimer_fixup_assert_init(void *addr, enum debug_obj_state state)
{
struct hrtimer *timer = addr;
switch (state) {
case ODEBUG_STATE_NOTAVAILABLE:
hrtimer_setup(timer, stub_timer, CLOCK_MONOTONIC, 0);
return true;
default:
return false;
}
}
static const struct debug_obj_descr hrtimer_debug_descr = {
.name = "hrtimer",
.debug_hint = hrtimer_debug_hint,
.fixup_init = hrtimer_fixup_init,
.fixup_activate = hrtimer_fixup_activate,
.fixup_free = hrtimer_fixup_free,
.fixup_assert_init = hrtimer_fixup_assert_init,
};
static inline void debug_hrtimer_init(struct hrtimer *timer)
{
debug_object_init(timer, &hrtimer_debug_descr);
}
static inline void debug_hrtimer_init_on_stack(struct hrtimer *timer)
{
debug_object_init_on_stack(timer, &hrtimer_debug_descr);
}
static inline void debug_hrtimer_activate(struct hrtimer *timer, enum hrtimer_mode mode)
{
debug_object_activate(timer, &hrtimer_debug_descr);
}
static inline void debug_hrtimer_deactivate(struct hrtimer *timer)
{
debug_object_deactivate(timer, &hrtimer_debug_descr);
}
static inline void debug_hrtimer_assert_init(struct hrtimer *timer)
{
debug_object_assert_init(timer, &hrtimer_debug_descr);
}
void destroy_hrtimer_on_stack(struct hrtimer *timer)
{
debug_object_free(timer, &hrtimer_debug_descr);
}
EXPORT_SYMBOL_GPL(destroy_hrtimer_on_stack);
#else
static inline void debug_hrtimer_init(struct hrtimer *timer) { }
static inline void debug_hrtimer_init_on_stack(struct hrtimer *timer) { }
static inline void debug_hrtimer_activate(struct hrtimer *timer, enum hrtimer_mode mode) { }
static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { }
static inline void debug_hrtimer_assert_init(struct hrtimer *timer) { }
#endif
static inline void debug_setup(struct hrtimer *timer, clockid_t clockid, enum hrtimer_mode mode)
{
debug_hrtimer_init(timer);
trace_hrtimer_setup(timer, clockid, mode);
}
static inline void debug_setup_on_stack(struct hrtimer *timer, clockid_t clockid,
enum hrtimer_mode mode)
{
debug_hrtimer_init_on_stack(timer);
trace_hrtimer_setup(timer, clockid, mode);
}
static inline void debug_activate(struct hrtimer *timer, enum hrtimer_mode mode, bool was_armed)
{
debug_hrtimer_activate(timer, mode);
trace_hrtimer_start(timer, mode, was_armed);
}
#define for_each_active_base(base, cpu_base, active) \
for (unsigned int idx = ffs(active); idx--; idx = ffs((active))) \
for (bool done = false; !done; active &= ~(1U << idx)) \
for (base = &cpu_base->clock_base[idx]; !done; done = true)
#define hrtimer_from_timerqueue_node(_n) container_of_const(_n, struct hrtimer, node)
#if defined(CONFIG_NO_HZ_COMMON)
static ktime_t hrtimer_bases_next_event_without(struct hrtimer_cpu_base *cpu_base,
const struct hrtimer *exclude,
unsigned int active, ktime_t expires_next)
{
struct hrtimer_clock_base *base;
ktime_t expires;
lockdep_assert_held(&cpu_base->lock);
for_each_active_base(base, cpu_base, active) {
expires = ktime_sub(base->expires_next, base->offset);
if (expires >= expires_next)
continue;
struct timerqueue_linked_node *node = timerqueue_linked_first(&base->active);
if (unlikely(&exclude->node == node)) {
node = timerqueue_linked_next(node);
if (!node)
continue;
expires = ktime_sub(node->expires, base->offset);
if (expires >= expires_next)
continue;
}
expires_next = expires;
}
return max(expires_next, 0);
}
#endif
static __always_inline struct hrtimer *clock_base_next_timer(struct hrtimer_clock_base *base)
{
struct timerqueue_linked_node *next = timerqueue_linked_first(&base->active);
return hrtimer_from_timerqueue_node(next);
}
static void hrtimer_bases_first(struct hrtimer_cpu_base *cpu_base,unsigned int active,
ktime_t *expires_next, struct hrtimer **next_timer)
{
struct hrtimer_clock_base *base;
ktime_t expires;
for_each_active_base(base, cpu_base, active) {
expires = ktime_sub(base->expires_next, base->offset);
if (expires < *expires_next) {
*expires_next = expires;
*next_timer = clock_base_next_timer(base);
}
}
}
static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base, unsigned int active_mask)
{
struct hrtimer *next_timer = NULL;
ktime_t expires_next = KTIME_MAX;
unsigned int active;
lockdep_assert_held(&cpu_base->lock);
if (!cpu_base->softirq_activated && (active_mask & HRTIMER_ACTIVE_SOFT)) {
active = cpu_base->active_bases & HRTIMER_ACTIVE_SOFT;
if (active)
hrtimer_bases_first(cpu_base, active, &expires_next, &next_timer);
cpu_base->softirq_next_timer = next_timer;
}
if (active_mask & HRTIMER_ACTIVE_HARD) {
active = cpu_base->active_bases & HRTIMER_ACTIVE_HARD;
if (active)
hrtimer_bases_first(cpu_base, active, &expires_next, &next_timer);
cpu_base->next_timer = next_timer;
}
return max(expires_next, 0);
}
static ktime_t hrtimer_update_next_event(struct hrtimer_cpu_base *cpu_base)
{
ktime_t expires_next, soft = KTIME_MAX;
if (!cpu_base->softirq_activated) {
soft = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_SOFT);
cpu_base->softirq_expires_next = soft;
}
expires_next = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_HARD);
if (expires_next > soft) {
cpu_base->next_timer = cpu_base->softirq_next_timer;
expires_next = soft;
}
return expires_next;
}
static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
{
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
ktime_t now = ktime_get_update_offsets_now(&base->clock_was_set_seq, offs_real,
offs_boot, offs_tai);
base->clock_base[HRTIMER_BASE_REALTIME_SOFT].offset = *offs_real;
base->clock_base[HRTIMER_BASE_BOOTTIME_SOFT].offset = *offs_boot;
base->clock_base[HRTIMER_BASE_TAI_SOFT].offset = *offs_tai;
return now;
}
static inline int hrtimer_hres_active(struct hrtimer_cpu_base *cpu_base)
{
return IS_ENABLED(CONFIG_HIGH_RES_TIMERS) ?
cpu_base->hres_active : 0;
}
static inline void hrtimer_rearm_event(ktime_t expires_next, bool deferred)
{
trace_hrtimer_rearm(expires_next, deferred);
tick_program_event(expires_next, 1);
}
static void __hrtimer_reprogram(struct hrtimer_cpu_base *cpu_base, struct hrtimer *next_timer,
ktime_t expires_next)
{
cpu_base->expires_next = expires_next;
if (!hrtimer_hres_active(cpu_base) || cpu_base->hang_detected)
return;
hrtimer_rearm_event(expires_next, false);
}
static void hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, bool skip_equal)
{
ktime_t expires_next = hrtimer_update_next_event(cpu_base);
if (skip_equal && expires_next == cpu_base->expires_next)
return;
__hrtimer_reprogram(cpu_base, cpu_base->next_timer, expires_next);
}
#ifdef CONFIG_HIGH_RES_TIMERS
static bool hrtimer_hres_enabled __read_mostly = true;
unsigned int hrtimer_resolution __read_mostly = LOW_RES_NSEC;
EXPORT_SYMBOL_GPL(hrtimer_resolution);
static int __init setup_hrtimer_hres(char *str)
{
return (kstrtobool(str, &hrtimer_hres_enabled) == 0);
}
__setup("highres=", setup_hrtimer_hres);
static inline bool hrtimer_is_hres_enabled(void)
{
return hrtimer_hres_enabled;
}
static void hrtimer_switch_to_hres(void)
{
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
if (tick_init_highres()) {
pr_warn("Could not switch to high resolution mode on CPU %u\n", base->cpu);
return;
}
base->hres_active = true;
hrtimer_resolution = HIGH_RES_NSEC;
tick_setup_sched_timer(true);
retrigger_next_event(NULL);
hrtimer_schedule_hres_work();
}
#else
static inline bool hrtimer_is_hres_enabled(void) { return 0; }
static inline void hrtimer_switch_to_hres(void) { }
#endif
static void retrigger_next_event(void *arg)
{
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
guard(raw_spinlock)(&base->lock);
hrtimer_update_base(base);
if (hrtimer_hres_active(base))
hrtimer_force_reprogram(base, false);
else
hrtimer_update_next_event(base);
}
static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
struct hrtimer_clock_base *base = timer->base;
ktime_t expires = hrtimer_get_expires(timer);
WARN_ON_ONCE(expires < 0);
expires = ktime_sub(expires, base->offset);
if (expires < 0)
expires = 0;
if (timer->is_soft) {
struct hrtimer_cpu_base *timer_cpu_base = base->cpu_base;
if (timer_cpu_base->softirq_activated)
return;
if (!ktime_before(expires, timer_cpu_base->softirq_expires_next))
return;
timer_cpu_base->softirq_next_timer = timer;
timer_cpu_base->softirq_expires_next = expires;
if (!ktime_before(expires, timer_cpu_base->expires_next) || !reprogram)
return;
}
if (base->cpu_base != cpu_base)
return;
if (expires >= cpu_base->expires_next)
return;
if (cpu_base->deferred_rearm)
return;
cpu_base->next_timer = timer;
__hrtimer_reprogram(cpu_base, timer, expires);
}
static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base, unsigned int active)
{
struct hrtimer_clock_base *base;
unsigned int seq;
ktime_t expires;
seq = cpu_base->clock_was_set_seq;
hrtimer_update_base(cpu_base);
if (seq == cpu_base->clock_was_set_seq)
return false;
if (cpu_base->deferred_rearm) {
cpu_base->deferred_needs_update = true;
return false;
}
active &= cpu_base->active_bases;
for_each_active_base(base, cpu_base, active) {
struct timerqueue_linked_node *next;
next = timerqueue_linked_first(&base->active);
expires = ktime_sub(next->expires, base->offset);
if (expires < cpu_base->expires_next)
return true;
if (base->index < HRTIMER_BASE_MONOTONIC_SOFT)
continue;
if (cpu_base->softirq_activated)
continue;
if (expires < cpu_base->softirq_expires_next)
return true;
}
return false;
}
void clock_was_set(unsigned int bases)
{
cpumask_var_t mask;
if (!hrtimer_highres_enabled() && !tick_nohz_is_active())
goto out_timerfd;
if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
on_each_cpu(retrigger_next_event, NULL, 1);
goto out_timerfd;
}
scoped_guard(cpus_read_lock) {
int cpu;
for_each_online_cpu(cpu) {
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
guard(raw_spinlock_irqsave)(&cpu_base->lock);
if (update_needs_ipi(cpu_base, bases))
cpumask_set_cpu(cpu, mask);
}
scoped_guard(preempt)
smp_call_function_many(mask, retrigger_next_event, NULL, 1);
}
free_cpumask_var(mask);
out_timerfd:
timerfd_clock_was_set();
}
static void clock_was_set_work(struct work_struct *work)
{
clock_was_set(CLOCK_SET_WALL);
}
static DECLARE_WORK(hrtimer_work, clock_was_set_work);
void clock_was_set_delayed(void)
{
schedule_work(&hrtimer_work);
}
void hrtimers_resume_local(void)
{
lockdep_assert_irqs_disabled();
retrigger_next_event(NULL);
}
static inline void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags)
__releases(&timer->base->cpu_base->lock)
{
raw_spin_unlock_irqrestore(&timer->base->cpu_base->lock, *flags);
}
u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
{
ktime_t delta;
u64 orun = 1;
delta = ktime_sub(now, hrtimer_get_expires(timer));
if (delta < 0)
return 0;
if (WARN_ON(timer->is_queued))
return 0;
if (interval < hrtimer_resolution)
interval = hrtimer_resolution;
if (unlikely(delta >= interval)) {
s64 incr = ktime_to_ns(interval);
orun = ktime_divns(delta, incr);
hrtimer_add_expires_ns(timer, incr * orun);
if (hrtimer_get_expires(timer) > now)
return orun;
orun++;
}
hrtimer_add_expires(timer, interval);
return orun;
}
EXPORT_SYMBOL_GPL(hrtimer_forward);
static bool enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
enum hrtimer_mode mode, bool was_armed)
{
lockdep_assert_held(&base->cpu_base->lock);
debug_activate(timer, mode, was_armed);
WARN_ON_ONCE(!base->cpu_base->online);
base->cpu_base->active_bases |= 1 << base->index;
WRITE_ONCE(timer->is_queued, HRTIMER_STATE_ENQUEUED);
if (!timerqueue_linked_add(&base->active, &timer->node))
return false;
base->expires_next = hrtimer_get_expires(timer);
return true;
}
static inline void base_update_next_timer(struct hrtimer_clock_base *base)
{
struct timerqueue_linked_node *next = timerqueue_linked_first(&base->active);
base->expires_next = next ? next->expires : KTIME_MAX;
}
static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
bool newstate, bool reprogram)
{
struct hrtimer_cpu_base *cpu_base = base->cpu_base;
bool was_first;
lockdep_assert_held(&cpu_base->lock);
if (!timer->is_queued)
return;
WRITE_ONCE(timer->is_queued, newstate);
was_first = !timerqueue_linked_prev(&timer->node);
if (!timerqueue_linked_del(&base->active, &timer->node))
cpu_base->active_bases &= ~(1 << base->index);
if (!was_first)
return;
base_update_next_timer(base);
if (!reprogram || timer != cpu_base->next_timer || timer->is_lazy)
return;
if (cpu_base->deferred_rearm)
cpu_base->deferred_needs_update = true;
else
hrtimer_force_reprogram(cpu_base, true);
}
static inline bool remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
bool newstate)
{
lockdep_assert_held(&base->cpu_base->lock);
if (timer->is_queued) {
bool reprogram;
debug_hrtimer_deactivate(timer);
reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases);
__remove_hrtimer(timer, base, newstate, reprogram);
return true;
}
return false;
}
static inline bool
hrtimer_can_update_in_place(struct hrtimer *timer, struct hrtimer_clock_base *base, ktime_t expires)
{
struct timerqueue_linked_node *next = timerqueue_linked_next(&timer->node);
struct timerqueue_linked_node *prev = timerqueue_linked_prev(&timer->node);
if (next && expires > next->expires)
return false;
if (!prev)
return true;
return expires >= prev->expires;
}
static inline bool
remove_and_enqueue_same_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
const enum hrtimer_mode mode, ktime_t expires, u64 delta_ns)
{
bool was_first = false;
if (timer->is_queued) {
was_first = !timerqueue_linked_prev(&timer->node);
if (hrtimer_can_update_in_place(timer, base, expires)) {
hrtimer_set_expires_range_ns(timer, expires, delta_ns);
trace_hrtimer_start(timer, mode, true);
if (was_first)
base->expires_next = expires;
return was_first;
}
debug_hrtimer_deactivate(timer);
timerqueue_linked_del(&base->active, &timer->node);
}
hrtimer_set_expires_range_ns(timer, expires, delta_ns);
debug_activate(timer, mode, timer->is_queued);
base->cpu_base->active_bases |= 1 << base->index;
WRITE_ONCE(timer->is_queued, HRTIMER_STATE_ENQUEUED);
if (timerqueue_linked_add(&base->active, &timer->node)) {
base->expires_next = expires;
return true;
}
if (was_first)
base_update_next_timer(base);
return false;
}
static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim,
const enum hrtimer_mode mode)
{
#ifdef CONFIG_TIME_LOW_RES
timer->is_rel = mode & HRTIMER_MODE_REL;
if (timer->is_rel)
tim = ktime_add_safe(tim, hrtimer_resolution);
#endif
return tim;
}
static void hrtimer_update_softirq_timer(struct hrtimer_cpu_base *cpu_base, bool reprogram)
{
ktime_t expires = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_SOFT);
if (expires == KTIME_MAX)
return;
hrtimer_reprogram(cpu_base->softirq_next_timer, reprogram);
}
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
static __always_inline bool hrtimer_prefer_local(bool is_local, bool is_first, bool is_pinned)
{
if (static_branch_likely(&timers_migration_enabled)) {
if (!is_local)
return false;
if (is_first || is_pinned)
return true;
if (!housekeeping_cpu(smp_processor_id(), HK_TYPE_KERNEL_NOISE))
return false;
return !tick_nohz_tick_stopped() || need_resched();
}
return is_local;
}
#else
static __always_inline bool hrtimer_prefer_local(bool is_local, bool is_first, bool is_pinned)
{
return is_local;
}
#endif
static inline bool hrtimer_keep_base(struct hrtimer *timer, bool is_local, bool is_first,
bool is_pinned)
{
if (unlikely(timer->base->running == timer))
return true;
return hrtimer_prefer_local(is_local, is_first, is_pinned);
}
enum {
HRTIMER_REPROGRAM_NONE,
HRTIMER_REPROGRAM,
HRTIMER_REPROGRAM_FORCE,
};
static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, u64 delta_ns,
const enum hrtimer_mode mode, struct hrtimer_clock_base *base)
{
struct hrtimer_cpu_base *this_cpu_base = this_cpu_ptr(&hrtimer_bases);
bool is_pinned, first, was_first, keep_base = false;
struct hrtimer_cpu_base *cpu_base = base->cpu_base;
was_first = cpu_base->next_timer == timer;
is_pinned = !!(mode & HRTIMER_MODE_PINNED);
if (likely(this_cpu_base->online)) {
bool is_local = cpu_base == this_cpu_base;
keep_base = hrtimer_keep_base(timer, is_local, was_first, is_pinned);
}
if (mode & HRTIMER_MODE_REL)
tim = ktime_add_safe(tim, __hrtimer_cb_get_time(base->clockid));
tim = hrtimer_update_lowres(timer, tim, mode);
if (likely(keep_base)) {
first = remove_and_enqueue_same_base(timer, base, mode, tim, delta_ns);
} else {
bool was_armed = remove_hrtimer(timer, base, HRTIMER_STATE_ENQUEUED);
hrtimer_set_expires_range_ns(timer, tim, delta_ns);
base = switch_hrtimer_base(timer, base, is_pinned);
cpu_base = base->cpu_base;
first = enqueue_hrtimer(timer, base, mode, was_armed);
}
if (cpu_base->deferred_rearm) {
cpu_base->deferred_needs_update = true;
return HRTIMER_REPROGRAM_NONE;
}
if (!was_first || cpu_base != this_cpu_base) {
if (likely(hrtimer_base_is_online(this_cpu_base)))
return first ? HRTIMER_REPROGRAM : HRTIMER_REPROGRAM_NONE;
if (first)
smp_call_function_single_async(cpu_base->cpu, &cpu_base->csd);
return HRTIMER_REPROGRAM_NONE;
}
if (timer->is_lazy) {
if (cpu_base->expires_next <= hrtimer_get_expires(timer))
return HRTIMER_REPROGRAM_NONE;
}
return HRTIMER_REPROGRAM_FORCE;
}
static int hrtimer_start_range_ns_common(struct hrtimer *timer, ktime_t tim,
u64 delta_ns, const enum hrtimer_mode mode,
struct hrtimer_clock_base *base)
{
if (!IS_ENABLED(CONFIG_PREEMPT_RT))
WARN_ON_ONCE(!(mode & HRTIMER_MODE_SOFT) ^ !timer->is_soft);
else
WARN_ON_ONCE(!(mode & HRTIMER_MODE_HARD) ^ !timer->is_hard);
return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, base);
}
void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, u64 delta_ns,
const enum hrtimer_mode mode)
{
struct hrtimer_clock_base *base;
unsigned long flags;
debug_hrtimer_assert_init(timer);
base = lock_hrtimer_base(timer, &flags);
switch (hrtimer_start_range_ns_common(timer, tim, delta_ns, mode, base)) {
case HRTIMER_REPROGRAM:
hrtimer_reprogram(timer, true);
break;
case HRTIMER_REPROGRAM_FORCE:
hrtimer_force_reprogram(timer->base->cpu_base, 1);
break;
case HRTIMER_REPROGRAM_NONE:
break;
}
unlock_hrtimer_base(timer, &flags);
}
EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
static inline bool hrtimer_check_user_timer(struct hrtimer *timer)
{
struct hrtimer_cpu_base *cpu_base = timer->base->cpu_base;
ktime_t expires;
expires = hrtimer_get_softexpires(timer);
expires = ktime_sub(expires, timer->base->offset);
if (expires >= cpu_base->expires_next)
return true;
if (expires > ktime_get())
return true;
debug_hrtimer_deactivate(timer);
__remove_hrtimer(timer, timer->base, HRTIMER_STATE_INACTIVE, false);
trace_hrtimer_start_expired(timer);
return false;
}
bool hrtimer_start_range_ns_user(struct hrtimer *timer, ktime_t tim,
u64 delta_ns, const enum hrtimer_mode mode)
{
struct hrtimer_clock_base *base;
unsigned long flags;
bool ret = true;
debug_hrtimer_assert_init(timer);
base = lock_hrtimer_base(timer, &flags);
switch (hrtimer_start_range_ns_common(timer, tim, delta_ns, mode, base)) {
case HRTIMER_REPROGRAM:
ret = hrtimer_check_user_timer(timer);
if (ret)
hrtimer_reprogram(timer, true);
break;
case HRTIMER_REPROGRAM_FORCE:
ret = hrtimer_check_user_timer(timer);
hrtimer_force_reprogram(timer->base->cpu_base, 1);
break;
case HRTIMER_REPROGRAM_NONE:
break;
}
unlock_hrtimer_base(timer, &flags);
return ret;
}
EXPORT_SYMBOL_GPL(hrtimer_start_range_ns_user);
int hrtimer_try_to_cancel(struct hrtimer *timer)
{
struct hrtimer_clock_base *base;
unsigned long flags;
int ret = -1;
if (!hrtimer_active(timer))
return 0;
base = lock_hrtimer_base(timer, &flags);
if (!hrtimer_callback_running(timer)) {
ret = remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE);
if (ret)
trace_hrtimer_cancel(timer);
}
unlock_hrtimer_base(timer, &flags);
return ret;
}
EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel);
#ifdef CONFIG_PREEMPT_RT
static void hrtimer_cpu_base_init_expiry_lock(struct hrtimer_cpu_base *base)
{
spin_lock_init(&base->softirq_expiry_lock);
}
static void hrtimer_cpu_base_lock_expiry(struct hrtimer_cpu_base *base)
__acquires(&base->softirq_expiry_lock)
{
spin_lock(&base->softirq_expiry_lock);
}
static void hrtimer_cpu_base_unlock_expiry(struct hrtimer_cpu_base *base)
__releases(&base->softirq_expiry_lock)
{
spin_unlock(&base->softirq_expiry_lock);
}
static void hrtimer_sync_wait_running(struct hrtimer_cpu_base *cpu_base, unsigned long flags)
{
if (atomic_read(&cpu_base->timer_waiters)) {
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
spin_unlock(&cpu_base->softirq_expiry_lock);
spin_lock(&cpu_base->softirq_expiry_lock);
raw_spin_lock_irq(&cpu_base->lock);
}
}
#ifdef CONFIG_SMP
static __always_inline bool is_migration_base(struct hrtimer_clock_base *base)
{
return base == &migration_base;
}
#else
static __always_inline bool is_migration_base(struct hrtimer_clock_base *base)
{
return false;
}
#endif
void hrtimer_cancel_wait_running(const struct hrtimer *timer)
{
struct hrtimer_clock_base *base = READ_ONCE(timer->base);
if (!timer->is_soft || is_migration_base(base)) {
cpu_relax();
return;
}
atomic_inc(&base->cpu_base->timer_waiters);
spin_lock_bh(&base->cpu_base->softirq_expiry_lock);
atomic_dec(&base->cpu_base->timer_waiters);
spin_unlock_bh(&base->cpu_base->softirq_expiry_lock);
}
#else
static inline void hrtimer_cpu_base_init_expiry_lock(struct hrtimer_cpu_base *base) { }
static inline void hrtimer_cpu_base_lock_expiry(struct hrtimer_cpu_base *base) { }
static inline void hrtimer_cpu_base_unlock_expiry(struct hrtimer_cpu_base *base) { }
static inline void hrtimer_sync_wait_running(struct hrtimer_cpu_base *base, unsigned long fl) { }
#endif
int hrtimer_cancel(struct hrtimer *timer)
{
int ret;
do {
ret = hrtimer_try_to_cancel(timer);
if (ret < 0)
hrtimer_cancel_wait_running(timer);
} while (ret < 0);
return ret;
}
EXPORT_SYMBOL_GPL(hrtimer_cancel);
ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust)
{
unsigned long flags;
ktime_t rem;
lock_hrtimer_base(timer, &flags);
if (IS_ENABLED(CONFIG_TIME_LOW_RES) && adjust)
rem = hrtimer_expires_remaining_adjusted(timer);
else
rem = hrtimer_expires_remaining(timer);
unlock_hrtimer_base(timer, &flags);
return rem;
}
EXPORT_SYMBOL_GPL(__hrtimer_get_remaining);
#ifdef CONFIG_NO_HZ_COMMON
ktime_t hrtimer_get_next_event(void)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
ktime_t expires = KTIME_MAX;
guard(raw_spinlock_irqsave)(&cpu_base->lock);
if (!hrtimer_hres_active(cpu_base))
expires = __hrtimer_get_next_event(cpu_base, HRTIMER_ACTIVE_ALL);
return expires;
}
ktime_t hrtimer_next_event_without(const struct hrtimer *exclude)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
ktime_t expires = KTIME_MAX;
unsigned int active;
guard(raw_spinlock_irqsave)(&cpu_base->lock);
if (!hrtimer_hres_active(cpu_base))
return expires;
active = cpu_base->active_bases & HRTIMER_ACTIVE_SOFT;
if (active && !cpu_base->softirq_activated)
expires = hrtimer_bases_next_event_without(cpu_base, exclude, active, KTIME_MAX);
active = cpu_base->active_bases & HRTIMER_ACTIVE_HARD;
if (!active)
return expires;
return hrtimer_bases_next_event_without(cpu_base, exclude, active, expires);
}
#endif
static inline int hrtimer_clockid_to_base(clockid_t clock_id)
{
switch (clock_id) {
case CLOCK_MONOTONIC:
return HRTIMER_BASE_MONOTONIC;
case CLOCK_REALTIME:
return HRTIMER_BASE_REALTIME;
case CLOCK_BOOTTIME:
return HRTIMER_BASE_BOOTTIME;
case CLOCK_TAI:
return HRTIMER_BASE_TAI;
default:
WARN(1, "Invalid clockid %d. Using MONOTONIC\n", clock_id);
return HRTIMER_BASE_MONOTONIC;
}
}
static ktime_t __hrtimer_cb_get_time(clockid_t clock_id)
{
switch (clock_id) {
case CLOCK_MONOTONIC:
return ktime_get();
case CLOCK_REALTIME:
return ktime_get_real();
case CLOCK_BOOTTIME:
return ktime_get_boottime();
case CLOCK_TAI:
return ktime_get_clocktai();
default:
WARN(1, "Invalid clockid %d. Using MONOTONIC\n", clock_id);
return ktime_get();
}
}
ktime_t hrtimer_cb_get_time(const struct hrtimer *timer)
{
return __hrtimer_cb_get_time(timer->base->clockid);
}
EXPORT_SYMBOL_GPL(hrtimer_cb_get_time);
static void __hrtimer_setup(struct hrtimer *timer, enum hrtimer_restart (*fn)(struct hrtimer *),
clockid_t clock_id, enum hrtimer_mode mode)
{
bool softtimer = !!(mode & HRTIMER_MODE_SOFT);
struct hrtimer_cpu_base *cpu_base;
int base;
if (IS_ENABLED(CONFIG_PREEMPT_RT) && !(mode & HRTIMER_MODE_HARD))
softtimer = true;
memset(timer, 0, sizeof(struct hrtimer));
cpu_base = raw_cpu_ptr(&hrtimer_bases);
if (clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL)
clock_id = CLOCK_MONOTONIC;
base = softtimer ? HRTIMER_MAX_CLOCK_BASES / 2 : 0;
base += hrtimer_clockid_to_base(clock_id);
timer->is_soft = softtimer;
timer->is_hard = !!(mode & HRTIMER_MODE_HARD);
timer->is_lazy = !!(mode & HRTIMER_MODE_LAZY_REARM);
timer->base = &cpu_base->clock_base[base];
timerqueue_linked_init(&timer->node);
if (WARN_ON_ONCE(!fn))
ACCESS_PRIVATE(timer, function) = hrtimer_dummy_timeout;
else
ACCESS_PRIVATE(timer, function) = fn;
}
void hrtimer_setup(struct hrtimer *timer, enum hrtimer_restart (*function)(struct hrtimer *),
clockid_t clock_id, enum hrtimer_mode mode)
{
debug_setup(timer, clock_id, mode);
__hrtimer_setup(timer, function, clock_id, mode);
}
EXPORT_SYMBOL_GPL(hrtimer_setup);
void hrtimer_setup_on_stack(struct hrtimer *timer,
enum hrtimer_restart (*function)(struct hrtimer *),
clockid_t clock_id, enum hrtimer_mode mode)
{
debug_setup_on_stack(timer, clock_id, mode);
__hrtimer_setup(timer, function, clock_id, mode);
}
EXPORT_SYMBOL_GPL(hrtimer_setup_on_stack);
bool hrtimer_active(const struct hrtimer *timer)
{
struct hrtimer_clock_base *base;
unsigned int seq;
do {
base = READ_ONCE(timer->base);
seq = raw_read_seqcount_begin(&base->seq);
if (timer->is_queued || base->running == timer)
return true;
} while (read_seqcount_retry(&base->seq, seq) || base != READ_ONCE(timer->base));
return false;
}
EXPORT_SYMBOL_GPL(hrtimer_active);
static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, struct hrtimer_clock_base *base,
struct hrtimer *timer, ktime_t now, unsigned long flags)
__must_hold(&cpu_base->lock)
{
enum hrtimer_restart (*fn)(struct hrtimer *);
bool expires_in_hardirq;
int restart;
lockdep_assert_held(&cpu_base->lock);
debug_hrtimer_deactivate(timer);
base->running = timer;
raw_write_seqcount_barrier(&base->seq);
__remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, false);
fn = ACCESS_PRIVATE(timer, function);
if (IS_ENABLED(CONFIG_TIME_LOW_RES))
timer->is_rel = false;
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
trace_hrtimer_expire_entry(timer, now);
expires_in_hardirq = lockdep_hrtimer_enter(timer);
restart = fn(timer);
lockdep_hrtimer_exit(expires_in_hardirq);
trace_hrtimer_expire_exit(timer);
raw_spin_lock_irq(&cpu_base->lock);
if (restart == HRTIMER_RESTART && !timer->is_queued)
enqueue_hrtimer(timer, base, HRTIMER_MODE_ABS, false);
raw_write_seqcount_barrier(&base->seq);
WARN_ON_ONCE(base->running != timer);
base->running = NULL;
}
static __always_inline struct hrtimer *clock_base_next_timer_safe(struct hrtimer_clock_base *base)
{
struct timerqueue_linked_node *next = timerqueue_linked_first(&base->active);
return next ? hrtimer_from_timerqueue_node(next) : NULL;
}
static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now,
unsigned long flags, unsigned int active_mask)
{
unsigned int active = cpu_base->active_bases & active_mask;
struct hrtimer_clock_base *base;
for_each_active_base(base, cpu_base, active) {
ktime_t basenow = ktime_add(now, base->offset);
struct hrtimer *timer;
while ((timer = clock_base_next_timer(base))) {
if (basenow < hrtimer_get_softexpires(timer))
break;
__run_hrtimer(cpu_base, base, timer, basenow, flags);
if (active_mask == HRTIMER_ACTIVE_SOFT)
hrtimer_sync_wait_running(cpu_base, flags);
}
}
}
static __latent_entropy void hrtimer_run_softirq(void)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
unsigned long flags;
ktime_t now;
hrtimer_cpu_base_lock_expiry(cpu_base);
raw_spin_lock_irqsave(&cpu_base->lock, flags);
now = hrtimer_update_base(cpu_base);
__hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_SOFT);
cpu_base->softirq_activated = false;
hrtimer_update_softirq_timer(cpu_base, true);
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
hrtimer_cpu_base_unlock_expiry(cpu_base);
}
#ifdef CONFIG_HIGH_RES_TIMERS
static void hrtimer_rearm(struct hrtimer_cpu_base *cpu_base, ktime_t expires_next, bool deferred)
{
cpu_base->expires_next = expires_next;
cpu_base->deferred_rearm = false;
if (unlikely(cpu_base->hang_detected)) {
expires_next = ktime_add_ns(ktime_get(),
min(100 * NSEC_PER_MSEC, cpu_base->max_hang_time));
}
hrtimer_rearm_event(expires_next, deferred);
}
#ifdef CONFIG_HRTIMER_REARM_DEFERRED
void __hrtimer_rearm_deferred(void)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
ktime_t expires_next;
if (!cpu_base->deferred_rearm)
return;
guard(raw_spinlock)(&cpu_base->lock);
if (cpu_base->deferred_needs_update) {
hrtimer_update_base(cpu_base);
expires_next = hrtimer_update_next_event(cpu_base);
} else {
expires_next = cpu_base->deferred_expires_next;
}
hrtimer_rearm(cpu_base, expires_next, true);
}
static __always_inline void
hrtimer_interrupt_rearm(struct hrtimer_cpu_base *cpu_base, ktime_t expires_next)
{
cpu_base->deferred_needs_update = false;
cpu_base->deferred_expires_next = expires_next;
set_thread_flag(TIF_HRTIMER_REARM);
}
#else
static __always_inline void
hrtimer_interrupt_rearm(struct hrtimer_cpu_base *cpu_base, ktime_t expires_next)
{
hrtimer_rearm(cpu_base, expires_next, false);
}
#endif
void hrtimer_interrupt(struct clock_event_device *dev)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
ktime_t expires_next, now, entry_time, delta;
unsigned long flags;
int retries = 0;
BUG_ON(!cpu_base->hres_active);
cpu_base->nr_events++;
dev->next_event = KTIME_MAX;
dev->next_event_forced = 0;
raw_spin_lock_irqsave(&cpu_base->lock, flags);
entry_time = now = hrtimer_update_base(cpu_base);
retry:
cpu_base->deferred_rearm = true;
cpu_base->expires_next = KTIME_MAX;
if (!ktime_before(now, cpu_base->softirq_expires_next)) {
cpu_base->softirq_expires_next = KTIME_MAX;
cpu_base->softirq_activated = true;
raise_timer_softirq(HRTIMER_SOFTIRQ);
}
__hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
now = hrtimer_update_base(cpu_base);
expires_next = hrtimer_update_next_event(cpu_base);
cpu_base->hang_detected = false;
if (expires_next < now) {
if (++retries < 3)
goto retry;
delta = ktime_sub(now, entry_time);
cpu_base->max_hang_time = max_t(unsigned int, cpu_base->max_hang_time, delta);
cpu_base->nr_hangs++;
cpu_base->hang_detected = true;
}
hrtimer_interrupt_rearm(cpu_base, expires_next);
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
}
#endif
void hrtimer_run_queues(void)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
unsigned long flags;
ktime_t now;
if (hrtimer_hres_active(cpu_base))
return;
if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {
hrtimer_switch_to_hres();
return;
}
raw_spin_lock_irqsave(&cpu_base->lock, flags);
now = hrtimer_update_base(cpu_base);
if (!ktime_before(now, cpu_base->softirq_expires_next)) {
cpu_base->softirq_expires_next = KTIME_MAX;
cpu_base->softirq_activated = true;
raise_timer_softirq(HRTIMER_SOFTIRQ);
}
__hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
}
static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer)
{
struct hrtimer_sleeper *t = container_of(timer, struct hrtimer_sleeper, timer);
struct task_struct *task = t->task;
t->task = NULL;
if (task)
wake_up_process(task);
return HRTIMER_NORESTART;
}
void hrtimer_sleeper_start_expires(struct hrtimer_sleeper *sl, enum hrtimer_mode mode)
{
if (IS_ENABLED(CONFIG_PREEMPT_RT) && sl->timer.is_hard)
mode |= HRTIMER_MODE_HARD;
if (!hrtimer_start_expires_user(&sl->timer, mode)) {
sl->task = NULL;
__set_current_state(TASK_RUNNING);
}
}
EXPORT_SYMBOL_GPL(hrtimer_sleeper_start_expires);
static void __hrtimer_setup_sleeper(struct hrtimer_sleeper *sl, clockid_t clock_id,
enum hrtimer_mode mode)
{
if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
if (rt_or_dl_task_policy(current) && !(mode & HRTIMER_MODE_SOFT))
mode |= HRTIMER_MODE_HARD;
}
__hrtimer_setup(&sl->timer, hrtimer_wakeup, clock_id, mode);
sl->task = current;
}
void hrtimer_setup_sleeper_on_stack(struct hrtimer_sleeper *sl, clockid_t clock_id,
enum hrtimer_mode mode)
{
debug_setup_on_stack(&sl->timer, clock_id, mode);
__hrtimer_setup_sleeper(sl, clock_id, mode);
}
EXPORT_SYMBOL_GPL(hrtimer_setup_sleeper_on_stack);
int nanosleep_copyout(struct restart_block *restart, struct timespec64 *ts)
{
switch(restart->nanosleep.type) {
#ifdef CONFIG_COMPAT_32BIT_TIME
case TT_COMPAT:
if (put_old_timespec32(ts, restart->nanosleep.compat_rmtp))
return -EFAULT;
break;
#endif
case TT_NATIVE:
if (put_timespec64(ts, restart->nanosleep.rmtp))
return -EFAULT;
break;
default:
BUG();
}
return -ERESTART_RESTARTBLOCK;
}
static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
{
struct restart_block *restart;
do {
set_current_state(TASK_INTERRUPTIBLE|TASK_FREEZABLE);
hrtimer_sleeper_start_expires(t, mode);
if (likely(t->task))
schedule();
hrtimer_cancel(&t->timer);
mode = HRTIMER_MODE_ABS;
} while (t->task && !signal_pending(current));
__set_current_state(TASK_RUNNING);
if (!t->task)
return 0;
restart = ¤t->restart_block;
if (restart->nanosleep.type != TT_NONE) {
ktime_t rem = hrtimer_expires_remaining(&t->timer);
struct timespec64 rmt;
if (rem <= 0)
return 0;
rmt = ktime_to_timespec64(rem);
return nanosleep_copyout(restart, &rmt);
}
return -ERESTART_RESTARTBLOCK;
}
static long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
{
struct hrtimer_sleeper t;
int ret;
hrtimer_setup_sleeper_on_stack(&t, restart->nanosleep.clockid, HRTIMER_MODE_ABS);
hrtimer_set_expires(&t.timer, restart->nanosleep.expires);
ret = do_nanosleep(&t, HRTIMER_MODE_ABS);
destroy_hrtimer_on_stack(&t.timer);
return ret;
}
long hrtimer_nanosleep(ktime_t rqtp, const enum hrtimer_mode mode, const clockid_t clockid)
{
struct restart_block *restart;
struct hrtimer_sleeper t;
int ret;
hrtimer_setup_sleeper_on_stack(&t, clockid, mode);
hrtimer_set_expires_range_ns(&t.timer, rqtp, current->timer_slack_ns);
ret = do_nanosleep(&t, mode);
if (ret != -ERESTART_RESTARTBLOCK)
goto out;
if (mode == HRTIMER_MODE_ABS) {
ret = -ERESTARTNOHAND;
goto out;
}
restart = ¤t->restart_block;
restart->nanosleep.clockid = t.timer.base->clockid;
restart->nanosleep.expires = hrtimer_get_expires(&t.timer);
set_restart_fn(restart, hrtimer_nanosleep_restart);
out:
destroy_hrtimer_on_stack(&t.timer);
return ret;
}
#ifdef CONFIG_64BIT
SYSCALL_DEFINE2(nanosleep, struct __kernel_timespec __user *, rqtp,
struct __kernel_timespec __user *, rmtp)
{
struct timespec64 tu;
if (get_timespec64(&tu, rqtp))
return -EFAULT;
if (!timespec64_valid(&tu))
return -EINVAL;
current->restart_block.fn = do_no_restart_syscall;
current->restart_block.nanosleep.type = rmtp ? TT_NATIVE : TT_NONE;
current->restart_block.nanosleep.rmtp = rmtp;
return hrtimer_nanosleep(timespec64_to_ktime(tu), HRTIMER_MODE_REL, CLOCK_MONOTONIC);
}
#endif
#ifdef CONFIG_COMPAT_32BIT_TIME
SYSCALL_DEFINE2(nanosleep_time32, struct old_timespec32 __user *, rqtp,
struct old_timespec32 __user *, rmtp)
{
struct timespec64 tu;
if (get_old_timespec32(&tu, rqtp))
return -EFAULT;
if (!timespec64_valid(&tu))
return -EINVAL;
current->restart_block.fn = do_no_restart_syscall;
current->restart_block.nanosleep.type = rmtp ? TT_COMPAT : TT_NONE;
current->restart_block.nanosleep.compat_rmtp = rmtp;
return hrtimer_nanosleep(timespec64_to_ktime(tu), HRTIMER_MODE_REL, CLOCK_MONOTONIC);
}
#endif
int hrtimers_prepare_cpu(unsigned int cpu)
{
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
for (int i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
struct hrtimer_clock_base *clock_b = &cpu_base->clock_base[i];
clock_b->cpu_base = cpu_base;
seqcount_raw_spinlock_init(&clock_b->seq, &cpu_base->lock);
timerqueue_linked_init_head(&clock_b->active);
}
cpu_base->cpu = cpu;
hrtimer_cpu_base_init_expiry_lock(cpu_base);
return 0;
}
int hrtimers_cpu_starting(unsigned int cpu)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
cpu_base->active_bases = 0;
cpu_base->hres_active = false;
cpu_base->hang_detected = false;
cpu_base->next_timer = NULL;
cpu_base->softirq_next_timer = NULL;
cpu_base->expires_next = KTIME_MAX;
cpu_base->softirq_expires_next = KTIME_MAX;
cpu_base->softirq_activated = false;
cpu_base->online = true;
return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
struct hrtimer_clock_base *new_base)
{
struct timerqueue_linked_node *node;
struct hrtimer *timer;
while ((node = timerqueue_linked_first(&old_base->active))) {
timer = hrtimer_from_timerqueue_node(node);
BUG_ON(hrtimer_callback_running(timer));
debug_hrtimer_deactivate(timer);
__remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, false);
timer->base = new_base;
enqueue_hrtimer(timer, new_base, HRTIMER_MODE_ABS, true);
}
}
int hrtimers_cpu_dying(unsigned int dying_cpu)
{
int ncpu = cpumask_any_and(cpu_active_mask, housekeeping_cpumask(HK_TYPE_TIMER));
struct hrtimer_cpu_base *old_base, *new_base;
old_base = this_cpu_ptr(&hrtimer_bases);
new_base = &per_cpu(hrtimer_bases, ncpu);
raw_spin_lock(&old_base->lock);
raw_spin_lock_nested(&new_base->lock, SINGLE_DEPTH_NESTING);
for (int i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++)
migrate_hrtimer_list(&old_base->clock_base[i], &new_base->clock_base[i]);
smp_call_function_single(ncpu, retrigger_next_event, NULL, 0);
raw_spin_unlock(&new_base->lock);
old_base->online = false;
raw_spin_unlock(&old_base->lock);
return 0;
}
#endif
void __init hrtimers_init(void)
{
hrtimers_prepare_cpu(smp_processor_id());
hrtimers_cpu_starting(smp_processor_id());
open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq);
}