[前][次][番号順一覧][スレッド一覧]

ruby-changes:39224

From: normal <ko1@a...>
Date: Tue, 21 Jul 2015 05:34:13 +0900 (JST)
Subject: [ruby-changes:39224] normal:r51305 (trunk): io.c: IO.copy_stream uses poll on Linux

normal	2015-07-21 05:33:50 +0900 (Tue, 21 Jul 2015)

  New Revision: 51305

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51305

  Log:
    io.c: IO.copy_stream uses poll on Linux
    
    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 [ruby-core:35572].  So favor using poll in case IO.copy_stream
    encounters 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 (nogvl_wait_for_single_fd): new function for Linux
      (maygvl_copy_stream_wait_read): Linux-specific version
      (nogvl_copy_stream_wait_write): use nogvl_wait_for_single_fd
      [ruby-core:70051] [Feature #11377]

  Modified files:
    trunk/ChangeLog
    trunk/io.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 51304)
+++ ChangeLog	(revision 51305)
@@ -1,3 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Jul 21 05:20:21 2015  Eric Wong  <e@8...>
+
+	* io.c (nogvl_wait_for_single_fd): new function for Linux
+	  (maygvl_copy_stream_wait_read): Linux-specific version
+	  (nogvl_copy_stream_wait_write): use nogvl_wait_for_single_fd
+	  [ruby-core:70051] [Feature #11377]
+
 Mon Jul 20 15:04:30 2015  Eric Wong  <e@8...>
 
 	* parse.y (parser_initialize): avoid redundant zero-ing
Index: io.c
===================================================================
--- io.c	(revision 51304)
+++ io.c	(revision 51305)
@@ -10087,6 +10087,49 @@ maygvl_copy_stream_continue_p(int has_gv https://github.com/ruby/ruby/blob/trunk/io.c#L10087
     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"
+#  define USE_POLL 0
+#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, 0);
+}
+
+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 +10157,7 @@ maygvl_copy_stream_wait_read(int has_gvl https://github.com/ruby/ruby/blob/trunk/io.c#L10157
     }
     return 0;
 }
+#endif /* !USE_POLL */
 
 static int
 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
@@ -10121,13 +10165,17 @@ nogvl_copy_stream_wait_write(struct copy https://github.com/ruby/ruby/blob/trunk/io.c#L10165
     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;
     }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]