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

ruby-changes:31360

From: akr <ko1@a...>
Date: Sun, 27 Oct 2013 21:04:19 +0900 (JST)
Subject: [ruby-changes:31360] akr:r43439 (trunk): * ext/readline/readline.c: Include ruby/thread.h for

akr	2013-10-27 21:04:14 +0900 (Sun, 27 Oct 2013)

  New Revision: 43439

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

  Log:
    * ext/readline/readline.c: Include ruby/thread.h for
      rb_thread_call_without_gvl2.
      (readline_rl_instream, readline_rl_outstream): Record FILE
      structures allocated by this extension.
      (getc_body): New function extracted from readline_getc.
      (getc_func): New function.
      (readline_getc): Use rb_thread_call_without_gvl2 to invoke getc_func.
      [ruby-dev:47033] [Bug #8749]
      (clear_rl_instream, clear_rl_outstream): Close FILE structure
      allocated by this extention reliably.  [ruby-core:57951] [Bug #9040]
      (readline_readline): Use clear_rl_instream and clear_rl_outstream.
      (readline_s_set_input): Set readline_rl_instream.
      (readline_s_set_output): Set readline_rl_outstream.
      (Init_readline): Don't call readline_s_set_input because
      readline_getc doesn't block other threads for any FILE structure now.
    
      [ruby-dev:47033] [Bug #8749] reported by Nobuhiro IMAI.
      [ruby-core:57951] [Bug #9040] reporeted by Eamonn Webster.

  Modified files:
    trunk/ChangeLog
    trunk/ext/readline/readline.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 43438)
+++ ChangeLog	(revision 43439)
@@ -1,3 +1,24 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sun Oct 27 20:53:08 2013  Tanaka Akira  <akr@f...>
+
+	* ext/readline/readline.c: Include ruby/thread.h for
+	  rb_thread_call_without_gvl2.
+	  (readline_rl_instream, readline_rl_outstream): Record FILE
+	  structures allocated by this extension.
+	  (getc_body): New function extracted from readline_getc.
+	  (getc_func): New function.
+	  (readline_getc): Use rb_thread_call_without_gvl2 to invoke getc_func.
+	  [ruby-dev:47033] [Bug #8749]
+	  (clear_rl_instream, clear_rl_outstream): Close FILE structure
+	  allocated by this extention reliably.  [ruby-core:57951] [Bug #9040]
+	  (readline_readline): Use clear_rl_instream and clear_rl_outstream.
+	  (readline_s_set_input): Set readline_rl_instream.
+	  (readline_s_set_output): Set readline_rl_outstream.
+	  (Init_readline): Don't call readline_s_set_input because
+	  readline_getc doesn't block other threads for any FILE structure now.
+
+	  [ruby-dev:47033] [Bug #8749] reported by Nobuhiro IMAI.
+	  [ruby-core:57951] [Bug #9040] reporeted by Eamonn Webster.
+
 Sat Oct 26 19:31:28 2013  Kazuki Tsujimoto  <kazuki@c...>
 
 	* gc.c: catch up recent changes to compile on GC_DEBUG,
Index: ext/readline/readline.c
===================================================================
--- ext/readline/readline.c	(revision 43438)
+++ ext/readline/readline.c	(revision 43439)
@@ -35,6 +35,7 @@ https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L35
 
 #include "ruby/ruby.h"
 #include "ruby/io.h"
+#include "ruby/thread.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -128,6 +129,8 @@ static char **readline_attempted_complet https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L129
 
 static VALUE readline_instream;
 static VALUE readline_outstream;
+static FILE *readline_rl_instream;
+static FILE *readline_rl_outstream;
 
 #if defined HAVE_RL_GETC_FUNCTION
 
@@ -135,14 +138,19 @@ static VALUE readline_outstream; https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L138
 #define rl_getc(f) EOF
 #endif
 
-static int readline_getc(FILE *);
+struct getc_struct {
+  FILE *input;
+  int fd;
+  int ret;
+  int err;
+};
+
 static int
-readline_getc(FILE *input)
+getc_body(struct getc_struct *p)
 {
-    rb_io_t *ifp = 0;
-    VALUE c;
-    if (!readline_instream) return rl_getc(input);
-    GetOpenFile(readline_instream, ifp);
+    char ch;
+    ssize_t ss;
+
 #if defined(_WIN32)
     {
         INPUT_RECORD ir;
@@ -150,19 +158,19 @@ readline_getc(FILE *input) https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L158
         static int prior_key = '0';
         for (;;) {
             if (prior_key > 0xff) {
-                prior_key = rl_getc(rl_instream);
+                prior_key = rl_getc(p->input);
                 return prior_key;
             }
-            if (PeekConsoleInput((HANDLE)_get_osfhandle(ifp->fd), &ir, 1, &n)) {
+            if (PeekConsoleInput((HANDLE)_get_osfhandle(p->fd), &ir, 1, &n)) {
                 if (n == 1) {
                     if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
-                        prior_key = rl_getc(rl_instream);
+                        prior_key = rl_getc(p->input);
                         return prior_key;
                     } else {
-                        ReadConsoleInput((HANDLE)_get_osfhandle(ifp->fd), &ir, 1, &n);
+                        ReadConsoleInput((HANDLE)_get_osfhandle(p->fd), &ir, 1, &n);
                     }
                 } else {
-                    HANDLE h = (HANDLE)_get_osfhandle(ifp->fd);
+                    HANDLE h = (HANDLE)_get_osfhandle(p->fd);
                     rb_w32_wait_events(&h, 1, INFINITE);
                 }
             } else {
@@ -171,22 +179,60 @@ readline_getc(FILE *input) https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L179
         }
     }
 #endif
-    c = rb_io_getbyte(readline_instream);
-    if (NIL_P(c)) return EOF;
-#ifdef ESC
-    if (c == INT2FIX(ESC) &&
-        RL_ISSTATE(RL_STATE_ISEARCH) && /* isn't needed in other states? */
-        rb_io_read_pending(ifp)) {
-        int meta = 0;
-        c = rb_io_getbyte(readline_instream);
-        if (FIXNUM_P(c) && isascii(FIX2INT(c))) meta = 1;
-        rb_io_ungetbyte(readline_instream, c);
-        if (meta) rl_execute_next(ESC);
-        return ESC;
+
+    ss = read(p->fd, &ch, 1);
+    if (ss == 0) {
+        errno = 0;
+        return EOF;
+    }
+    if (ss != 1)
+        return EOF;
+    return (unsigned char)ch;
+}
+
+static void *
+getc_func(void *data1)
+{
+    struct getc_struct *p = data1;
+    errno = 0;
+    p->ret = getc_body(p);
+    p->err = errno;
+    return NULL;
+}
+
+static int
+readline_getc(FILE *input)
+{
+    struct getc_struct data;
+    data.input = input;
+    data.fd = fileno(input);
+  again:
+    data.ret = EOF;
+    data.err = EINTR; /* getc_func is not called if already interrupted. */
+    rb_thread_call_without_gvl2(getc_func, &data, RUBY_UBF_IO, NULL);
+    if (data.ret == EOF) {
+        if (data.err == 0) {
+            return EOF;
+        }
+        if (data.err == EINTR) {
+            rb_thread_check_ints();
+            goto again;
+        }
+        if (data.err == EWOULDBLOCK || data.err == EAGAIN) {
+            int ret;
+            if (fileno(input) != data.fd)
+                rb_bug("readline_getc: input closed unexpectedly or memory corrupted");
+            ret = rb_wait_for_single_fd(data.fd, RB_WAITFD_IN, NULL);
+            if (ret != -1 || errno == EINTR)
+                goto again;
+            rb_sys_fail("rb_wait_for_single_fd");
+        }
+        errno = data.err;
+        rb_sys_fail("read");
     }
-#endif
-    return FIX2INT(c);
+    return data.ret;
 }
+
 #elif defined HAVE_RL_EVENT_HOOK
 #define BUSY_WAIT 0
 
@@ -287,6 +333,30 @@ readline_get(VALUE prompt) https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L333
     return (VALUE)readline((char *)prompt);
 }
 
+static void
+clear_rl_instream(void)
+{
+    if (readline_rl_instream) {
+        fclose(readline_rl_instream);
+        if (rl_instream == readline_rl_instream)
+            rl_instream = NULL;
+        readline_rl_instream = NULL;
+    }
+    readline_instream = Qfalse;
+}
+
+static void
+clear_rl_outstream(void)
+{
+    if (readline_rl_outstream) {
+        fclose(readline_rl_outstream);
+        if (rl_outstream == readline_rl_outstream)
+            rl_outstream = NULL;
+        readline_rl_outstream = NULL;
+    }
+    readline_outstream = Qfalse;
+}
+
 /*
  * call-seq:
  *   Readline.readline(prompt = "", add_hist = false) -> string or nil
@@ -390,27 +460,19 @@ readline_readline(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L460
 
     if (readline_instream) {
         rb_io_t *ifp;
-        GetOpenFile(readline_instream, ifp);
+        rb_io_check_initialized(ifp = RFILE(rb_io_taint_check(readline_instream))->fptr);
         if (ifp->fd < 0) {
-            if (rl_instream) {
-                fclose(rl_instream);
-                rl_instream = NULL;
-            }
-            readline_instream = Qfalse;
-            rb_raise(rb_eIOError, "closed stdin");
+            clear_rl_instream();
+            rb_raise(rb_eIOError, "closed readline input");
         }
     }
 
     if (readline_outstream) {
         rb_io_t *ofp;
-        GetOpenFile(readline_outstream, ofp);
+        rb_io_check_initialized(ofp = RFILE(rb_io_taint_check(readline_outstream))->fptr);
         if (ofp->fd < 0) {
-            if (rl_outstream) {
-                fclose(rl_outstream);
-                rl_outstream = NULL;
-            }
-            readline_outstream = Qfalse;
-            rb_raise(rb_eIOError, "closed stdout");
+            clear_rl_outstream();
+            rb_raise(rb_eIOError, "closed readline output");
         }
     }
 
@@ -453,23 +515,6 @@ readline_readline(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L515
     return result;
 }
 
-static void
-clear_rl_instream(void)
-{
-    rb_io_t *ifp;
-    if (rl_instream) {
-        if (readline_instream) {
-            rb_io_check_initialized(ifp = RFILE(rb_io_taint_check(readline_instream))->fptr);
-            if (ifp->fd < 0 || fileno(rl_instream) == ifp->fd) {
-                fclose(rl_instream);
-                rl_instream = NULL;
-            }
-        }
-        readline_instream = Qfalse;
-        rl_instream = NULL;
-    }
-}
-
 /*
  * call-seq:
  *   Readline.input = input
@@ -501,29 +546,12 @@ readline_s_set_input(VALUE self, VALUE i https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L546
             errno = save_errno;
             rb_sys_fail("fdopen");
         }
-        rl_instream = f;
+        rl_instream = readline_rl_instream = f;
         readline_instream = input;
     }
     return input;
 }
 
-static void
-clear_rl_outstream(void)
-{
-    rb_io_t *ofp;
-    if (rl_outstream) {
-        if (readline_outstream) {
-            rb_io_check_initialized(ofp = RFILE(rb_io_taint_check(readline_outstream))->fptr);
-            if (ofp->fd < 0 || fileno(rl_outstream) == ofp->fd) {
-                fclose(rl_outstream);
-                rl_outstream = NULL;
-            }
-        }
-        readline_outstream = Qfalse;
-        rl_outstream = NULL;
-    }
-}
-
 /*
  * call-seq:
  *   Readline.output = output
@@ -555,7 +583,7 @@ readline_s_set_output(VALUE self, VALUE https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L583
             errno = save_errno;
             rb_sys_fail("fdopen");
         }
-        rl_outstream = f;
+        rl_outstream = readline_rl_outstream = f;
         readline_outstream = output;
     }
     return output;
@@ -1955,6 +1983,4 @@ Init_readline() https://github.com/ruby/ruby/blob/trunk/ext/readline/readline.c#L1983
 
     rb_gc_register_address(&readline_instream);
     rb_gc_register_address(&readline_outstream);
-
-    readline_s_set_input(mReadline, rb_stdin);
 }

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

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