From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS16276 149.202.0.0/16 X-Spam-Status: No, score=-2.0 required=3.0 tests=AWL,BAYES_00,RCVD_IN_XBL shortcircuit=no autolearn=no version=3.3.2 X-Original-To: spew@80x24.org Received: from 80x24.org (3.tor.exit.babylon.network [149.202.98.161]) by dcvr.yhbt.net (Postfix) with ESMTP id 345B263637A for ; Mon, 20 Jul 2015 19:58:33 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH] io.c: IO.copy_stream uses poll on Linux Date: Mon, 20 Jul 2015 19:58:30 +0000 Message-Id: <1437422310-23604-1-git-send-email-e@80x24.org> List-Id: poll and ppoll have a superior API which doesn't require the kernel to scan a potentially large bitmap to find a high-numbered FD. So favor using poll in case IO.copy_stream encounteres a non-blocking FD. We cannot reliably use poll on most OSes, because file types (e.g. FIFOs) which work with select may not work with poll. Fortunately, Linux uses a common notification mechanism between all select/poll/epoll variants, so all file types are equally supported between the notification mechanisms. Verified by watching strace on the following scripts: --- maygvl_copy_stream_wait_read --- require 'io/nonblock' r, w = IO.pipe r.nonblock = true IO.copy_stream(r, "/dev/null") --- nogvl_copy_stream_wait_write --- require 'io/nonblock' r, w = IO.pipe w.nonblock = true IO.copy_stream("/dev/zero", w) --- io.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/io.c b/io.c index 3616d0a..b776f76 100644 --- a/io.c +++ b/io.c @@ -10087,6 +10087,48 @@ maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp) return FALSE; } +/* non-Linux poll may not work on all FDs */ +#if defined(HAVE_POLL) && defined(__linux__) +# define USE_POLL 1 +# define IOWAIT_SYSCALL "poll" +#else +# define IOWAIT_SYSCALL "select" +#endif + +#if USE_POLL +static int +nogvl_wait_for_single_fd(int fd, short events) +{ + struct pollfd fds; + + fds.fd = fd; + fds.events = events; + + return poll(&fds, 1, NULL); +} + +static int +maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp) +{ + int ret; + + do { + if (has_gvl) { + ret = rb_wait_for_single_fd(stp->src_fd, RB_WAITFD_IN, NULL); + } + else { + ret = nogvl_wait_for_single_fd(stp->src_fd, POLLIN); + } + } while (ret == -1 && maygvl_copy_stream_continue_p(has_gvl, stp)); + + if (ret == -1) { + stp->syserr = "poll"; + stp->error_no = errno; + return -1; + } + return 0; +} +#else /* !USE_POLL */ static int maygvl_select(int has_gvl, int n, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout) { @@ -10114,6 +10156,7 @@ maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp) } return 0; } +#endif /* !USE_POLL */ static int nogvl_copy_stream_wait_write(struct copy_stream_struct *stp) @@ -10121,13 +10164,17 @@ nogvl_copy_stream_wait_write(struct copy_stream_struct *stp) int ret; do { +#if USE_POLL + ret = nogvl_wait_for_single_fd(stp->dst_fd, POLLOUT); +#else rb_fd_zero(&stp->fds); rb_fd_set(stp->dst_fd, &stp->fds); ret = rb_fd_select(rb_fd_max(&stp->fds), NULL, &stp->fds, NULL, NULL); +#endif } while (ret == -1 && maygvl_copy_stream_continue_p(0, stp)); if (ret == -1) { - stp->syserr = "select"; + stp->syserr = IOWAIT_SYSCALL; stp->error_no = errno; return -1; } -- EW