From 288867ec5c377db82933b64460ce050e5c998ee9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 12 Jan 2006 11:25:54 +0100 Subject: [hrtimer] Remove listhead from hrtimer struct The list_head in the hrtimer structure was introduced for easy access to the first timer with the further extensions of real high resolution timers in mind, but it turned out in the course of development that it is not necessary for the standard use case. Remove the list head and access the first expiry timer by a datafield in the timer base. Signed-off-by: Thomas Gleixner --- kernel/hrtimer.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'kernel') diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index f073a2461faa0..e6e8278bcb181 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -314,7 +314,6 @@ hrtimer_forward(struct hrtimer *timer, const ktime_t interval) static void enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) { struct rb_node **link = &base->active.rb_node; - struct list_head *prev = &base->pending; struct rb_node *parent = NULL; struct hrtimer *entry; @@ -330,22 +329,23 @@ static void enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) */ if (timer->expires.tv64 < entry->expires.tv64) link = &(*link)->rb_left; - else { + else link = &(*link)->rb_right; - prev = &entry->list; - } } /* - * Insert the timer to the rbtree and to the sorted list: + * Insert the timer to the rbtree and check whether it + * replaces the first pending timer */ rb_link_node(&timer->node, parent, link); rb_insert_color(&timer->node, &base->active); - list_add(&timer->list, prev); timer->state = HRTIMER_PENDING; -} + if (!base->first || timer->expires.tv64 < + rb_entry(base->first, struct hrtimer, node)->expires.tv64) + base->first = &timer->node; +} /* * __remove_hrtimer - internal function to remove a timer @@ -355,9 +355,11 @@ static void enqueue_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_base *base) { /* - * Remove the timer from the sorted list and from the rbtree: + * Remove the timer from the rbtree and replace the + * first entry pointer if necessary. */ - list_del(&timer->list); + if (base->first == &timer->node) + base->first = rb_next(&timer->node); rb_erase(&timer->node, &base->active); } @@ -529,16 +531,17 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) static inline void run_hrtimer_queue(struct hrtimer_base *base) { ktime_t now = base->get_time(); + struct rb_node *node; spin_lock_irq(&base->lock); - while (!list_empty(&base->pending)) { + while ((node = base->first)) { struct hrtimer *timer; int (*fn)(void *); int restart; void *data; - timer = list_entry(base->pending.next, struct hrtimer, list); + timer = rb_entry(node, struct hrtimer, node); if (now.tv64 <= timer->expires.tv64) break; @@ -732,7 +735,6 @@ static void __devinit init_hrtimers_cpu(int cpu) for (i = 0; i < MAX_HRTIMER_BASES; i++) { spin_lock_init(&base->lock); - INIT_LIST_HEAD(&base->pending); base++; } } -- cgit 1.2.3-korg From e2787630c1abb075c935cf47e91beb7c656f48c4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 12 Jan 2006 11:36:14 +0100 Subject: [hrtimer] Change resolution storage to ktime_t format Change the storage format of the per base resolution to ktime_t to make it easier accessible in the hrtimers code. Change the resolution from (NSEC_PER_SEC/HZ) to TICK_NSEC as Roman pointed out. TICK_NSEC is closer to the real resolution. Signed-off-by: Thomas Gleixner --- include/linux/hrtimer.h | 2 +- include/linux/ktime.h | 4 ++-- kernel/hrtimer.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index abb674c9b7646..98c5c1537b5d7 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -85,7 +85,7 @@ struct hrtimer_base { spinlock_t lock; struct rb_root active; struct rb_node *first; - unsigned long resolution; + ktime_t resolution; ktime_t (*get_time)(void); struct hrtimer *curr_timer; }; diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 222a047cc145e..1bd6552cc3413 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -272,8 +272,8 @@ static inline u64 ktime_to_ns(const ktime_t kt) * idea of the (in)accuracy of timers. Timer values are rounded up to * this resolution values. */ -#define KTIME_REALTIME_RES (NSEC_PER_SEC/HZ) -#define KTIME_MONOTONIC_RES (NSEC_PER_SEC/HZ) +#define KTIME_REALTIME_RES (ktime_t){ .tv64 = TICK_NSEC } +#define KTIME_MONOTONIC_RES (ktime_t){ .tv64 = TICK_NSEC } /* Get the monotonic time in timespec format: */ extern void ktime_get_ts(struct timespec *ts); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index e6e8278bcb181..76d759ce62316 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -518,9 +518,8 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) { struct hrtimer_base *bases; - tp->tv_sec = 0; bases = per_cpu(hrtimer_bases, raw_smp_processor_id()); - tp->tv_nsec = bases[which_clock].resolution; + *tp = ktime_to_timespec(bases[which_clock].resolution); return 0; } -- cgit 1.2.3-korg From c9db4fa11526affde83603fe52595bd1260c1354 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 12 Jan 2006 11:47:34 +0100 Subject: [hrtimer] Enforce resolution as lower limit of intervals Roman Zippel pointed out that the missing lower limit of intervals leads to an accounting error in the overrun count. Enforce the lower limit of intervals to resolution in the timer forwarding code. Signed-off-by: Thomas Gleixner --- include/linux/hrtimer.h | 3 +-- kernel/hrtimer.c | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'kernel') diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 98c5c1537b5d7..089bfb1fa01a7 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -122,8 +122,7 @@ static inline int hrtimer_active(const struct hrtimer *timer) } /* Forward a hrtimer so it expires after now: */ -extern unsigned long hrtimer_forward(struct hrtimer *timer, - const ktime_t interval); +extern unsigned long hrtimer_forward(struct hrtimer *timer, ktime_t interval); /* Precise sleep: */ extern long hrtimer_nanosleep(struct timespec *rqtp, diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 76d759ce62316..04ccab099e84e 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -275,7 +275,7 @@ void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) * The number of overruns is added to the overrun field. */ unsigned long -hrtimer_forward(struct hrtimer *timer, const ktime_t interval) +hrtimer_forward(struct hrtimer *timer, ktime_t interval) { unsigned long orun = 1; ktime_t delta, now; @@ -287,6 +287,9 @@ hrtimer_forward(struct hrtimer *timer, const ktime_t interval) if (delta.tv64 < 0) return 0; + if (interval.tv64 < timer->base->resolution.tv64) + interval.tv64 = timer->base->resolution.tv64; + if (unlikely(delta.tv64 >= interval.tv64)) { nsec_t incr = ktime_to_ns(interval); -- cgit 1.2.3-korg