* [patch v2 0/5] Nano/Microsecond resolution for select() and poll()
@ 2008-08-31 16:28 Arjan van de Ven
2008-08-31 16:29 ` [PATCH 1/5] select: Introduce a hrtimeout function Arjan van de Ven
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 16:28 UTC (permalink / raw)
To: linux-kernel; +Cc: tglx, mingo, torvalds, Arnd Bergmann
New in this version:
* With lots of help from Thomas Gleixner, select() and poll() now
exclusively use hrtimers
* Several key cleanups from Thomas actually simplify and clean the
code up so that it's an overall improvement in code quality
* Various interesting bugs were encountered during the switchover on this
level. The Fedora/Red Hat "nash" program deserves a special mention for
both asking for a 1 nanosecond ppoll() timeout AND depending on the
implementation to set this to 0 nanoseconds in userspace memory at
the end of the first iteration.
fs/compat.c | 187 +++++++++--------------
fs/select.c | 346 +++++++++++++++++++++-----------------------
include/linux/hrtimer.h | 2
include/linux/poll.h | 8 -
include/linux/thread_info.h | 8 +
include/linux/time.h | 4
kernel/hrtimer.c | 65 ++++++++
kernel/time.c | 18 ++
8 files changed, 344 insertions(+), 294 deletions(-)
(the bulk of actual linecount growth is just newly added comments)
----
Today in Linux, select() and poll() operate in jiffies resolution
(granularity), meaning an effective resolution of 1 millisecond (HZ=1000) to
10 milliseconds (HZ=100). Delays shorter than this are not possible, and all
delays are in multiples of this granularity.
The effect is that applications that want (on average) to specify more
accurate delays (for example multimedia or other interactive apps) just
cannot do that; this creates more than needed jitter.
With this patch series, the internals of select() and poll() interfaces are
changed such that they work on the nanosecond level (using hrtimers). The
userspace interface for select() is in microseconds, for pselect() and
ppoll() this is in nanoseconds.
[actual behavior obviously on what resolution the hardware timers work, on
modern PCs this is pretty good though]
To show this effect I made a test application to measure the error made
in the select() timing.
For example, a userspace application asking for a 1200 microsecond delay, on
a HZ=1000 kernel, will in practice get a 1997 microsecond delay, a delta of
almost 800 microseconds (which is of course a high percentage of 1200). The
extreme case is asking for 1 microsecond, and getting 998 microseconds
delay... with the patch we get a 250 times improvement in behavior (!).
A graph of various inputs with the jitter can be seen at
http://www.tglx.de/~arjan/select_benefits.png
One thing to note is that on my machine, the current select() implementation
will return after 1997 microseconds when asked for 1999 microseconds; this
can be seen in a zoom in of the graph above:
http://www.tglx.de/~arjan/zoom.png
E.g. select() is returning too early in current Linux kernels; and this is
also fixed (by nature) by this patch series.
In the graph there's a 4 microsecond delta for most data points, this is
basically the measurement overhead (C-state exit, a few system calls, a
loop and some math).
Note:
even though poll() (as opposed to ppoll()) only accepts milliseconds
as userspace interface, the behavior will still improve because the current
time no longer needs to be rounded up to the next jiffie, so on average
a 500 microseconds behavior improvement.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/5] select: Introduce a hrtimeout function
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
@ 2008-08-31 16:29 ` Arjan van de Ven
2008-08-31 16:29 ` [PATCH 2/5] select: add a timespec_add_safe() function Arjan van de Ven
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 16:29 UTC (permalink / raw)
To: linux-kernel; +Cc: Arjan van de Ven, tglx, mingo, torvalds, Arnd Bergmann
From: Arjan van de Ven <arjan@linux.intel.com>
Subject: [PATCH] select: Introduce a hrtimeout function
This patch adds a schedule_hrtimeout() function, to be used by select() and
poll() in a later patch. This function works similar to schedule_timeout()
in most ways, but takes a timespec rather than jiffies.
With a lot of contributions/fixes from Thomas
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
include/linux/hrtimer.h | 2 +
kernel/hrtimer.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+), 0 deletions(-)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 6d93dce..becd17d 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -346,6 +346,8 @@ 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(ktime_t *expires, const enum hrtimer_mode mode);
+
/* Soft interrupt function to run the hrtimer queues: */
extern void hrtimer_run_queues(void);
extern void hrtimer_run_pending(void);
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index b8e4dce..782137d 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1678,3 +1678,68 @@ void __init hrtimers_init(void)
#endif
}
+/**
+ * schedule_hrtimeout - sleep until timeout
+ * @expires: timeout value (ktime_t)
+ * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL
+ *
+ * Make the current task sleep until the given expiry time has
+ * elapsed. The routine will return immediately unless
+ * the current task state has been set (see set_current_state()).
+ *
+ * You can set the task state as follows -
+ *
+ * %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to
+ * pass before the routine returns.
+ *
+ * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
+ * delivered to the current task.
+ *
+ * The current task state is guaranteed to be TASK_RUNNING when this
+ * routine returns.
+ *
+ * Returns 0 when the timer has expired otherwise -EINTR
+ */
+int __sched schedule_hrtimeout(ktime_t *expires,
+ const enum hrtimer_mode mode)
+{
+ struct hrtimer_sleeper t;
+
+ /*
+ * Optimize when a zero timeout value is given. It does not
+ * matter whether this is an absolute or a relative time.
+ */
+ if (expires && !expires->tv64) {
+ __set_current_state(TASK_RUNNING);
+ return 0;
+ }
+
+ /*
+ * A NULL parameter means "inifinte"
+ */
+ if (!expires) {
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ return -EINTR;
+ }
+
+ hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, mode);
+ t.timer.expires = *expires;
+
+ hrtimer_init_sleeper(&t, current);
+
+ hrtimer_start(&t.timer, t.timer.expires, mode);
+ if (!hrtimer_active(&t.timer))
+ t.task = NULL;
+
+ if (likely(t.task))
+ schedule();
+
+ hrtimer_cancel(&t.timer);
+ destroy_hrtimer_on_stack(&t.timer);
+
+ __set_current_state(TASK_RUNNING);
+
+ return !t.task ? 0 : -EINTR;
+}
+EXPORT_SYMBOL_GPL(schedule_hrtimeout);
--
1.5.5.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/5] select: add a timespec_add_safe() function
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
2008-08-31 16:29 ` [PATCH 1/5] select: Introduce a hrtimeout function Arjan van de Ven
@ 2008-08-31 16:29 ` Arjan van de Ven
2008-08-31 16:30 ` [PATCH 3/5] select: add poll_select_set_timeout() and poll_select_copy_remaining() helpers Arjan van de Ven
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 16:29 UTC (permalink / raw)
To: linux-kernel; +Cc: Arjan van de Ven, tglx, mingo, torvalds, Arnd Bergmann
From: Thomas Gleixner <tglx@linutronix.de>
Subject: [PATCH] select: add a timespec_add_safe() function
For the select() rework, it's important to be able to add timespec
structures in an overflow-safe manner.
This patch adds a timespec_add_safe() function for this which is similar in
operation to ktime_add_safe(), but works on a struct timespec.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
include/linux/time.h | 4 ++++
kernel/time.c | 18 ++++++++++++++++++
2 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/include/linux/time.h b/include/linux/time.h
index e15206a..7269764 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -38,6 +38,8 @@ struct timezone {
#define NSEC_PER_SEC 1000000000L
#define FSEC_PER_SEC 1000000000000000L
+#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
+
static inline int timespec_equal(const struct timespec *a,
const struct timespec *b)
{
@@ -72,6 +74,8 @@ extern unsigned long mktime(const unsigned int year, const unsigned int mon,
const unsigned int min, const unsigned int sec);
extern void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec);
+extern struct timespec timespec_add_safe(const struct timespec lhs,
+ const struct timespec rhs);
/*
* sub = lhs - rhs, in normalized form
diff --git a/kernel/time.c b/kernel/time.c
index 6a08660..d63a433 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -669,3 +669,21 @@ EXPORT_SYMBOL(get_jiffies_64);
#endif
EXPORT_SYMBOL(jiffies);
+
+/*
+ * Add two timespec values and do a safety check for overflow.
+ * It's assumed that both values are valid (>= 0)
+ */
+struct timespec timespec_add_safe(const struct timespec lhs,
+ const struct timespec rhs)
+{
+ struct timespec res;
+
+ set_normalized_timespec(&res, lhs.tv_sec + rhs.tv_sec,
+ lhs.tv_nsec + rhs.tv_nsec);
+
+ if (res.tv_sec < lhs.tv_sec || res.tv_sec < rhs.tv_sec)
+ res.tv_sec = TIME_T_MAX;
+
+ return res;
+}
--
1.5.5.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/5] select: add poll_select_set_timeout() and poll_select_copy_remaining() helpers
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
2008-08-31 16:29 ` [PATCH 1/5] select: Introduce a hrtimeout function Arjan van de Ven
2008-08-31 16:29 ` [PATCH 2/5] select: add a timespec_add_safe() function Arjan van de Ven
@ 2008-08-31 16:30 ` Arjan van de Ven
2008-08-31 16:30 ` [PATCH 4/5] select: add a poll specific struct to the restart_block union Arjan van de Ven
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 16:30 UTC (permalink / raw)
To: linux-kernel; +Cc: Arjan van de Ven, tglx, mingo, torvalds, Arnd Bergmann
From: Thomas Gleixner <tglx@linutronix.de>
Date: Sun, 31 Aug 2008 08:16:57 -0700
Subject: [PATCH] select: add poll_select_set_timeout() and
poll_select_copy_remaining() helpers
This patch adds 2 helpers that will be used for the hrtimer based
select/poll:
poll_select_set_timeout() is a helper that takes a timeout (as a
second, nanosecond pair) and turns that into a "struct timespec" that
represents the absolute end time. This is a common operation in the
many select() and poll() variants and needs various, common, sanity
checks.
poll_select_copy_remaining() is a helper that takes care of copying the
remaining time to userspace, as select(), pselect() and ppoll() do.
This function comes in both a natural and a compat implementation (due
to datastructure differences).
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
fs/compat.c | 51 ++++++++++++++++++++++++++++++++++
fs/select.c | 75
++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/poll.h
| 2 + 3 files changed, 128 insertions(+), 0 deletions(-)
diff --git a/fs/compat.c b/fs/compat.c
index 075d050..424767c 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1436,6 +1436,57 @@ out_ret:
#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
+static int poll_select_copy_remaining(struct timespec *end_time, void
__user *p,
+ int timeval, int ret)
+{
+ struct timespec ts;
+
+ if (!p)
+ return ret;
+
+ if (current->personality & STICKY_TIMEOUTS)
+ goto sticky;
+
+ /* No update for zero timeout */
+ if (!end_time->tv_sec && !end_time->tv_nsec)
+ return ret;
+
+ ktime_get_ts(&ts);
+ ts = timespec_sub(*end_time, ts);
+ if (ts.tv_sec < 0)
+ ts.tv_sec = ts.tv_nsec = 0;
+
+ if (timeval) {
+ struct compat_timeval rtv;
+
+ rtv.tv_sec = ts.tv_sec;
+ rtv.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+ if (!copy_to_user(p, &rtv, sizeof(rtv)))
+ return ret;
+ } else {
+ struct compat_timespec rts;
+
+ rts.tv_sec = ts.tv_sec;
+ rts.tv_nsec = ts.tv_nsec;
+
+ if (!copy_to_user(p, &rts, sizeof(rts)))
+ return ret;
+ }
+ /*
+ * If an application puts its timeval in read-only memory, we
+ * don't want the Linux-specific update to the timeval to
+ * cause a fault after the select has completed
+ * successfully. However, because we're not updating the
+ * timeval, we can't restart the system call.
+ */
+
+sticky:
+ if (ret == -ERESTARTNOHAND)
+ ret = -EINTR;
+ return ret;
+}
+
/*
* Ooo, nasty. We need here to frob 32-bit unsigned longs to
* 64-bit unsigned longs.
diff --git a/fs/select.c b/fs/select.c
index da0e882..1180a62 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -130,6 +130,81 @@ static void __pollwait(struct file *filp,
wait_queue_head_t *wait_address, add_wait_queue(wait_address,
&entry->wait); }
+/**
+ * poll_select_set_timeout - helper function to setup the timeout value
+ * @to: pointer to timespec variable for the final
timeout
+ * @sec: seconds (from user space)
+ * @nsec: nanoseconds (from user space)
+ *
+ * Note, we do not use a timespec for the user space value here, That
+ * way we can use the function for timeval and compat interfaces as
well.
+ *
+ * Returns -EINVAL if sec/nsec are not normalized. Otherwise 0.
+ */
+int poll_select_set_timeout(struct timespec *to, long sec, long nsec)
+{
+ struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec};
+
+ if (!timespec_valid(&ts))
+ return -EINVAL;
+
+ /* Optimize for the zero timeout value here */
+ if (!sec && !nsec) {
+ to->tv_sec = to->tv_nsec = 0;
+ } else {
+ ktime_get_ts(to);
+ *to = timespec_add_safe(*to, ts);
+ }
+ return 0;
+}
+
+static int poll_select_copy_remaining(struct timespec *end_time, void
__user *p,
+ int timeval, int ret)
+{
+ struct timespec rts;
+ struct timeval rtv;
+
+ if (!p)
+ return ret;
+
+ if (current->personality & STICKY_TIMEOUTS)
+ goto sticky;
+
+ /* No update for zero timeout */
+ if (!end_time->tv_sec && !end_time->tv_nsec)
+ return ret;
+
+ ktime_get_ts(&rts);
+ rts = timespec_sub(*end_time, rts);
+ if (rts.tv_sec < 0)
+ rts.tv_sec = rts.tv_nsec = 0;
+
+ if (timeval) {
+ rtv.tv_sec = rts.tv_sec;
+ rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
+
+ if (!copy_to_user(p, &rtv, sizeof(rtv)))
+ return ret;
+
+ } else if (!copy_to_user(p, &rts, sizeof(rts)))
+ return ret;
+
+ /*
+ * If an application puts its timeval in read-only memory, we
+ * don't want the Linux-specific update to the timeval to
+ * cause a fault after the select has completed
+ * successfully. However, because we're not updating the
+ * timeval, we can't restart the system call.
+ */
+
+sticky:
+ if (ret == -ERESTARTNOHAND)
+ ret = -EINTR;
+ return ret;
+}
+
+
+
#define FDS_IN(fds, n) (fds->in + n)
#define FDS_OUT(fds, n) (fds->out + n)
#define FDS_EX(fds, n) (fds->ex + n)
diff --git a/include/linux/poll.h b/include/linux/poll.h
index ef45382..f65de51 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -120,6 +120,8 @@ extern int do_sys_poll(struct pollfd __user * ufds,
unsigned int nfds, extern int core_sys_select(int n, fd_set __user
*inp, fd_set __user *outp, fd_set __user *exp, s64 *timeout);
+extern int poll_select_set_timeout(struct timespec *to, long sec, long
nsec); +
#endif /* KERNEL */
#endif /* _LINUX_POLL_H */
--
1.5.5.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/5] select: add a poll specific struct to the restart_block union
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
` (2 preceding siblings ...)
2008-08-31 16:30 ` [PATCH 3/5] select: add poll_select_set_timeout() and poll_select_copy_remaining() helpers Arjan van de Ven
@ 2008-08-31 16:30 ` Arjan van de Ven
2008-08-31 16:31 ` [PATCH 5/5] select: switch select() and poll() over to hrtimers Arjan van de Ven
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 16:30 UTC (permalink / raw)
To: linux-kernel; +Cc: Arjan van de Ven, tglx, mingo, torvalds, Arnd Bergmann
From: Thomas Gleixner <tglx@linutronix.de>
Date: Sun, 31 Aug 2008 08:19:15 -0700
Subject: [PATCH] select: add a poll specific struct to the restart_block union
with hrtimer poll/select, the signal restart data no longer is a single
long representing a jiffies count, but it becomes a second/nanosecond pair
that also needs to encode if there was a timeout at all or not.
This patch adds a struct to the restart_block union for this purpose
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
include/linux/thread_info.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index 38a5647..e6b820f 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -38,6 +38,14 @@ struct restart_block {
#endif
u64 expires;
} nanosleep;
+ /* For poll */
+ struct {
+ struct pollfd __user *ufds;
+ int nfds;
+ int has_timeout;
+ unsigned long tv_sec;
+ unsigned long tv_nsec;
+ } poll;
};
};
--
1.5.5.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/5] select: switch select() and poll() over to hrtimers
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
` (3 preceding siblings ...)
2008-08-31 16:30 ` [PATCH 4/5] select: add a poll specific struct to the restart_block union Arjan van de Ven
@ 2008-08-31 16:31 ` Arjan van de Ven
2008-08-31 16:55 ` [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Willy Tarreau
2008-08-31 21:13 ` Davide Libenzi
6 siblings, 0 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 16:31 UTC (permalink / raw)
To: linux-kernel; +Cc: Arjan van de Ven, tglx, mingo, torvalds, Arnd Bergmann
From: Arjan van de Ven <arjan@linux.intel.com>
Date: Sun, 31 Aug 2008 08:26:40 -0700
Subject: [PATCH] select: switch select() and poll() over to hrtimers
With lots of help, input and cleanups from Thomas Gleixner
This patch switches select() and poll() over to hrtimers.
The core of the patch is replacing the "s64 timeout" with a
"struct timespec end_time" in all the plumbing.
But most of the diffstat comes from using the just introduced helpers:
poll_select_set_timeout
poll_select_copy_remaining
timespec_add_safe
which make manipulating the timespec easier and less error-prone.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
fs/compat.c | 136 ++++----------------------
fs/select.c | 263 +++++++++++++++++---------------------------------
include/linux/poll.h | 6 +-
3 files changed, 111 insertions(+), 294 deletions(-)
diff --git a/fs/compat.c b/fs/compat.c
index 424767c..133ed7f 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1568,7 +1568,8 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
int compat_core_sys_select(int n, compat_ulong_t __user *inp,
- compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout)
+ compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+ struct timespec *end_time)
{
fd_set_bits fds;
void *bits;
@@ -1615,7 +1616,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
zero_fd_set(n, fds.res_out);
zero_fd_set(n, fds.res_ex);
- ret = do_select(n, &fds, timeout);
+ ret = do_select(n, &fds, end_time);
if (ret < 0)
goto out;
@@ -1641,7 +1642,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
struct compat_timeval __user *tvp)
{
- s64 timeout = -1;
+ struct timespec end_time, *to = NULL;
struct compat_timeval tv;
int ret;
@@ -1649,43 +1650,14 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
if (copy_from_user(&tv, tvp, sizeof(tv)))
return -EFAULT;
- if (tv.tv_sec < 0 || tv.tv_usec < 0)
+ to = &end_time;
+ if (poll_select_set_timeout(to, tv.tv_sec,
+ tv.tv_usec * NSEC_PER_USEC))
return -EINVAL;
-
- /* Cast to u64 to make GCC stop complaining */
- if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
- timeout = -1; /* infinite */
- else {
- timeout = DIV_ROUND_UP(tv.tv_usec, 1000000/HZ);
- timeout += tv.tv_sec * HZ;
- }
}
- ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
-
- if (tvp) {
- struct compat_timeval rtv;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
- rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ));
- rtv.tv_sec = timeout;
- if (compat_timeval_compare(&rtv, &tv) >= 0)
- rtv = tv;
- if (copy_to_user(tvp, &rtv, sizeof(rtv))) {
-sticky:
- /*
- * If an application puts its timeval in read-only
- * memory, we don't want the Linux-specific update to
- * the timeval to cause a fault after the select has
- * completed successfully. However, because we're not
- * updating the timeval, we can't restart the system
- * call.
- */
- if (ret == -ERESTARTNOHAND)
- ret = -EINTR;
- }
- }
+ ret = compat_core_sys_select(n, inp, outp, exp, to);
+ ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);
return ret;
}
@@ -1698,15 +1670,16 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
{
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved;
- s64 timeout = MAX_SCHEDULE_TIMEOUT;
struct compat_timespec ts;
+ struct timespec end_time, *to = NULL;
int ret;
if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts)))
return -EFAULT;
- if (ts.tv_sec < 0 || ts.tv_nsec < 0)
+ to = &end_time;
+ if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
return -EINVAL;
}
@@ -1721,51 +1694,8 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}
- do {
- if (tsp) {
- if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
- timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
- timeout += ts.tv_sec * (unsigned long)HZ;
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
- } else {
- ts.tv_sec -= MAX_SELECT_SECONDS;
- timeout = MAX_SELECT_SECONDS * HZ;
- }
- }
-
- ret = compat_core_sys_select(n, inp, outp, exp, &timeout);
-
- } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec));
-
- if (tsp) {
- struct compat_timespec rts;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
-
- rts.tv_sec = timeout / HZ;
- rts.tv_nsec = (timeout % HZ) * (NSEC_PER_SEC/HZ);
- if (rts.tv_nsec >= NSEC_PER_SEC) {
- rts.tv_sec++;
- rts.tv_nsec -= NSEC_PER_SEC;
- }
- if (compat_timespec_compare(&rts, &ts) >= 0)
- rts = ts;
- if (copy_to_user(tsp, &rts, sizeof(rts))) {
-sticky:
- /*
- * If an application puts its timeval in read-only
- * memory, we don't want the Linux-specific update to
- * the timeval to cause a fault after the select has
- * completed successfully. However, because we're not
- * updating the timeval, we can't restart the system
- * call.
- */
- if (ret == -ERESTARTNOHAND)
- ret = -EINTR;
- }
- }
+ ret = compat_core_sys_select(n, inp, outp, exp, to);
+ ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
if (ret == -ERESTARTNOHAND) {
/*
@@ -1810,18 +1740,16 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
compat_sigset_t ss32;
sigset_t ksigmask, sigsaved;
struct compat_timespec ts;
- s64 timeout = -1;
+ struct timespec end_time, *to = NULL;
int ret;
if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts)))
return -EFAULT;
- /* We assume that ts.tv_sec is always lower than
- the number of seconds that can be expressed in
- an s64. Otherwise the compiler bitches at us */
- timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
- timeout += ts.tv_sec * HZ;
+ to = &end_time;
+ if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
+ return -EINVAL;
}
if (sigmask) {
@@ -1835,7 +1763,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}
- ret = do_sys_poll(ufds, nfds, &timeout);
+ ret = do_sys_poll(ufds, nfds, to);
/* We can restart this syscall, usually */
if (ret == -EINTR) {
@@ -1853,31 +1781,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- if (tsp && timeout >= 0) {
- struct compat_timespec rts;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
- /* Yes, we know it's actually an s64, but it's also positive. */
- rts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) *
- 1000;
- rts.tv_sec = timeout;
- if (compat_timespec_compare(&rts, &ts) >= 0)
- rts = ts;
- if (copy_to_user(tsp, &rts, sizeof(rts))) {
-sticky:
- /*
- * If an application puts its timeval in read-only
- * memory, we don't want the Linux-specific update to
- * the timeval to cause a fault after the select has
- * completed successfully. However, because we're not
- * updating the timeval, we can't restart the system
- * call.
- */
- if (ret == -ERESTARTNOHAND && timeout >= 0)
- ret = -EINTR;
- }
- }
+ ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
return ret;
}
diff --git a/fs/select.c b/fs/select.c
index 1180a62..f6dceb5 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -24,6 +24,7 @@
#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/rcupdate.h>
+#include <linux/hrtimer.h>
#include <asm/uaccess.h>
@@ -203,8 +204,6 @@ sticky:
return ret;
}
-
-
#define FDS_IN(fds, n) (fds->in + n)
#define FDS_OUT(fds, n) (fds->out + n)
#define FDS_EX(fds, n) (fds->ex + n)
@@ -257,11 +256,12 @@ get_max:
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)
-int do_select(int n, fd_set_bits *fds, s64 *timeout)
+int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
{
+ ktime_t expire, *to = NULL;
struct poll_wqueues table;
poll_table *wait;
- int retval, i;
+ int retval, i, timed_out = 0;
rcu_read_lock();
retval = max_select_fd(n, fds);
@@ -273,12 +273,14 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
poll_initwait(&table);
wait = &table.pt;
- if (!*timeout)
+ if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
wait = NULL;
+ timed_out = 1;
+ }
+
retval = 0;
for (;;) {
unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
- long __timeout;
set_current_state(TASK_INTERRUPTIBLE);
@@ -334,27 +336,25 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
cond_resched();
}
wait = NULL;
- if (retval || !*timeout || signal_pending(current))
+ if (retval || timed_out || signal_pending(current))
break;
if (table.error) {
retval = table.error;
break;
}
- if (*timeout < 0) {
- /* Wait indefinitely */
- __timeout = MAX_SCHEDULE_TIMEOUT;
- } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT - 1)) {
- /* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */
- __timeout = MAX_SCHEDULE_TIMEOUT - 1;
- *timeout -= __timeout;
- } else {
- __timeout = *timeout;
- *timeout = 0;
+ /*
+ * If this is the first loop and we have a timeout
+ * given, then we convert to ktime_t and set the to
+ * pointer to the expiry value.
+ */
+ if (end_time && !to) {
+ expire = timespec_to_ktime(*end_time);
+ to = &expire;
}
- __timeout = schedule_timeout(__timeout);
- if (*timeout >= 0)
- *timeout += __timeout;
+
+ if (!schedule_hrtimeout(to, HRTIMER_MODE_ABS))
+ timed_out = 1;
}
__set_current_state(TASK_RUNNING);
@@ -375,7 +375,7 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
- fd_set __user *exp, s64 *timeout)
+ fd_set __user *exp, struct timespec *end_time)
{
fd_set_bits fds;
void *bits;
@@ -426,7 +426,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
zero_fd_set(n, fds.res_out);
zero_fd_set(n, fds.res_ex);
- ret = do_select(n, &fds, timeout);
+ ret = do_select(n, &fds, end_time);
if (ret < 0)
goto out;
@@ -452,7 +452,7 @@ out_nofds:
asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
fd_set __user *exp, struct timeval __user *tvp)
{
- s64 timeout = -1;
+ struct timespec end_time, *to = NULL;
struct timeval tv;
int ret;
@@ -460,43 +460,14 @@ asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
if (copy_from_user(&tv, tvp, sizeof(tv)))
return -EFAULT;
- if (tv.tv_sec < 0 || tv.tv_usec < 0)
+ to = &end_time;
+ if (poll_select_set_timeout(to, tv.tv_sec,
+ tv.tv_usec * NSEC_PER_USEC))
return -EINVAL;
-
- /* Cast to u64 to make GCC stop complaining */
- if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
- timeout = -1; /* infinite */
- else {
- timeout = DIV_ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
- timeout += tv.tv_sec * HZ;
- }
}
- ret = core_sys_select(n, inp, outp, exp, &timeout);
-
- if (tvp) {
- struct timeval rtv;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
- rtv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ));
- rtv.tv_sec = timeout;
- if (timeval_compare(&rtv, &tv) >= 0)
- rtv = tv;
- if (copy_to_user(tvp, &rtv, sizeof(rtv))) {
-sticky:
- /*
- * If an application puts its timeval in read-only
- * memory, we don't want the Linux-specific update to
- * the timeval to cause a fault after the select has
- * completed successfully. However, because we're not
- * updating the timeval, we can't restart the system
- * call.
- */
- if (ret == -ERESTARTNOHAND)
- ret = -EINTR;
- }
- }
+ ret = core_sys_select(n, inp, outp, exp, to);
+ ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);
return ret;
}
@@ -506,25 +477,17 @@ asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp,
fd_set __user *exp, struct timespec __user *tsp,
const sigset_t __user *sigmask, size_t sigsetsize)
{
- s64 timeout = MAX_SCHEDULE_TIMEOUT;
sigset_t ksigmask, sigsaved;
- struct timespec ts;
+ struct timespec ts, end_time, *to = NULL;
int ret;
if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts)))
return -EFAULT;
- if (ts.tv_sec < 0 || ts.tv_nsec < 0)
+ to = &end_time;
+ if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
return -EINVAL;
-
- /* Cast to u64 to make GCC stop complaining */
- if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
- timeout = -1; /* infinite */
- else {
- timeout = DIV_ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
- timeout += ts.tv_sec * HZ;
- }
}
if (sigmask) {
@@ -538,32 +501,8 @@ asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp,
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}
- ret = core_sys_select(n, inp, outp, exp, &timeout);
-
- if (tsp) {
- struct timespec rts;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
- rts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) *
- 1000;
- rts.tv_sec = timeout;
- if (timespec_compare(&rts, &ts) >= 0)
- rts = ts;
- if (copy_to_user(tsp, &rts, sizeof(rts))) {
-sticky:
- /*
- * If an application puts its timeval in read-only
- * memory, we don't want the Linux-specific update to
- * the timeval to cause a fault after the select has
- * completed successfully. However, because we're not
- * updating the timeval, we can't restart the system
- * call.
- */
- if (ret == -ERESTARTNOHAND)
- ret = -EINTR;
- }
- }
+ ret = core_sys_select(n, inp, outp, exp, &end_time);
+ ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
if (ret == -ERESTARTNOHAND) {
/*
@@ -649,18 +588,20 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
}
static int do_poll(unsigned int nfds, struct poll_list *list,
- struct poll_wqueues *wait, s64 *timeout)
+ struct poll_wqueues *wait, struct timespec *end_time)
{
- int count = 0;
poll_table* pt = &wait->pt;
+ ktime_t expire, *to = NULL;
+ int timed_out = 0, count = 0;
/* Optimise the no-wait case */
- if (!(*timeout))
+ if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
pt = NULL;
+ timed_out = 1;
+ }
for (;;) {
struct poll_list *walk;
- long __timeout;
set_current_state(TASK_INTERRUPTIBLE);
for (walk = list; walk != NULL; walk = walk->next) {
@@ -692,27 +633,21 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
if (signal_pending(current))
count = -EINTR;
}
- if (count || !*timeout)
+ if (count || timed_out)
break;
- if (*timeout < 0) {
- /* Wait indefinitely */
- __timeout = MAX_SCHEDULE_TIMEOUT;
- } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT-1)) {
- /*
- * Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in
- * a loop
- */
- __timeout = MAX_SCHEDULE_TIMEOUT - 1;
- *timeout -= __timeout;
- } else {
- __timeout = *timeout;
- *timeout = 0;
+ /*
+ * If this is the first loop and we have a timeout
+ * given, then we convert to ktime_t and set the to
+ * pointer to the expiry value.
+ */
+ if (end_time && !to) {
+ expire = timespec_to_ktime(*end_time);
+ to = &expire;
}
- __timeout = schedule_timeout(__timeout);
- if (*timeout >= 0)
- *timeout += __timeout;
+ if (!schedule_hrtimeout(to, HRTIMER_MODE_ABS))
+ timed_out = 1;
}
__set_current_state(TASK_RUNNING);
return count;
@@ -721,7 +656,8 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
#define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \
sizeof(struct pollfd))
-int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
+int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
+ struct timespec *end_time)
{
struct poll_wqueues table;
int err = -EFAULT, fdcount, len, size;
@@ -761,7 +697,7 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
}
poll_initwait(&table);
- fdcount = do_poll(nfds, head, &table, timeout);
+ fdcount = do_poll(nfds, head, &table, end_time);
poll_freewait(&table);
for (walk = head; walk; walk = walk->next) {
@@ -787,16 +723,21 @@ out_fds:
static long do_restart_poll(struct restart_block *restart_block)
{
- struct pollfd __user *ufds = (struct pollfd __user*)restart_block->arg0;
- int nfds = restart_block->arg1;
- s64 timeout = ((s64)restart_block->arg3<<32) | (s64)restart_block->arg2;
+ struct pollfd __user *ufds = restart_block->poll.ufds;
+ int nfds = restart_block->poll.nfds;
+ struct timespec *to = NULL, end_time;
int ret;
- ret = do_sys_poll(ufds, nfds, &timeout);
+ if (restart_block->poll.has_timeout) {
+ end_time.tv_sec = restart_block->poll.tv_sec;
+ end_time.tv_nsec = restart_block->poll.tv_nsec;
+ to = &end_time;
+ }
+
+ ret = do_sys_poll(ufds, nfds, to);
+
if (ret == -EINTR) {
restart_block->fn = do_restart_poll;
- restart_block->arg2 = timeout & 0xFFFFFFFF;
- restart_block->arg3 = (u64)timeout >> 32;
ret = -ERESTART_RESTARTBLOCK;
}
return ret;
@@ -805,31 +746,32 @@ static long do_restart_poll(struct restart_block *restart_block)
asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
long timeout_msecs)
{
- s64 timeout_jiffies;
+ struct timespec end_time, *to = NULL;
int ret;
- if (timeout_msecs > 0) {
-#if HZ > 1000
- /* We can only overflow if HZ > 1000 */
- if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ)
- timeout_jiffies = -1;
- else
-#endif
- timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1;
- } else {
- /* Infinite (< 0) or no (0) timeout */
- timeout_jiffies = timeout_msecs;
+ if (timeout_msecs >= 0) {
+ to = &end_time;
+ poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,
+ NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
}
- ret = do_sys_poll(ufds, nfds, &timeout_jiffies);
+ ret = do_sys_poll(ufds, nfds, to);
+
if (ret == -EINTR) {
struct restart_block *restart_block;
+
restart_block = ¤t_thread_info()->restart_block;
restart_block->fn = do_restart_poll;
- restart_block->arg0 = (unsigned long)ufds;
- restart_block->arg1 = nfds;
- restart_block->arg2 = timeout_jiffies & 0xFFFFFFFF;
- restart_block->arg3 = (u64)timeout_jiffies >> 32;
+ restart_block->poll.ufds = ufds;
+ restart_block->poll.nfds = nfds;
+
+ if (timeout_msecs >= 0) {
+ restart_block->poll.tv_sec = end_time.tv_sec;
+ restart_block->poll.tv_nsec = end_time.tv_nsec;
+ restart_block->poll.has_timeout = 1;
+ } else
+ restart_block->poll.has_timeout = 0;
+
ret = -ERESTART_RESTARTBLOCK;
}
return ret;
@@ -841,21 +783,16 @@ asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
size_t sigsetsize)
{
sigset_t ksigmask, sigsaved;
- struct timespec ts;
- s64 timeout = -1;
+ struct timespec ts, end_time, *to = NULL;
int ret;
if (tsp) {
if (copy_from_user(&ts, tsp, sizeof(ts)))
return -EFAULT;
- /* Cast to u64 to make GCC stop complaining */
- if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
- timeout = -1; /* infinite */
- else {
- timeout = DIV_ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
- timeout += ts.tv_sec * HZ;
- }
+ to = &end_time;
+ if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
+ return -EINVAL;
}
if (sigmask) {
@@ -869,7 +806,7 @@ asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
}
- ret = do_sys_poll(ufds, nfds, &timeout);
+ ret = do_sys_poll(ufds, nfds, to);
/* We can restart this syscall, usually */
if (ret == -EINTR) {
@@ -887,31 +824,7 @@ asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- if (tsp && timeout >= 0) {
- struct timespec rts;
-
- if (current->personality & STICKY_TIMEOUTS)
- goto sticky;
- /* Yes, we know it's actually an s64, but it's also positive. */
- rts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) *
- 1000;
- rts.tv_sec = timeout;
- if (timespec_compare(&rts, &ts) >= 0)
- rts = ts;
- if (copy_to_user(tsp, &rts, sizeof(rts))) {
- sticky:
- /*
- * If an application puts its timeval in read-only
- * memory, we don't want the Linux-specific update to
- * the timeval to cause a fault after the select has
- * completed successfully. However, because we're not
- * updating the timeval, we can't restart the system
- * call.
- */
- if (ret == -ERESTARTNOHAND && timeout >= 0)
- ret = -EINTR;
- }
- }
+ ret = poll_select_copy_remaining(&end_time, tsp, 0, ret);
return ret;
}
diff --git a/include/linux/poll.h b/include/linux/poll.h
index f65de51..badd98a 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -114,11 +114,11 @@ void zero_fd_set(unsigned long nr, unsigned long *fdset)
#define MAX_INT64_SECONDS (((s64)(~((u64)0)>>1)/HZ)-1)
-extern int do_select(int n, fd_set_bits *fds, s64 *timeout);
+extern int do_select(int n, fd_set_bits *fds, struct timespec *end_time);
extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds,
- s64 *timeout);
+ struct timespec *end_time);
extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
- fd_set __user *exp, s64 *timeout);
+ fd_set __user *exp, struct timespec *end_time);
extern int poll_select_set_timeout(struct timespec *to, long sec, long nsec);
--
1.5.5.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch v2 0/5] Nano/Microsecond resolution for select() and poll()
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
` (4 preceding siblings ...)
2008-08-31 16:31 ` [PATCH 5/5] select: switch select() and poll() over to hrtimers Arjan van de Ven
@ 2008-08-31 16:55 ` Willy Tarreau
2008-08-31 21:13 ` Davide Libenzi
6 siblings, 0 replies; 9+ messages in thread
From: Willy Tarreau @ 2008-08-31 16:55 UTC (permalink / raw)
To: Arjan van de Ven; +Cc: linux-kernel, tglx, mingo, torvalds, Arnd Bergmann
Hi Arjan,
On Sun, Aug 31, 2008 at 09:28:28AM -0700, Arjan van de Ven wrote:
> One thing to note is that on my machine, the current select() implementation
> will return after 1997 microseconds when asked for 1999 microseconds; this
> can be seen in a zoom in of the graph above:
> http://www.tglx.de/~arjan/zoom.png
> E.g. select() is returning too early in current Linux kernels; and this is
> also fixed (by nature) by this patch series.
This is a good news. I've been bothered by this problem for a long time
and got used to add 99999 us to any delay fed to select() (that started
when HZ=100). I remember having noticed performance improvements in my
applications using this trick even on other systems, so I don't think
that Linux is the only one with this anomaly. I think it's simply caused
by the rounding methods which make it hard to compute an accurate deadline
when a value is converted before being added to jiffies.
I do not remember noticing this on epoll though. Maybe it's just because
I did not look close enough :-/
Cheers,
Willy
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch v2 0/5] Nano/Microsecond resolution for select() and poll()
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
` (5 preceding siblings ...)
2008-08-31 16:55 ` [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Willy Tarreau
@ 2008-08-31 21:13 ` Davide Libenzi
2008-08-31 21:28 ` Arjan van de Ven
6 siblings, 1 reply; 9+ messages in thread
From: Davide Libenzi @ 2008-08-31 21:13 UTC (permalink / raw)
To: Arjan van de Ven
Cc: Linux Kernel Mailing List, tglx, Ingo Molnar, Linus Torvalds,
Arnd Bergmann
On Sun, 31 Aug 2008, Arjan van de Ven wrote:
> Note:
> even though poll() (as opposed to ppoll()) only accepts milliseconds
> as userspace interface, the behavior will still improve because the current
> time no longer needs to be rounded up to the next jiffie, so on average
> a 500 microseconds behavior improvement.
Another way to get down in the timeout resolution for newer kernels, and
still supporting the syscalls with millisec timeouts, is to use timerfds.
- Davide
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [patch v2 0/5] Nano/Microsecond resolution for select() and poll()
2008-08-31 21:13 ` Davide Libenzi
@ 2008-08-31 21:28 ` Arjan van de Ven
0 siblings, 0 replies; 9+ messages in thread
From: Arjan van de Ven @ 2008-08-31 21:28 UTC (permalink / raw)
To: Davide Libenzi
Cc: Linux Kernel Mailing List, tglx, Ingo Molnar, Linus Torvalds,
Arnd Bergmann
On Sun, 31 Aug 2008 14:13:45 -0700 (PDT)
Davide Libenzi <davidel@xmailserver.org> wrote:
> On Sun, 31 Aug 2008, Arjan van de Ven wrote:
>
> > Note:
> > even though poll() (as opposed to ppoll()) only accepts milliseconds
> > as userspace interface, the behavior will still improve because the
> > current time no longer needs to be rounded up to the next jiffie,
> > so on average a 500 microseconds behavior improvement.
>
> Another way to get down in the timeout resolution for newer kernels,
> and still supporting the syscalls with millisec timeouts, is to use
> timerfds.
perhaps, but once you have to change the app you can also make it use
ppoll() rather than poll().. that's a VERY minute change.
--
If you want to reach me at my work email, use arjan@linux.intel.com
For development, discussion and tips for power savings,
visit http://www.lesswatts.org
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-08-31 21:28 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-08-31 16:28 [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Arjan van de Ven
2008-08-31 16:29 ` [PATCH 1/5] select: Introduce a hrtimeout function Arjan van de Ven
2008-08-31 16:29 ` [PATCH 2/5] select: add a timespec_add_safe() function Arjan van de Ven
2008-08-31 16:30 ` [PATCH 3/5] select: add poll_select_set_timeout() and poll_select_copy_remaining() helpers Arjan van de Ven
2008-08-31 16:30 ` [PATCH 4/5] select: add a poll specific struct to the restart_block union Arjan van de Ven
2008-08-31 16:31 ` [PATCH 5/5] select: switch select() and poll() over to hrtimers Arjan van de Ven
2008-08-31 16:55 ` [patch v2 0/5] Nano/Microsecond resolution for select() and poll() Willy Tarreau
2008-08-31 21:13 ` Davide Libenzi
2008-08-31 21:28 ` Arjan van de Ven
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®