timer changes for v2.6.38
Subsystems (4)
Linus,
Please pull the latest timers-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git timers-for-linus
Thanks,
Ingo
------------------>
Changli Gao (1):
timer: Initialize the field slack of timer_list
Christoph Lameter (1):
timers: Use this_cpu_read
John Stultz (5):
timers: Introduce timerlist infrastructure.
timers: Rename timerlist infrastructure to timerqueue
timers: Fixup allmodconfig build issue
hrtimers: Convert hrtimers to use timerlist infrastructure
hrtimer: fix timerqueue conversion flub
Kasper Pedersen (1):
time: Compensate for rounding on odd-frequency clocksources
Namhyung Kim (1):
posix-timers: Annotate lock_timer()
Nikitas Angelinas (1):
time: Use ARRAY_SIZE macro in timecompare.c
Phil Carmody (1):
timer: Permit statically-declared work with deferrable timers
Richard Kennedy (1):
timer_list: Remove alignment padding on 64 bit when CONFIG_TIMER_STATS
Thomas Gleixner (2):
timerqueue: Make timerqueue_getnext() static inline
MAINTAINERS: Update timer related entries
Yong Zhang (4):
timer: Make try_to_del_timer_sync() the same on SMP and UP
timer: Del_timer_sync() can be used in softirq context
timer: Warn when del_timer_sync() is called in hardirq context
hrtimer: Remove stale comment on curr_timer
MAINTAINERS | 16 +++++++ include/linux/hrtimer.h | 33 ++++++------- include/linux/timer.h | 32 ++++++++++++- include/linux/timerqueue.h | 50 ++++++++++++++++++++ include/linux/workqueue.h | 8 +++ kernel/hrtimer.c | 83 +++++++++++----------------------- kernel/posix-timers.c | 10 +++- kernel/time/timecompare.c | 5 +- kernel/time/timekeeping.c | 9 +++- kernel/time/timer_list.c | 8 ++-- kernel/timer.c | 50 ++++++--------------- lib/Makefile | 2 +- lib/timerqueue.c | 107 ++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 289 insertions(+), 124 deletions(-) create mode 100644 include/linux/timerqueue.h create mode 100644 lib/timerqueue.c
MAINTAINERS +16 -0
@@ -2730,6 +2730,10 @@ M: Thomas Gleixner <[email protected]> S: Maintained F: Documentation/timers/ F: kernel/hrtimer.c +F: kernel/time/clockevents.c +F: kernel/time/tick*.* +F: kernel/time/timer_*.c +F include/linux/clockevents.h F: include/linux/hrtimer.h HIGH-SPEED SCC DRIVER FOR AX.25
@@ -4986,6 +4990,18 @@ F: drivers/media/common/saa7146* F: drivers/media/video/*7146* F: include/media/*7146* +TIMEKEEPING, NTP +M: John Stultz <[email protected]> +M: Thomas Gleixner <[email protected]> +S: Supported +F: include/linux/clocksource.h +F: include/linux/time.h +F: include/linux/timex.h +F: include/linux/timekeeping.h +F: kernel/time/clocksource.c +F: kernel/time/time*.c +F: kernel/time/ntp.c + TLG2300 VIDEO4LINUX-2 DRIVER M: Huang Shijie <[email protected]> M: Kang Yong <[email protected]>
include/linux/hrtimer.h +15 -18
@@ -22,7 +22,7 @@#include <linux/wait.h> #include <linux/percpu.h> #include <linux/timer.h> - +#include <linux/timerqueue.h> struct hrtimer_clock_base ;struct hrtimer_cpu_base ;
@@ -79,8 +79,8 @@ enum hrtimer_restart {/** * struct hrtimer - the basic hrtimer structure -* @node: red black tree node for time ordered insertion -* @_expires: the absolute expiry time in the hrtimers internal +* @node: timerqueue node, which also manages node.expires, +* the absolute expiry time in the hrtimers internal * representation. The time is related to the clock on * which the timer is based. Is setup by adding * slack to the _softexpires value. For non range timers
@@ -101,8 +101,7 @@ enum hrtimer_restart {* The hrtimer structure must be initialized by hrtimer_init() */ struct hrtimer { -struct rb_node node; -ktime_t _expires; +struct timerqueue_node node;ktime_t _softexpires;enum hrtimer_restart (*function)(struct hrtimer *);struct hrtimer_clock_base *base;
@@ -141,8 +140,7 @@ struct hrtimer_sleeper {struct hrtimer_clock_base {struct hrtimer_cpu_base *cpu_base;clockid_t index; -struct rb_root active; -struct rb_node *first; +struct timerqueue_head active;ktime_t resolution;ktime_t (*get_time)(void );ktime_t softirq_time;
@@ -158,7 +156,6 @@ struct hrtimer_clock_base {* @lock: lock protecting the base and associated clock bases * and timers * @clock_base: array of clock bases for this cpu -* @curr_timer: the timer which is executing a callback right now * @expires_next: absolute time of the next event which was scheduled * via clock_set_next_event() * @hres_active: State of high resolution mode
@@ -184,43 +181,43 @@ struct hrtimer_cpu_base {static inline void hrtimer_set_expires (struct hrtimer *timer,ktime_t time) { - timer->_expires = 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->_expires =ktime_add_safe (time, delta); + timer->node.expires =ktime_add_safe (time, delta); }static inline void hrtimer_set_expires_range_ns (struct hrtimer *timer,ktime_t time,unsigned long delta) { timer->_softexpires = time; - timer->_expires =ktime_add_safe (time,ns_to_ktime (delta)); + timer->node.expires =ktime_add_safe (time,ns_to_ktime (delta)); }static inline void hrtimer_set_expires_tv64 (struct hrtimer *timer,s64 tv64) { - timer->_expires.tv64 = tv64; + timer->node.expires.tv64 = tv64; timer->_softexpires.tv64 = tv64; }static inline void hrtimer_add_expires (struct hrtimer *timer,ktime_t time) { - timer->_expires =ktime_add_safe (timer->_expires, 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->_expires =ktime_add_ns (timer->_expires, 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->_expires; +return timer->node.expires; }static inline ktime_t hrtimer_get_softexpires (const struct hrtimer *timer)
@@ -230,7 +227,7 @@ static inline ktime_t hrtimer_get_softexpires(const struct hrtimer *timer)static inline s64 hrtimer_get_expires_tv64 (const struct hrtimer *timer) { -return timer->_expires.tv64; +return timer->node.expires.tv64; }static inline s64 hrtimer_get_softexpires_tv64 (const struct hrtimer *timer) {
@@ -239,12 +236,12 @@ static inline s64 hrtimer_get_softexpires_tv64(const struct hrtimer *timer)static inline s64 hrtimer_get_expires_ns (const struct hrtimer *timer) { -return ktime_to_ns (timer->_expires); +return ktime_to_ns (timer->node.expires); }static inline ktime_t hrtimer_expires_remaining (const struct hrtimer *timer) { -return ktime_sub (timer->_expires, timer->base->get_time ()); +return ktime_sub (timer->node.expires, timer->base->get_time ()); }#ifdef CONFIG_HIGH_RES_TIMERS
include/linux/timer.h +29 -3
@@ -24,9 +24,9 @@ struct timer_list {int slack;#ifdef CONFIG_TIMER_STATS +int start_pid;void *start_site;char start_comm[16 ]; -int start_pid;#endif #ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map;
@@ -48,12 +48,38 @@ extern struct tvec_base boot_tvec_bases;#define __TIMER_LOCKDEP_MAP_INITIALIZER (_kn)#endif +/* +* Note that all tvec_bases are 2 byte aligned and lower bit of +* base in timer_list is guaranteed to be zero. Use the LSB to +* indicate whether the timer is 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. +*/ +#define TBASE_DEFERRABLE_FLAG (0x1) +#define TIMER_INITIALIZER (_function, _expires, _data) { \ .entry = { .prev = TIMER_ENTRY_STATIC }, \ .function = (_function), \ .expires = (_expires), \ .data = (_data), \ .base = &boot_tvec_bases, \ + .slack = -1, \ + __TIMER_LOCKDEP_MAP_INITIALIZER( \ + __FILE__ ":" __stringify(__LINE__)) \ + } + +#define TBASE_MAKE_DEFERRED (ptr) ((struct tvec_base *) \ + ((unsigned char *)(ptr) + TBASE_DEFERRABLE_FLAG)) + +#define TIMER_DEFERRED_INITIALIZER (_function, _expires, _data) {\ + .entry = { .prev = TIMER_ENTRY_STATIC }, \ + .function = (_function), \ + .expires = (_expires), \ + .data = (_data), \ + .base = TBASE_MAKE_DEFERRED(&boot_tvec_bases), \ __TIMER_LOCKDEP_MAP_INITIALIZER( \ __FILE__ ":" __stringify(__LINE__)) \ }
@@ -248,11 +274,11 @@ static inline void timer_stats_timer_clear_start_info(struct timer_list *timer)extern void add_timer (struct timer_list *timer); +extern int try_to_del_timer_sync (struct timer_list *timer); +#ifdef CONFIG_SMP -extern int try_to_del_timer_sync (struct timer_list *timer);extern int del_timer_sync (struct timer_list *timer);#else -# define try_to_del_timer_sync (t) del_timer(t)# define del_timer_sync (t) del_timer(t)#endif
include/linux/timerqueue.h new file +50 -0
50 lines not on this page · raw message
include/linux/workqueue.h +8 -0
@@ -127,12 +127,20 @@ struct execute_work { .timer = TIMER_INITIALIZER(NULL, 0, 0), \ } +#define __DEFERRED_WORK_INITIALIZER (n, f) { \ + .work = __WORK_INITIALIZER((n).work, (f)), \ + .timer = TIMER_DEFERRED_INITIALIZER(NULL, 0, 0), \ + } +#define DECLARE_WORK (n, f) \ struct work_struct n = __WORK_INITIALIZER(n, f)#define DECLARE_DELAYED_WORK (n, f) \ struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f) +#define DECLARE_DEFERRED_WORK (n, f) \ + struct delayed_work n = __DEFERRED_WORK_INITIALIZER(n, f) +/* * initialize a work item's function pointer */
kernel/hrtimer.c +27 -56
178 lines not on this page · raw message
kernel/posix-timers.c +8 -2
@@ -145,7 +145,13 @@ static int common_timer_del(struct k_itimer *timer);static enum hrtimer_restart posix_timer_fn (struct hrtimer *data); -static struct k_itimer *lock_timer (timer_t timer_id,unsigned long *flags); +static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags); + +#define lock_timer (tid, flags) \ +({ struct k_itimer *__timr; \ + __cond_lock(&__timr->it_lock, __timr = __lock_timer(tid, flags)); \ + __timr; \ +})static inline void unlock_timer (struct k_itimer *timr,unsigned long flags) {
@@ -619,7 +625,7 @@ out:* the find to the timer lock. To avoid a dead lock, the timer id MUST * be release with out holding the timer lock. */ -static struct k_itimer *lock_timer (timer_t timer_id,unsigned long *flags) +static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags) {struct k_itimer *timr;/*
kernel/time/timecompare.c +3 -2
@@ -21,6 +21,7 @@#include <linux/module.h> #include <linux/slab.h> #include <linux/math64.h> +#include <linux/kernel.h> /* * fixed point arithmetic scale factor for skew
@@ -57,11 +58,11 @@ int timecompare_offset(struct timecompare *sync,int index;int num_samples = sync->num_samples; -if (num_samples >sizeof (buffer)/sizeof (buffer[0 ])) { +if (num_samples >ARRAY_SIZE (buffer)) { samples =kmalloc (sizeof (*samples) * num_samples,GFP_ATOMIC );if (!samples) { samples = buffer; - num_samples =sizeof (buffer)/sizeof (buffer[0 ]); + num_samples =ARRAY_SIZE (buffer); } }else { samples = buffer;
kernel/time/timekeeping.c +7 -2
@@ -32,6 +32,8 @@ struct timekeeper {cycle_t cycle_interval;/* Number of clock shifted nano seconds in one NTP interval. */ u64 xtime_interval; +/* shifted nano seconds left over when rounding cycle_interval */ +s64 xtime_remainder;/* Raw nano seconds accumulated per NTP interval. */ u32 raw_interval;
@@ -62,7 +64,7 @@ struct timekeeper timekeeper;static void timekeeper_setup_internals (struct clocksource *clock) {cycle_t interval; -u64 tmp; +u64 tmp, ntpinterval; timekeeper.clock = clock; clock->cycle_last = clock->read (clock);
@@ -70,6 +72,7 @@ static void timekeeper_setup_internals(struct clocksource *clock)/* Do the ns -> cycle conversion first, using original mult */ tmp =NTP_INTERVAL_LENGTH ; tmp <<= clock->shift; + ntpinterval = tmp; tmp += clock->mult/2 ;do_div (tmp, clock->mult);if (tmp ==0 )
@@ -80,6 +83,7 @@ static void timekeeper_setup_internals(struct clocksource *clock)/* Go back from cycles -> shifted ns */ timekeeper.xtime_interval = (u64 ) interval * clock->mult; + timekeeper.xtime_remainder = ntpinterval - timekeeper.xtime_interval; timekeeper.raw_interval = ((u64 ) interval * clock->mult) >> clock->shift;
@@ -719,7 +723,8 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)/* Accumulate error between NTP and clock interval */ timekeeper.ntp_error += tick_length << shift; - timekeeper.ntp_error -= timekeeper.xtime_interval << + timekeeper.ntp_error -= + (timekeeper.xtime_interval + timekeeper.xtime_remainder) << (timekeeper.ntp_error_shift + shift);return offset;
kernel/time/timer_list.c +4 -4
@@ -79,26 +79,26 @@ print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, {struct hrtimer *timer, tmp;unsigned long next =0 , i; -struct rb_node *curr; +struct timerqueue_node *curr;unsigned long flags; next_one: i =0 ;raw_spin_lock_irqsave (&base->cpu_base->lock, flags); - curr = base->first; + curr =timerqueue_getnext (&base->active);/* * Crude but we have to do this O(N*N) thing, because * we have to unlock the base when printing: */ while (curr && i < next) { - curr =rb_next (curr); + curr =timerqueue_iterate_next (curr); i++; }if (curr) { - timer = rb_entry(curr, struct hrtimer, node); + timer = container_of(curr, struct hrtimer, node); tmp = *timer;raw_spin_unlock_irqrestore (&base->cpu_base->lock, flags);
kernel/timer.c +14 -36
125 lines not on this page · raw message
lib/Makefile +1 -1
@@ -8,7 +8,7 @@ KBUILD_CFLAGS = $(subst -pg,,$(ORIG_CFLAGS)) endif lib-y := ctype.o string.o vsprintf.o cmdline.o \ - rbtree.o radix-tree.o dump_stack.o \ + rbtree.o radix-tree.o dump_stack.o timerqueue.o\ idr.o int_sqrt.o extable.o prio_tree.o \ sha1.o irq_regs.o reciprocal_div.o argv_split.o \ proportions.o prio_heap.o ratelimit.o show_mem.o \
lib/timerqueue.c new file +107 -0
107 lines not on this page · raw message