* [PATCH] hrtimers: teach usleep_range() to return how many usecs was slept
@ 2012-01-16 12:53 Dmitry Antipov
2012-01-26 9:05 ` Andrew Morton
0 siblings, 1 reply; 2+ messages in thread
From: Dmitry Antipov @ 2012-01-16 12:53 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: linux-kernel, patches, Dmitry Antipov
Teach usleep_range() to return how many usecs was actually spent
in sleep. The rationale beyond this is to convert jiffies-based
wait-for-hardware loops like:
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(1000, 2000);
}
Signed-off-by: Dmitry Antipov <dmitry.antipov@linaro.org>
---
fs/eventpoll.c | 2 +-
fs/select.c | 2 +-
include/linux/delay.h | 2 +-
include/linux/hrtimer.h | 9 ++++++---
ipc/mqueue.c | 2 +-
kernel/hrtimer.c | 28 ++++++++++++++++++++++++----
kernel/timer.c | 12 ++++++++----
7 files changed, 42 insertions(+), 15 deletions(-)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index aabdfc3..7a957fd 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1349,7 +1349,7 @@ fetch_events:
}
spin_unlock_irqrestore(&ep->lock, flags);
- if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
+ if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS, NULL))
timed_out = 1;
spin_lock_irqsave(&ep->lock, flags);
diff --git a/fs/select.c b/fs/select.c
index d33418f..eceb573 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -236,7 +236,7 @@ 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, slack, HRTIMER_MODE_ABS, NULL);
__set_current_state(TASK_RUNNING);
/*
diff --git a/include/linux/delay.h b/include/linux/delay.h
index a6ecb34..e512a50 100644
--- a/include/linux/delay.h
+++ b/include/linux/delay.h
@@ -45,7 +45,7 @@ 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);
static inline void ssleep(unsigned int seconds)
{
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index fd0dc30..661dd25 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -128,6 +128,7 @@ struct hrtimer {
struct hrtimer_sleeper {
struct hrtimer timer;
struct task_struct *task;
+ ktime_t elapsed;
};
/**
@@ -429,9 +430,11 @@ 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,
- unsigned long delta, const enum hrtimer_mode mode, int clock);
+ const enum hrtimer_mode mode,
+ unsigned long *elapsed);
+extern int schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
+ const enum hrtimer_mode mode, int clock,
+ unsigned long *elapsed);
extern int schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode);
/* Soft interrupt function to run the hrtimer queues: */
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 9b7c8ab..578cce7 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -450,7 +450,7 @@ static int wq_sleep(struct mqueue_inode_info *info, int sr,
spin_unlock(&info->lock);
time = schedule_hrtimeout_range_clock(timeout, 0,
- HRTIMER_MODE_ABS, CLOCK_REALTIME);
+ HRTIMER_MODE_ABS, CLOCK_REALTIME, NULL);
while (ewp->state == STATE_PENDING)
cpu_relax();
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index ae34bf5..75c9c5c 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->elapsed = ktime_sub(base->get_time(), t->elapsed);
+ 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->elapsed = base->get_time();
+ unlock_hrtimer_base(&sl->timer, &flags);
+
sl->timer.function = hrtimer_wakeup;
sl->task = task;
}
@@ -1750,10 +1763,13 @@ void __init hrtimers_init(void)
* @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
+ * @elapsed: pointer to unsigned long variable where to store
+ * the time actually slept in timeout (usecs)
*/
int __sched
schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
- const enum hrtimer_mode mode, int clock)
+ const enum hrtimer_mode mode, int clock,
+ unsigned long *elapsed)
{
struct hrtimer_sleeper t;
@@ -1787,6 +1803,8 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
if (likely(t.task))
schedule();
+ if (elapsed)
+ *elapsed = ktime_to_us(t.elapsed);
hrtimer_cancel(&t.timer);
destroy_hrtimer_on_stack(&t.timer);
@@ -1800,6 +1818,8 @@ schedule_hrtimeout_range_clock(ktime_t *expires, unsigned long delta,
* @expires: timeout value (ktime_t)
* @delta: slack in expires timeout (ktime_t)
* @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
+ * @elapsed: pointer to unsigned long variable where to store
+ * the time actually slept in timeout (usecs)
*
* Make the current task sleep until the given expiry time has
* elapsed. The routine will return immediately unless
@@ -1824,10 +1844,10 @@ 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,
- const enum hrtimer_mode mode)
+ const enum hrtimer_mode mode, unsigned long *elapsed)
{
return schedule_hrtimeout_range_clock(expires, delta, mode,
- CLOCK_MONOTONIC);
+ CLOCK_MONOTONIC, elapsed);
}
EXPORT_SYMBOL_GPL(schedule_hrtimeout_range);
@@ -1856,6 +1876,6 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout_range);
int __sched schedule_hrtimeout(ktime_t *expires,
const enum hrtimer_mode mode)
{
- return schedule_hrtimeout_range(expires, 0, mode);
+ return schedule_hrtimeout_range(expires, 0, mode, NULL);
}
EXPORT_SYMBOL_GPL(schedule_hrtimeout);
diff --git a/kernel/timer.c b/kernel/timer.c
index a297ffc..aaad2b8 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1819,14 +1819,15 @@ unsigned long msleep_interruptible(unsigned int msecs)
EXPORT_SYMBOL(msleep_interruptible);
-static int __sched do_usleep_range(unsigned long min, unsigned long max)
+static int __sched do_usleep_range(unsigned long min, unsigned long max,
+ unsigned long *elapsed)
{
ktime_t kmin;
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, delta, HRTIMER_MODE_REL, elapsed);
}
/**
@@ -1834,9 +1835,12 @@ 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)
{
+ unsigned long elapsed;
+
__set_current_state(TASK_UNINTERRUPTIBLE);
- do_usleep_range(min, max);
+ do_usleep_range(min, max, &elapsed);
+ return elapsed;
}
EXPORT_SYMBOL(usleep_range);
--
1.7.7.5
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] hrtimers: teach usleep_range() to return how many usecs was slept
2012-01-16 12:53 [PATCH] hrtimers: teach usleep_range() to return how many usecs was slept Dmitry Antipov
@ 2012-01-26 9:05 ` Andrew Morton
0 siblings, 0 replies; 2+ messages in thread
From: Andrew Morton @ 2012-01-26 9:05 UTC (permalink / raw)
To: Dmitry Antipov; +Cc: Thomas Gleixner, linux-kernel, patches
On Mon, 16 Jan 2012 16:53:23 +0400 Dmitry Antipov <dmitry.antipov@linaro.org> wrote:
> Teach usleep_range() to return how many usecs was actually spent
> in sleep. The rationale beyond this is to convert jiffies-based
> wait-for-hardware loops like:
>
> 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(1000, 2000);
> }
>
Is that useful enough to justify making the change?
>
> int __sched schedule_hrtimeout_range(ktime_t *expires, unsigned long delta,
> - const enum hrtimer_mode mode)
> + const enum hrtimer_mode mode, unsigned long *elapsed)
Rather than adding another argument, I suggest you change the return
type to long and use return value semantics similar to schedule_timeout().
schedule_timeout() never returns -ve numbers and it returns jiffies,
but it will be close(r).
Returning usecs is odd. One would expect it to return a ktime_t. That
might inflict some code-size cost in callers.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2012-01-26 8:59 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-16 12:53 [PATCH] hrtimers: teach usleep_range() to return how many usecs was slept Dmitry Antipov
2012-01-26 9:05 ` Andrew Morton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.