Re: [PATCH] hrtimers, timers: eliminate some jiffies-backed code
From: Amit Kucheria
Date: Mon Jan 23 2012 - 11:57:42 EST
Adding Thomas since he is maintainer of hrtimers and John since he
knows a bit about timekeeping. :)
On Mon, Jan 23, 2012 at 5:40 PM, Dmitry Antipov
<dmitry.antipov@xxxxxxxxxx> wrote:
> This patch provides an attempt to get away from jiffies in msleep()
> and msleep_interruptible() to hrtimers-backed usleep_range() and
> usleep_range_interruptible(). Both of the latter now returns an amount
> of microseconds really spent in sleep; another rationale for this
> was to convert msleep()-based wait-for-hardware loops to usleep_range(),
> like this:
>
> unsigned long timeout = jiffies + msecs_to_jiffies(1000);
> while (hw_is_not_ready()) {
> if (time_after(jiffies, timeout))
> return -ETIMEDOUT;
> msleep(1);
> }
>
> to:
>
> unsigned long timeout = 0;
> while (hw_is_not_ready()) {
> if (timeout > USEC_PER_SEC)
> return -ETIMEDOUT;
> timeout += usleep_range(500, 1500);
> }
>
> Signed-off-by: Dmitry Antipov <dmitry.antipov@xxxxxxxxxx>
> ---
> fs/eventpoll.c | 3 ++-
> fs/select.c | 3 ++-
> include/linux/delay.h | 3 ++-
> include/linux/hrtimer.h | 8 +++++---
> ipc/mqueue.c | 4 ++--
> kernel/hrtimer.c | 38 +++++++++++++++++++++++++++++++-------
> kernel/timer.c | 39 +++++++++++++++++++++++++--------------
> 7 files changed, 69 insertions(+), 29 deletions(-)
>
> diff --git a/fs/eventpoll.c b/fs/eventpoll.c
> index aabdfc3..a374944 100644
> --- a/fs/eventpoll.c
> +++ b/fs/eventpoll.c
> @@ -1349,7 +1349,8 @@ fetch_events:
> }
>
> spin_unlock_irqrestore(&ep->lock, flags);
> - if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
> + if (!schedule_hrtimeout_range(to, NULL, slack,
> + HRTIMER_MODE_ABS))
> timed_out = 1;
>
> spin_lock_irqsave(&ep->lock, flags);
> diff --git a/fs/select.c b/fs/select.c
> index d33418f..b4354b2 100644
> --- a/fs/select.c
> +++ b/fs/select.c
> @@ -236,7 +236,8 @@ int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
>
> set_current_state(state);
> if (!pwq->triggered)
> - rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
> + rc = schedule_hrtimeout_range(expires, NULL, slack,
> + HRTIMER_MODE_ABS);
> __set_current_state(TASK_RUNNING);
>
> /*
> diff --git a/include/linux/delay.h b/include/linux/delay.h
> index a6ecb34..bad6d49 100644
> --- a/include/linux/delay.h
> +++ b/include/linux/delay.h
> @@ -45,7 +45,8 @@ extern unsigned long lpj_fine;
> void calibrate_delay(void);
> void msleep(unsigned int msecs);
> unsigned long msleep_interruptible(unsigned int msecs);
> -void usleep_range(unsigned long min, unsigned long max);
> +unsigned long usleep_range(unsigned long min, unsigned long max);
> +unsigned long usleep_range_interruptible(unsigned long min, unsigned long max);
>
> static inline void ssleep(unsigned int seconds)
> {
> diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
> index fd0dc30..01d782b 100644
> --- a/include/linux/hrtimer.h
> +++ b/include/linux/hrtimer.h
> @@ -126,6 +126,7 @@ struct hrtimer {
> * task is set to NULL, when the timer expires.
> */
> struct hrtimer_sleeper {
> + ktime_t kt;
> struct hrtimer timer;
> struct task_struct *task;
> };
> @@ -428,9 +429,10 @@ extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
> extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
> struct task_struct *tsk);
>
> -extern int schedule_hrtimeout_range(ktime_t *expires, unsigned long delta,
> - const enum hrtimer_mode mode);
> -extern int schedule_hrtimeout_range_clock(ktime_t *expires,
> +extern int schedule_hrtimeout_range(ktime_t *expires, ktime_t *elapsed,
> + unsigned long delta,
> + const enum hrtimer_mode mode);
> +extern int schedule_hrtimeout_range_clock(ktime_t *expires, ktime_t *elapsed,
> unsigned long delta, const enum hrtimer_mode mode, int clock);
> extern int schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode);
>
> diff --git a/ipc/mqueue.c b/ipc/mqueue.c
> index 9b7c8ab..e57d7c1 100644
> --- a/ipc/mqueue.c
> +++ b/ipc/mqueue.c
> @@ -449,8 +449,8 @@ static int wq_sleep(struct mqueue_inode_info *info, int sr,
> set_current_state(TASK_INTERRUPTIBLE);
>
> spin_unlock(&info->lock);
> - time = schedule_hrtimeout_range_clock(timeout, 0,
> - HRTIMER_MODE_ABS, CLOCK_REALTIME);
> + time = schedule_hrtimeout_range_clock(timeout, NULL,
> + 0, HRTIMER_MODE_ABS, CLOCK_REALTIME);
>
> while (ewp->state == STATE_PENDING)
> cpu_relax();
> diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
> index ae34bf5..8642c3f 100644
> --- a/kernel/hrtimer.c
> +++ b/kernel/hrtimer.c
> @@ -1475,6 +1475,12 @@ 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;
> + struct hrtimer_clock_base *base;
> + unsigned long flags;
> +
> + base = lock_hrtimer_base(timer, &flags);
> + t->kt = ktime_sub(base->get_time(), t->kt);
> + unlock_hrtimer_base(timer, &flags);
>
> t->task = NULL;
> if (task)
> @@ -1485,6 +1491,13 @@ static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer)
>
> void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
> {
> + struct hrtimer_clock_base *base;
> + unsigned long flags;
> +
> + base = lock_hrtimer_base(&sl->timer, &flags);
> + sl->kt = base->get_time();
> + unlock_hrtimer_base(&sl->timer, &flags);
> +
> sl->timer.function = hrtimer_wakeup;
> sl->task = task;
> }
> @@ -1747,12 +1760,14 @@ void __init hrtimers_init(void)
> /**
> * schedule_hrtimeout_range_clock - sleep until timeout
> * @expires: timeout value (ktime_t)
> + * @elapsed: pointer to ktime_t used to save time spent in sleep
> * @delta: slack in expires timeout (ktime_t)
> * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
> * @clock: timer clock, CLOCK_MONOTONIC or CLOCK_REALTIME
> */
> int __sched
> -schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
> +schedule_hrtimeout_range_clock(ktime_t *expires, ktime_t *elapsed,
> + unsigned long delta,
> const enum hrtimer_mode mode, int clock)
> {
> struct hrtimer_sleeper t;
> @@ -1763,6 +1778,8 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
> */
> if (expires && !expires->tv64) {
> __set_current_state(TASK_RUNNING);
> + if (elapsed)
> + *elapsed = ktime_set(0, 0);
> return 0;
> }
>
> @@ -1772,6 +1789,8 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
> if (!expires) {
> schedule();
> __set_current_state(TASK_RUNNING);
> + if (elapsed)
> + *elapsed = ktime_set(KTIME_SEC_MAX, 0);
> return -EINTR;
> }
>
> @@ -1787,6 +1806,9 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
> if (likely(t.task))
> schedule();
>
> + if (elapsed)
> + *elapsed = t.kt;
> +
> hrtimer_cancel(&t.timer);
> destroy_hrtimer_on_stack(&t.timer);
>
> @@ -1798,6 +1820,7 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
> /**
> * schedule_hrtimeout_range - sleep until timeout
> * @expires: timeout value (ktime_t)
> + * @elapsed: pointer to ktime_t used to save time spent in sleep
> * @delta: slack in expires timeout (ktime_t)
> * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
> *
> @@ -1823,17 +1846,19 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
> *
> * Returns 0 when the timer has expired otherwise -EINTR
> */
> -int __sched schedule_hrtimeout_range(ktime_t *expires, unsigned long delta,
> +int __sched schedule_hrtimeout_range(ktime_t *expires, ktime_t *elapsed,
> + unsigned long delta,
> const enum hrtimer_mode mode)
> {
> - return schedule_hrtimeout_range_clock(expires, delta, mode,
> - CLOCK_MONOTONIC);
> + return schedule_hrtimeout_range_clock(expires, elapsed, delta,
> + mode, CLOCK_MONOTONIC);
> }
> EXPORT_SYMBOL_GPL(schedule_hrtimeout_range);
>
> /**
> * schedule_hrtimeout - sleep until timeout
> * @expires: timeout value (ktime_t)
> + * @elapsed: pointer to ktime_t used to save time spent in sleep
> * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
> *
> * Make the current task sleep until the given expiry time has
> @@ -1853,9 +1878,8 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout_range);
> *
> * Returns 0 when the timer has expired otherwise -EINTR
> */
> -int __sched schedule_hrtimeout(ktime_t *expires,
> - const enum hrtimer_mode mode)
> +int __sched schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode)
> {
> - return schedule_hrtimeout_range(expires, 0, mode);
> + return schedule_hrtimeout_range(expires, NULL, 0, mode);
> }
> EXPORT_SYMBOL_GPL(schedule_hrtimeout);
> diff --git a/kernel/timer.c b/kernel/timer.c
> index a297ffc..00acab6 100644
> --- a/kernel/timer.c
> +++ b/kernel/timer.c
> @@ -1796,12 +1796,12 @@ void __init init_timers(void)
> */
> void msleep(unsigned int msecs)
> {
> - unsigned long timeout = msecs_to_jiffies(msecs) + 1;
> + unsigned long usecs = msecs * USEC_PER_MSEC;
> + unsigned long slack = rt_task(current) ? 0 :
> + current->timer_slack_ns / NSEC_PER_USEC;
>
> - while (timeout)
> - timeout = schedule_timeout_uninterruptible(timeout);
> + usleep_range(usecs, usecs + slack);
> }
> -
> EXPORT_SYMBOL(msleep);
>
> /**
> @@ -1810,23 +1810,27 @@ EXPORT_SYMBOL(msleep);
> */
> unsigned long msleep_interruptible(unsigned int msecs)
> {
> - unsigned long timeout = msecs_to_jiffies(msecs) + 1;
> + unsigned long timeout, usecs, slack;
>
> - while (timeout && !signal_pending(current))
> - timeout = schedule_timeout_interruptible(timeout);
> - return jiffies_to_msecs(timeout);
> -}
> + timeout = 0;
> + usecs = msecs * USEC_PER_MSEC;
> + slack = rt_task(current) ? 0 : current->timer_slack_ns / NSEC_PER_USEC;
>
> + while (timeout < usecs && !signal_pending(current))
> + timeout += usleep_range_interruptible(usecs, usecs + slack);
> + return timeout / USEC_PER_MSEC;
> +}
> EXPORT_SYMBOL(msleep_interruptible);
>
> -static int __sched do_usleep_range(unsigned long min, unsigned long max)
> +static inline unsigned long do_usleep_range(unsigned long min, unsigned long max)
> {
> - ktime_t kmin;
> + ktime_t kmin, elapsed;
> unsigned long delta;
>
> kmin = ktime_set(0, min * NSEC_PER_USEC);
> delta = (max - min) * NSEC_PER_USEC;
> - return schedule_hrtimeout_range(&kmin, delta, HRTIMER_MODE_REL);
> + return schedule_hrtimeout_range(&kmin, &elapsed, delta, HRTIMER_MODE_REL)
> + ? 0 : ktime_to_us(elapsed);
> }
>
> /**
> @@ -1834,9 +1838,16 @@ static int __sched do_usleep_range(unsigned long min, unsigned long max)
> * @min: Minimum time in usecs to sleep
> * @max: Maximum time in usecs to sleep
> */
> -void usleep_range(unsigned long min, unsigned long max)
> +unsigned long usleep_range(unsigned long min, unsigned long max)
> {
> __set_current_state(TASK_UNINTERRUPTIBLE);
> - do_usleep_range(min, max);
> + return do_usleep_range(min, max);
> }
> EXPORT_SYMBOL(usleep_range);
> +
> +unsigned long usleep_range_interruptible(unsigned long min, unsigned long max)
> +{
> + __set_current_state(TASK_INTERRUPTIBLE);
> + return do_usleep_range(min, max);
> +}
> +EXPORT_SYMBOL(usleep_range_interruptible);
> --
> 1.7.7.5
>
>
> _______________________________________________
> linaro-dev mailing list
> linaro-dev@xxxxxxxxxxxxxxxx
> http://lists.linaro.org/mailman/listinfo/linaro-dev
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/