* [PATCH] io.c: IO.copy_stream uses poll on Linux
@ 2015-07-20 19:58 Eric Wong
0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2015-07-20 19:58 UTC (permalink / raw)
To: spew
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
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH] io.c: IO.copy_stream uses poll on Linux
@ 2015-07-20 20:07 Eric Wong
0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2015-07-20 20:07 UTC (permalink / raw)
To: spew
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
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2015-07-20 20:08 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-20 20:07 [PATCH] io.c: IO.copy_stream uses poll on Linux Eric Wong
-- strict thread matches above, loose matches on Subject: below --
2015-07-20 19:58 Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).