lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 23 Jan 2012 19:40:58 +0400
From:	Dmitry Antipov <dmitry.antipov@...aro.org>
To:	Steve Glendinning <steve.glendinning@...c.com>
Cc:	linux-kernel@...r.kernel.org, linaro-dev@...ts.linaro.org,
	patches@...aro.org, Dmitry Antipov <dmitry.antipov@...aro.org>
Subject: [PATCH] hrtimers, timers: eliminate some jiffies-backed code

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@...aro.org>
---
 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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ