In preparation of new epoll syscalls, this patch allows reusing the code from epoll_pwait implementation. The new functions uses ktime_t for more accuracy.
Signed-off-by: Fam Zheng <f...@redhat.com> --- fs/eventpoll.c | 154 ++++++++++++++++++++++++++------------------------------- 1 file changed, 71 insertions(+), 83 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 1e009ca..7dfabeb 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1554,17 +1554,6 @@ static int ep_send_events(struct eventpoll *ep, return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0, false); } -static inline struct timespec ep_set_mstimeout(long ms) -{ - struct timespec now, ts = { - .tv_sec = ms / MSEC_PER_SEC, - .tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC), - }; - - ktime_get_ts(&now); - return timespec_add_safe(now, ts); -} - /** * ep_poll - Retrieves ready events, and delivers them to the caller supplied * event buffer. @@ -1573,17 +1562,15 @@ static inline struct timespec ep_set_mstimeout(long ms) * @events: Pointer to the userspace buffer where the ready events should be * stored. * @maxevents: Size (in terms of number of events) of the caller event buffer. - * @timeout: Maximum timeout for the ready events fetch operation, in - * milliseconds. If the @timeout is zero, the function will not block, - * while if the @timeout is less than zero, the function will block - * until at least one event has been retrieved (or an error - * occurred). + * @timeout: Maximum timeout for the ready events fetch operation. If 0, the + * function will not block. If negative, the function will block until + * at least one event has been retrieved (or an error occurred). * * Returns: Returns the number of ready events which have been fetched, or an * error code, in case of error. */ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, - int maxevents, long timeout) + int maxevents, const ktime_t timeout) { int res = 0, eavail, timed_out = 0; unsigned long flags; @@ -1591,13 +1578,7 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, wait_queue_t wait; ktime_t expires, *to = NULL; - if (timeout > 0) { - struct timespec end_time = ep_set_mstimeout(timeout); - - slack = select_estimate_accuracy(&end_time); - to = &expires; - *to = timespec_to_ktime(end_time); - } else if (timeout == 0) { + if (!ktime_to_ns(timeout)) { /* * Avoid the unnecessary trip to the wait queue loop, if the * caller specified a non blocking operation. @@ -1605,6 +1586,15 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, timed_out = 1; spin_lock_irqsave(&ep->lock, flags); goto check_events; + } else if (ktime_to_ns(timeout) > 0) { + struct timespec now, end_time; + + ktime_get_ts(&now); + end_time = timespec_add_safe(now, ktime_to_timespec(timeout)); + + slack = select_estimate_accuracy(&end_time); + to = &expires; + *to = timespec_to_ktime(end_time); } fetch_events: @@ -1954,12 +1944,8 @@ error_return: return error; } -/* - * Implement the event wait interface for the eventpoll file. It is the kernel - * part of the user space epoll_wait(2). - */ -SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events, - int, maxevents, int, timeout) +static inline int epoll_wait_do(int epfd, struct epoll_event __user *events, + int maxevents, const ktime_t timeout) { int error; struct fd f; @@ -2002,46 +1988,70 @@ error_fput: /* * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_wait(2). + */ +SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events, + int, maxevents, int, timeout) +{ + ktime_t kt = ms_to_ktime(timeout); + return epoll_wait_do(epfd, events, maxevents, kt); +} + +static inline int epoll_pwait_do(int epfd, struct epoll_event __user *events, + int maxevents, ktime_t timeout, + sigset_t *sigmask, size_t sigsetsize) +{ + int error; + sigset_t sigsaved; + + /* + * If the caller wants a certain signal mask to be set during the wait, + * we apply it here. + */ + if (sigmask) { + sigsaved = current->blocked; + set_current_blocked(sigmask); + } + + error = epoll_wait_do(epfd, events, maxevents, timeout); + + /* + * If we changed the signal mask, we need to restore the original one. + * In case we've got a signal while waiting, we do not restore the + * signal mask yet, and we allow do_signal() to deliver the signal on + * the way back to userspace, before the signal mask is restored. + */ + if (sigmask) { + if (error == -EINTR) { + memcpy(¤t->saved_sigmask, &sigsaved, + sizeof(sigsaved)); + set_restore_sigmask(); + } else + set_current_blocked(&sigsaved); + } + + return error; +} + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel * part of the user space epoll_pwait(2). */ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, int, maxevents, int, timeout, const sigset_t __user *, sigmask, size_t, sigsetsize) { - int error; - sigset_t ksigmask, sigsaved; + ktime_t kt = ms_to_ktime(timeout); + sigset_t ksigmask; - /* - * If the caller wants a certain signal mask to be set during the wait, - * we apply it here. - */ if (sigmask) { if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) return -EFAULT; - sigsaved = current->blocked; - set_current_blocked(&ksigmask); } - - error = sys_epoll_wait(epfd, events, maxevents, timeout); - - /* - * If we changed the signal mask, we need to restore the original one. - * In case we've got a signal while waiting, we do not restore the - * signal mask yet, and we allow do_signal() to deliver the signal on - * the way back to userspace, before the signal mask is restored. - */ - if (sigmask) { - if (error == -EINTR) { - memcpy(¤t->saved_sigmask, &sigsaved, - sizeof(sigsaved)); - set_restore_sigmask(); - } else - set_current_blocked(&sigsaved); - } - - return error; + return epoll_pwait_do(epfd, events, maxevents, kt, + sigmask ? &ksigmask : NULL, sigsetsize); } #ifdef CONFIG_COMPAT @@ -2051,42 +2061,20 @@ COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize) { - long err; compat_sigset_t csigmask; - sigset_t ksigmask, sigsaved; + sigset_t ksigmask; + ktime_t kt = ms_to_ktime(timeout); - /* - * If the caller wants a certain signal mask to be set during the wait, - * we apply it here. - */ if (sigmask) { if (sigsetsize != sizeof(compat_sigset_t)) return -EINVAL; if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) return -EFAULT; sigset_from_compat(&ksigmask, &csigmask); - sigsaved = current->blocked; - set_current_blocked(&ksigmask); } - err = sys_epoll_wait(epfd, events, maxevents, timeout); - - /* - * If we changed the signal mask, we need to restore the original one. - * In case we've got a signal while waiting, we do not restore the - * signal mask yet, and we allow do_signal() to deliver the signal on - * the way back to userspace, before the signal mask is restored. - */ - if (sigmask) { - if (err == -EINTR) { - memcpy(¤t->saved_sigmask, &sigsaved, - sizeof(sigsaved)); - set_restore_sigmask(); - } else - set_current_blocked(&sigsaved); - } - - return err; + return epoll_pwait_do(epfd, events, maxevents, kt, + sigmask ? &ksigmask : NULL, sigsetsize); } #endif -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/