diff options
Diffstat (limited to 'include/linux/timer.h')
| -rw-r--r-- | include/linux/timer.h | 273 |
1 files changed, 103 insertions, 170 deletions
diff --git a/include/linux/timer.h b/include/linux/timer.h index 8c5a197e1587..62e1cea71125 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_TIMER_H #define _LINUX_TIMER_H @@ -6,34 +7,7 @@ #include <linux/stddef.h> #include <linux/debugobjects.h> #include <linux/stringify.h> - -struct tvec_base; - -struct timer_list { - /* - * All fields that change during normal runtime grouped to the - * same cacheline - */ - struct list_head entry; - unsigned long expires; - struct tvec_base *base; - - void (*function)(unsigned long); - unsigned long data; - - int slack; - -#ifdef CONFIG_TIMER_STATS - int start_pid; - void *start_site; - char start_comm[16]; -#endif -#ifdef CONFIG_LOCKDEP - struct lockdep_map lockdep_map; -#endif -}; - -extern struct tvec_base boot_tvec_bases; +#include <linux/timer_types.h> #ifdef CONFIG_LOCKDEP /* @@ -49,112 +23,114 @@ extern struct tvec_base boot_tvec_bases; #endif /* - * Note that all tvec_bases are at least 4 byte aligned and lower two bits - * of base in timer_list is guaranteed to be zero. Use them for flags. + * @TIMER_DEFERRABLE: A deferrable timer will work normally when the + * system is busy, but will not cause a CPU to come out of idle just + * to service it; instead, the timer will be serviced when the CPU + * eventually wakes up with a subsequent non-deferrable timer. * - * A deferrable timer will work normally when the system is busy, but - * will not cause a CPU to come out of idle just to service it; instead, - * the timer will be serviced when the CPU eventually wakes up with a - * subsequent non-deferrable timer. - * - * An irqsafe timer is executed with IRQ disabled and it's safe to wait for - * the completion of the running instance from IRQ handlers, for example, - * by calling del_timer_sync(). + * @TIMER_IRQSAFE: An irqsafe timer is executed with IRQ disabled and + * it's safe to wait for the completion of the running instance from + * IRQ handlers, for example, by calling timer_delete_sync(). * * Note: The irq disabled callback execution is a special case for * workqueue locking issues. It's not meant for executing random crap * with interrupts disabled. Abuse is monitored! + * + * @TIMER_PINNED: A pinned timer will always expire on the CPU on which the + * timer was enqueued. When a particular CPU is required, add_timer_on() + * has to be used. Enqueue via mod_timer() and add_timer() is always done + * on the local CPU. */ -#define TIMER_DEFERRABLE 0x1LU -#define TIMER_IRQSAFE 0x2LU - -#define TIMER_FLAG_MASK 0x3LU - -#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ - .entry = { .prev = TIMER_ENTRY_STATIC }, \ +#define TIMER_CPUMASK 0x0003FFFF +#define TIMER_MIGRATING 0x00040000 +#define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING) +#define TIMER_DEFERRABLE 0x00080000 +#define TIMER_PINNED 0x00100000 +#define TIMER_IRQSAFE 0x00200000 +#define TIMER_INIT_FLAGS (TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE) +#define TIMER_ARRAYSHIFT 22 +#define TIMER_ARRAYMASK 0xFFC00000 + +#define TIMER_TRACE_FLAGMASK (TIMER_MIGRATING | TIMER_DEFERRABLE | TIMER_PINNED | TIMER_IRQSAFE) + +#define __TIMER_INITIALIZER(_function, _flags) { \ + .entry = { .next = TIMER_ENTRY_STATIC }, \ .function = (_function), \ - .expires = (_expires), \ - .data = (_data), \ - .base = (void *)((unsigned long)&boot_tvec_bases + (_flags)), \ - .slack = -1, \ - __TIMER_LOCKDEP_MAP_INITIALIZER( \ - __FILE__ ":" __stringify(__LINE__)) \ + .flags = (_flags), \ + __TIMER_LOCKDEP_MAP_INITIALIZER(FILE_LINE) \ } -#define TIMER_INITIALIZER(_function, _expires, _data) \ - __TIMER_INITIALIZER((_function), (_expires), (_data), 0) - -#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) \ - __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE) - -#define DEFINE_TIMER(_name, _function, _expires, _data) \ +#define DEFINE_TIMER(_name, _function) \ struct timer_list _name = \ - TIMER_INITIALIZER(_function, _expires, _data) + __TIMER_INITIALIZER(_function, 0) -void init_timer_key(struct timer_list *timer, unsigned int flags, +/* + * LOCKDEP and DEBUG timer interfaces. + */ +void timer_init_key(struct timer_list *timer, + void (*func)(struct timer_list *), unsigned int flags, const char *name, struct lock_class_key *key); #ifdef CONFIG_DEBUG_OBJECTS_TIMERS -extern void init_timer_on_stack_key(struct timer_list *timer, +extern void timer_init_key_on_stack(struct timer_list *timer, + void (*func)(struct timer_list *), unsigned int flags, const char *name, struct lock_class_key *key); -extern void destroy_timer_on_stack(struct timer_list *timer); #else -static inline void destroy_timer_on_stack(struct timer_list *timer) { } -static inline void init_timer_on_stack_key(struct timer_list *timer, - unsigned int flags, const char *name, +static inline void timer_init_key_on_stack(struct timer_list *timer, + void (*func)(struct timer_list *), + unsigned int flags, + const char *name, struct lock_class_key *key) { - init_timer_key(timer, flags, name, key); + timer_init_key(timer, func, flags, name, key); } #endif #ifdef CONFIG_LOCKDEP -#define __init_timer(_timer, _flags) \ +#define __timer_init(_timer, _fn, _flags) \ do { \ static struct lock_class_key __key; \ - init_timer_key((_timer), (_flags), #_timer, &__key); \ + timer_init_key((_timer), (_fn), (_flags), #_timer, &__key);\ } while (0) -#define __init_timer_on_stack(_timer, _flags) \ +#define __timer_init_on_stack(_timer, _fn, _flags) \ do { \ static struct lock_class_key __key; \ - init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \ + timer_init_key_on_stack((_timer), (_fn), (_flags), \ + #_timer, &__key); \ } while (0) #else -#define __init_timer(_timer, _flags) \ - init_timer_key((_timer), (_flags), NULL, NULL) -#define __init_timer_on_stack(_timer, _flags) \ - init_timer_on_stack_key((_timer), (_flags), NULL, NULL) +#define __timer_init(_timer, _fn, _flags) \ + timer_init_key((_timer), (_fn), (_flags), NULL, NULL) +#define __timer_init_on_stack(_timer, _fn, _flags) \ + timer_init_key_on_stack((_timer), (_fn), (_flags), NULL, NULL) #endif -#define init_timer(timer) \ - __init_timer((timer), 0) -#define init_timer_deferrable(timer) \ - __init_timer((timer), TIMER_DEFERRABLE) -#define init_timer_on_stack(timer) \ - __init_timer_on_stack((timer), 0) +/** + * timer_setup - prepare a timer for first use + * @timer: the timer in question + * @callback: the function to call when timer expires + * @flags: any TIMER_* flags + * + * Regular timer initialization should use either DEFINE_TIMER() above, + * or timer_setup(). For timers on the stack, timer_setup_on_stack() must + * be used and must be balanced with a call to timer_destroy_on_stack(). + */ +#define timer_setup(timer, callback, flags) \ + __timer_init((timer), (callback), (flags)) -#define __setup_timer(_timer, _fn, _data, _flags) \ - do { \ - __init_timer((_timer), (_flags)); \ - (_timer)->function = (_fn); \ - (_timer)->data = (_data); \ - } while (0) +#define timer_setup_on_stack(timer, callback, flags) \ + __timer_init_on_stack((timer), (callback), (flags)) -#define __setup_timer_on_stack(_timer, _fn, _data, _flags) \ - do { \ - __init_timer_on_stack((_timer), (_flags)); \ - (_timer)->function = (_fn); \ - (_timer)->data = (_data); \ - } while (0) +#ifdef CONFIG_DEBUG_OBJECTS_TIMERS +extern void timer_destroy_on_stack(struct timer_list *timer); +#else +static inline void timer_destroy_on_stack(struct timer_list *timer) { } +#endif -#define setup_timer(timer, fn, data) \ - __setup_timer((timer), (fn), (data), 0) -#define setup_timer_on_stack(timer, fn, data) \ - __setup_timer_on_stack((timer), (fn), (data), 0) -#define setup_deferrable_timer_on_stack(timer, fn, data) \ - __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE) +#define timer_container_of(var, callback_timer, timer_fieldname) \ + container_of(callback_timer, typeof(*var), timer_fieldname) /** * timer_pending - is a timer pending? @@ -164,104 +140,61 @@ static inline void init_timer_on_stack_key(struct timer_list *timer, * or not. Callers must ensure serialization wrt. other operations done * to this timer, eg. interrupt contexts, or other CPUs on SMP. * - * return value: 1 if the timer is pending, 0 if not. + * Returns: 1 if the timer is pending, 0 if not. */ static inline int timer_pending(const struct timer_list * timer) { - return timer->entry.next != NULL; + return !hlist_unhashed_lockless(&timer->entry); } extern void add_timer_on(struct timer_list *timer, int cpu); -extern int del_timer(struct timer_list * timer); extern int mod_timer(struct timer_list *timer, unsigned long expires); extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); -extern int mod_timer_pinned(struct timer_list *timer, unsigned long expires); +extern int timer_reduce(struct timer_list *timer, unsigned long expires); -extern void set_timer_slack(struct timer_list *time, int slack_hz); - -#define TIMER_NOT_PINNED 0 -#define TIMER_PINNED 1 /* * The jiffies value which is added to now, when there is no timer * in the timer wheel: */ -#define NEXT_TIMER_MAX_DELTA ((1UL << 30) - 1) - -/* - * Return when the next timer-wheel timeout occurs (in absolute jiffies), - * locks the timer base and does the comparison against the given - * jiffie. - */ -extern unsigned long get_next_timer_interrupt(unsigned long now); - -/* - * Timer-statistics info: - */ -#ifdef CONFIG_TIMER_STATS - -extern int timer_stats_active; - -#define TIMER_STATS_FLAG_DEFERRABLE 0x1 - -extern void init_timer_stats(void); - -extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, - void *timerf, char *comm, - unsigned int timer_flag); - -extern void __timer_stats_timer_set_start_info(struct timer_list *timer, - void *addr); - -static inline void timer_stats_timer_set_start_info(struct timer_list *timer) -{ - if (likely(!timer_stats_active)) - return; - __timer_stats_timer_set_start_info(timer, __builtin_return_address(0)); -} - -static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) -{ - timer->start_site = NULL; -} -#else -static inline void init_timer_stats(void) -{ -} - -static inline void timer_stats_timer_set_start_info(struct timer_list *timer) -{ -} - -static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) -{ -} -#endif +#define TIMER_NEXT_MAX_DELTA ((1UL << 30) - 1) extern void add_timer(struct timer_list *timer); +extern void add_timer_local(struct timer_list *timer); +extern void add_timer_global(struct timer_list *timer); -extern int try_to_del_timer_sync(struct timer_list *timer); - -#ifdef CONFIG_SMP - extern int del_timer_sync(struct timer_list *timer); -#else -# define del_timer_sync(t) del_timer(t) -#endif - -#define del_singleshot_timer_sync(t) del_timer_sync(t) +extern int timer_delete_sync_try(struct timer_list *timer); +extern int timer_delete_sync(struct timer_list *timer); +extern int timer_delete(struct timer_list *timer); +extern int timer_shutdown_sync(struct timer_list *timer); +extern int timer_shutdown(struct timer_list *timer); -extern void init_timers(void); -extern void run_local_timers(void); +extern void timers_init(void); struct hrtimer; extern enum hrtimer_restart it_real_fn(struct hrtimer *); -unsigned long __round_jiffies(unsigned long j, int cpu); unsigned long __round_jiffies_relative(unsigned long j, int cpu); unsigned long round_jiffies(unsigned long j); unsigned long round_jiffies_relative(unsigned long j); -unsigned long __round_jiffies_up(unsigned long j, int cpu); unsigned long __round_jiffies_up_relative(unsigned long j, int cpu); unsigned long round_jiffies_up(unsigned long j); unsigned long round_jiffies_up_relative(unsigned long j); +#ifdef CONFIG_HOTPLUG_CPU +int timers_prepare_cpu(unsigned int cpu); +int timers_dead_cpu(unsigned int cpu); +#else +#define timers_prepare_cpu NULL +#define timers_dead_cpu NULL +#endif + +#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) +extern int tmigr_isolated_exclude_cpumask(struct cpumask *exclude_cpumask); +#else +static inline int tmigr_isolated_exclude_cpumask(struct cpumask *exclude_cpumask) +{ + return 0; +} +#endif + #endif |
