diff options
Diffstat (limited to 'include/linux/hrtimer.h')
| -rw-r--r-- | include/linux/hrtimer.h | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h new file mode 100644 index 000000000..29072d89e --- /dev/null +++ b/include/linux/hrtimer.h @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * hrtimers - High-resolution kernel timers + * + * Copyright(C) 2005, Linutronix GmbH, Thomas Gleixner <tglx@kernel.org> + * Copyright(C) 2005, Red Hat, Inc., Ingo Molnar + * + * data type definitions, declarations, prototypes + * + * Started by: Thomas Gleixner and Ingo Molnar + */ +#ifndef _LINUX_HRTIMER_H +#define _LINUX_HRTIMER_H + +#include <linux/hrtimer_rearm.h> +#include <linux/hrtimer_types.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/percpu-defs.h> +#include <linux/rbtree.h> +#include <linux/timer.h> + +/* + * Mode arguments of xxx_hrtimer functions: + * + * HRTIMER_MODE_ABS - Time value is absolute + * HRTIMER_MODE_REL - Time value is relative to now + * HRTIMER_MODE_PINNED - Timer is bound to CPU (is only considered + * when starting the timer) + * HRTIMER_MODE_SOFT - Timer callback function will be executed in + * soft irq context + * HRTIMER_MODE_HARD - Timer callback function will be executed in + * hard irq context even on PREEMPT_RT. + * HRTIMER_MODE_LAZY_REARM - Avoid reprogramming if the timer was the + * first expiring timer and is moved into the + * future. Special mode for the HRTICK timer to + * avoid extensive reprogramming of the hardware, + * which is expensive in virtual machines. Risks + * a pointless expiry, but that's better than + * reprogramming on every context switch, + */ +enum hrtimer_mode { + HRTIMER_MODE_ABS = 0x00, + HRTIMER_MODE_REL = 0x01, + HRTIMER_MODE_PINNED = 0x02, + HRTIMER_MODE_SOFT = 0x04, + HRTIMER_MODE_HARD = 0x08, + HRTIMER_MODE_LAZY_REARM = 0x10, + + HRTIMER_MODE_ABS_PINNED = HRTIMER_MODE_ABS | HRTIMER_MODE_PINNED, + HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL | HRTIMER_MODE_PINNED, + + HRTIMER_MODE_ABS_SOFT = HRTIMER_MODE_ABS | HRTIMER_MODE_SOFT, + HRTIMER_MODE_REL_SOFT = HRTIMER_MODE_REL | HRTIMER_MODE_SOFT, + + HRTIMER_MODE_ABS_PINNED_SOFT = HRTIMER_MODE_ABS_PINNED | HRTIMER_MODE_SOFT, + HRTIMER_MODE_REL_PINNED_SOFT = HRTIMER_MODE_REL_PINNED | HRTIMER_MODE_SOFT, + + HRTIMER_MODE_ABS_HARD = HRTIMER_MODE_ABS | HRTIMER_MODE_HARD, + HRTIMER_MODE_REL_HARD = HRTIMER_MODE_REL | HRTIMER_MODE_HARD, + + HRTIMER_MODE_ABS_PINNED_HARD = HRTIMER_MODE_ABS_PINNED | HRTIMER_MODE_HARD, + HRTIMER_MODE_REL_PINNED_HARD = HRTIMER_MODE_REL_PINNED | HRTIMER_MODE_HARD, +}; + +/** + * struct hrtimer_sleeper - simple sleeper structure + * @timer: embedded timer structure + * @task: task to wake up + * + * task is set to NULL, when the timer expires. + */ +struct hrtimer_sleeper { + struct hrtimer timer; + struct task_struct *task; +}; + +static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) +{ + timer->node.expires = time; + timer->_softexpires = time; +} + +static inline void hrtimer_set_expires_range(struct hrtimer *timer, ktime_t time, ktime_t delta) +{ + timer->_softexpires = time; + timer->node.expires = ktime_add_safe(time, delta); +} + +static inline void hrtimer_set_expires_range_ns(struct hrtimer *timer, ktime_t time, u64 delta) +{ + timer->_softexpires = time; + timer->node.expires = ktime_add_safe(time, ns_to_ktime(delta)); +} + +static inline void hrtimer_add_expires(struct hrtimer *timer, ktime_t time) +{ + timer->node.expires = ktime_add_safe(timer->node.expires, time); + timer->_softexpires = ktime_add_safe(timer->_softexpires, time); +} + +static inline void hrtimer_add_expires_ns(struct hrtimer *timer, u64 ns) +{ + timer->node.expires = ktime_add_ns(timer->node.expires, ns); + timer->_softexpires = ktime_add_ns(timer->_softexpires, ns); +} + +static inline ktime_t hrtimer_get_expires(const struct hrtimer *timer) +{ + return timer->node.expires; +} + +static inline ktime_t hrtimer_get_softexpires(const struct hrtimer *timer) +{ + return timer->_softexpires; +} + +ktime_t hrtimer_cb_get_time(const struct hrtimer *timer); + +static inline ktime_t hrtimer_expires_remaining(const struct hrtimer *timer) +{ + return ktime_sub(timer->node.expires, hrtimer_cb_get_time(timer)); +} + +#ifdef CONFIG_HIGH_RES_TIMERS +extern unsigned int hrtimer_resolution; +struct clock_event_device; + +extern void hrtimer_interrupt(struct clock_event_device *dev); + +extern struct static_key_false hrtimer_highres_enabled_key; + +static inline bool hrtimer_highres_enabled(void) +{ + return static_branch_likely(&hrtimer_highres_enabled_key); +} + +#else /* CONFIG_HIGH_RES_TIMERS */ +#define hrtimer_resolution (unsigned int)LOW_RES_NSEC +static inline bool hrtimer_highres_enabled(void) { return false; } +#endif /* !CONFIG_HIGH_RES_TIMERS */ + +static inline ktime_t +__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now) +{ + ktime_t rem = ktime_sub(timer->node.expires, now); + + /* + * Adjust relative timers for the extra we added in + * hrtimer_start_range_ns() to prevent short timeouts. + */ + if (IS_ENABLED(CONFIG_TIME_LOW_RES) && timer->is_rel) + rem -= hrtimer_resolution; + return rem; +} + +static inline ktime_t +hrtimer_expires_remaining_adjusted(const struct hrtimer *timer) +{ + return __hrtimer_expires_remaining_adjusted(timer, hrtimer_cb_get_time(timer)); +} + +#ifdef CONFIG_TIMERFD +extern void timerfd_clock_was_set(void); +extern void timerfd_resume(void); +#else +static inline void timerfd_clock_was_set(void) { } +static inline void timerfd_resume(void) { } +#endif + +DECLARE_PER_CPU(struct tick_device, tick_cpu_device); + +#ifdef CONFIG_PREEMPT_RT +void hrtimer_cancel_wait_running(const struct hrtimer *timer); +#else +static inline void hrtimer_cancel_wait_running(struct hrtimer *timer) +{ + cpu_relax(); +} +#endif + +static inline enum hrtimer_restart hrtimer_dummy_timeout(struct hrtimer *unused) +{ + return HRTIMER_NORESTART; +} + +/* Exported timer functions: */ + +/* Initialize timers: */ +extern void hrtimer_setup(struct hrtimer *timer, enum hrtimer_restart (*function)(struct hrtimer *), + clockid_t clock_id, enum hrtimer_mode mode); +extern void hrtimer_setup_on_stack(struct hrtimer *timer, + enum hrtimer_restart (*function)(struct hrtimer *), + clockid_t clock_id, enum hrtimer_mode mode); +extern void hrtimer_setup_sleeper_on_stack(struct hrtimer_sleeper *sl, clockid_t clock_id, + enum hrtimer_mode mode); + +#ifdef CONFIG_DEBUG_OBJECTS_TIMERS +extern void destroy_hrtimer_on_stack(struct hrtimer *timer); +#else +static inline void destroy_hrtimer_on_stack(struct hrtimer *timer) { } +#endif + +/* Basic timer operations: */ +extern void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, + u64 range_ns, const enum hrtimer_mode mode); + +extern bool hrtimer_start_range_ns_user(struct hrtimer *timer, ktime_t tim, + u64 range_ns, const enum hrtimer_mode mode); + +/** + * hrtimer_start - (re)start an hrtimer + * @timer: the timer to be added + * @tim: expiry time + * @mode: timer mode: absolute (HRTIMER_MODE_ABS) or + * relative (HRTIMER_MODE_REL), and pinned (HRTIMER_MODE_PINNED); + * softirq based mode is considered for debug purpose only! + */ +static inline void hrtimer_start(struct hrtimer *timer, ktime_t tim, + const enum hrtimer_mode mode) +{ + hrtimer_start_range_ns(timer, tim, 0, mode); +} + +extern int hrtimer_cancel(struct hrtimer *timer); +extern int hrtimer_try_to_cancel(struct hrtimer *timer); + +static inline void hrtimer_start_expires(struct hrtimer *timer, enum hrtimer_mode mode) +{ + ktime_t soft, hard; + u64 delta; + + soft = hrtimer_get_softexpires(timer); + hard = hrtimer_get_expires(timer); + delta = ktime_to_ns(ktime_sub(hard, soft)); + hrtimer_start_range_ns(timer, soft, delta, mode); +} + +static inline bool hrtimer_start_expires_user(struct hrtimer *timer, enum hrtimer_mode mode) +{ + ktime_t soft, hard; + u64 delta; + + soft = hrtimer_get_softexpires(timer); + hard = hrtimer_get_expires(timer); + delta = ktime_to_ns(ktime_sub(hard, soft)); + return hrtimer_start_range_ns_user(timer, soft, delta, mode); +} + +void hrtimer_sleeper_start_expires(struct hrtimer_sleeper *sl, + enum hrtimer_mode mode); + +static inline void hrtimer_restart(struct hrtimer *timer) +{ + hrtimer_start_expires(timer, HRTIMER_MODE_ABS); +} + +/* Query timers: */ +extern ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust); + +/** + * hrtimer_get_remaining - get remaining time for the timer + * @timer: the timer to read + */ +static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer) +{ + return __hrtimer_get_remaining(timer, false); +} + +extern ktime_t hrtimer_get_next_event(void); +extern ktime_t hrtimer_next_event_without(const struct hrtimer *exclude); + +extern bool hrtimer_active(const struct hrtimer *timer); + +/** + * hrtimer_is_queued - check, whether the timer is on one of the queues + * @timer: Timer to check + * + * Returns: True if the timer is queued, false otherwise + * + * The function can be used lockless, but it gives only a current snapshot. + */ +static inline bool hrtimer_is_queued(struct hrtimer *timer) +{ + /* The READ_ONCE pairs with the update functions of timer->is_queued */ + return READ_ONCE(timer->is_queued); +} + +void hrtimer_update_function(struct hrtimer *timer, + enum hrtimer_restart (*function)(struct hrtimer *)); + +/* Forward a hrtimer so it expires after now: */ +extern u64 +hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); + +/** + * hrtimer_forward_now() - forward the timer expiry so it expires after now + * @timer: hrtimer to forward + * @interval: the interval to forward + * + * It is a variant of hrtimer_forward(). The timer will expire after the current + * time of the hrtimer clock base. See hrtimer_forward() for details. + */ +static inline u64 hrtimer_forward_now(struct hrtimer *timer, + ktime_t interval) +{ + return hrtimer_forward(timer, hrtimer_cb_get_time(timer), interval); +} + +/* Precise sleep: */ + +extern int nanosleep_copyout(struct restart_block *, struct timespec64 *); +extern long hrtimer_nanosleep(ktime_t rqtp, const enum hrtimer_mode mode, + const clockid_t clockid); + +extern int schedule_hrtimeout_range(ktime_t *expires, u64 delta, + const enum hrtimer_mode mode); +extern int schedule_hrtimeout_range_clock(ktime_t *expires, + u64 delta, + const enum hrtimer_mode mode, + clockid_t clock_id); +extern int schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode); + +/* Soft interrupt function to run the hrtimer queues: */ +extern void hrtimer_run_queues(void); + +/* Bootup initialization: */ +extern void __init hrtimers_init(void); + +/* Show pending timers: */ +extern void sysrq_timer_list_show(void); + +int hrtimers_prepare_cpu(unsigned int cpu); +int hrtimers_cpu_starting(unsigned int cpu); +#ifdef CONFIG_HOTPLUG_CPU +int hrtimers_cpu_dying(unsigned int cpu); +#else +#define hrtimers_cpu_dying NULL +#endif + +#endif |
