Skip to content

Commit 95aac7b

Browse files
sbohrertorvalds
authored andcommitted
epoll: make epoll_wait() use the hrtimer range feature
This make epoll use hrtimers for the timeout value which prevents epoll_wait() from timing out up to a millisecond early. This mirrors the behavior of select() and poll(). Signed-off-by: Shawn Bohrer <shawn.bohrer@gmail.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Davide Libenzi <davidel@xmailserver.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 231f3d3 commit 95aac7b

File tree

3 files changed

+22
-17
lines changed

3 files changed

+22
-17
lines changed

fs/eventpoll.c

+19-16
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@
7777
/* Maximum number of nesting allowed inside epoll sets */
7878
#define EP_MAX_NESTS 4
7979

80-
/* Maximum msec timeout value storeable in a long int */
81-
#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
82-
8380
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
8481

8582
#define EP_UNACTIVE_PTR ((void *) -1L)
@@ -1117,18 +1114,22 @@ static int ep_send_events(struct eventpoll *ep,
11171114
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
11181115
int maxevents, long timeout)
11191116
{
1120-
int res, eavail;
1117+
int res, eavail, timed_out = 0;
11211118
unsigned long flags;
1122-
long jtimeout;
1119+
long slack;
11231120
wait_queue_t wait;
1124-
1125-
/*
1126-
* Calculate the timeout by checking for the "infinite" value (-1)
1127-
* and the overflow condition. The passed timeout is in milliseconds,
1128-
* that why (t * HZ) / 1000.
1129-
*/
1130-
jtimeout = (timeout < 0 || timeout >= EP_MAX_MSTIMEO) ?
1131-
MAX_SCHEDULE_TIMEOUT : (timeout * HZ + 999) / 1000;
1121+
struct timespec end_time;
1122+
ktime_t expires, *to = NULL;
1123+
1124+
if (timeout > 0) {
1125+
ktime_get_ts(&end_time);
1126+
timespec_add_ns(&end_time, (u64)timeout * NSEC_PER_MSEC);
1127+
slack = select_estimate_accuracy(&end_time);
1128+
to = &expires;
1129+
*to = timespec_to_ktime(end_time);
1130+
} else if (timeout == 0) {
1131+
timed_out = 1;
1132+
}
11321133

11331134
retry:
11341135
spin_lock_irqsave(&ep->lock, flags);
@@ -1150,15 +1151,17 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
11501151
* to TASK_INTERRUPTIBLE before doing the checks.
11511152
*/
11521153
set_current_state(TASK_INTERRUPTIBLE);
1153-
if (!list_empty(&ep->rdllist) || !jtimeout)
1154+
if (!list_empty(&ep->rdllist) || timed_out)
11541155
break;
11551156
if (signal_pending(current)) {
11561157
res = -EINTR;
11571158
break;
11581159
}
11591160

11601161
spin_unlock_irqrestore(&ep->lock, flags);
1161-
jtimeout = schedule_timeout(jtimeout);
1162+
if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
1163+
timed_out = 1;
1164+
11621165
spin_lock_irqsave(&ep->lock, flags);
11631166
}
11641167
__remove_wait_queue(&ep->wq, &wait);
@@ -1176,7 +1179,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
11761179
* more luck.
11771180
*/
11781181
if (!res && eavail &&
1179-
!(res = ep_send_events(ep, events, maxevents)) && jtimeout)
1182+
!(res = ep_send_events(ep, events, maxevents)) && !timed_out)
11801183
goto retry;
11811184

11821185
return res;

fs/select.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static long __estimate_accuracy(struct timespec *tv)
6767
return slack;
6868
}
6969

70-
static long select_estimate_accuracy(struct timespec *tv)
70+
long select_estimate_accuracy(struct timespec *tv)
7171
{
7272
unsigned long ret;
7373
struct timespec now;

include/linux/poll.h

+2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ extern void poll_initwait(struct poll_wqueues *pwq);
7373
extern void poll_freewait(struct poll_wqueues *pwq);
7474
extern int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
7575
ktime_t *expires, unsigned long slack);
76+
extern long select_estimate_accuracy(struct timespec *tv);
77+
7678

7779
static inline int poll_schedule(struct poll_wqueues *pwq, int state)
7880
{

0 commit comments

Comments
 (0)