Use hrtimers so that msleep() sleeps for the requested time
Current msleep() snoozes for at least two jiffies, causing msleep(1) to
sleep for at least 20ms on HZ=100 systems. Using hrtimers allows
msleep() to sleep for something much closer to the requested time.
Change-Id: If06b4fa3f489eed073213c763755ec3b387129e1
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
diff --git a/include/linux/delay.h b/include/linux/delay.h
index 0e303d1..08bbc7f 100644
--- a/include/linux/delay.h
+++ b/include/linux/delay.h
@@ -45,6 +45,8 @@
void calibrate_delay(void);
void msleep(unsigned int msecs);
unsigned long msleep_interruptible(unsigned int msecs);
+void hr_msleep(unsigned int msecs);
+unsigned long hr_msleep_interruptible(unsigned int msecs);
void usleep_range(unsigned long min, unsigned long max);
static inline void usleep(unsigned long usecs)
diff --git a/kernel/timer.c b/kernel/timer.c
index 02dbb09..baeca03 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1822,6 +1822,52 @@
EXPORT_SYMBOL(msleep_interruptible);
+static void do_nsleep(unsigned int msecs, struct hrtimer_sleeper *sleeper,
+ int sigs)
+{
+ enum hrtimer_mode mode = HRTIMER_MODE_REL;
+ int state = sigs ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
+
+ hrtimer_init(&sleeper->timer, CLOCK_MONOTONIC, mode);
+ sleeper->timer.node.expires = ktime_set(msecs / 1000,
+ (msecs % 1000) * NSEC_PER_MSEC);
+ hrtimer_init_sleeper(sleeper, current);
+
+ do {
+ set_current_state(state);
+ hrtimer_start(&sleeper->timer, sleeper->timer.node.expires, mode);
+ if (sleeper->task)
+ schedule();
+ hrtimer_cancel(&sleeper->timer);
+ mode = HRTIMER_MODE_ABS;
+ } while (sleeper->task && !(sigs && signal_pending(current)));
+}
+
+void hr_msleep(unsigned int msecs)
+{
+ struct hrtimer_sleeper sleeper;
+
+ do_nsleep(msecs, &sleeper, 0);
+}
+
+EXPORT_SYMBOL(hr_msleep);
+
+unsigned long hr_msleep_interruptible(unsigned int msecs)
+{
+ struct hrtimer_sleeper sleeper;
+ ktime_t left;
+
+ do_nsleep(msecs, &sleeper, 1);
+
+ if (!sleeper.task)
+ return 0;
+ left = ktime_sub(sleeper.timer.node.expires,
+ sleeper.timer.base->get_time());
+ return max(((long) ktime_to_ns(left))/(long)NSEC_PER_MSEC, 1L);
+}
+
+EXPORT_SYMBOL(hr_msleep_interruptible);
+
static int __sched do_usleep_range(unsigned long min, unsigned long max)
{
ktime_t kmin;