From: Tanaka Akira <akr@...>
Date: 2013-08-08T10:19:47+09:00
Subject: [ruby-dev:47037] Re: [ruby-trunk - Bug #8749][Open] Readline.readline stops STDOUT?

2013年8月8日 8:05 Tanaka Akira <akr@fsij.org>:

> でも、readline_getc では単に GVL を外して rl_getc を呼べばいいのではないか、という気もします。

こうするなら、こうですかねぇ。

% svn diff --diff-cmd diff -x '-u -p'
Index: ext/readline/readline.c
===================================================================
--- ext/readline/readline.c	(revision 42429)
+++ ext/readline/readline.c	(working copy)
@@ -35,6 +35,7 @@

 #include "ruby/ruby.h"
 #include "ruby/io.h"
+#include "ruby/thread.h"

 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -135,35 +136,35 @@ static VALUE readline_outstream;
 #define rl_getc(f) EOF
 #endif

-static int readline_getc(FILE *);
+struct getc_struct {
+  FILE *input;
+  int ret;
+};
+
 static int
-readline_getc(FILE *input)
+getc_body(FILE *input)
 {
-    rb_io_t *ifp = 0;
-    VALUE c;
-    if (!readline_instream) return rl_getc(input);
-    GetOpenFile(readline_instream, ifp);
-    if (rl_instream != ifp->stdio_file) return rl_getc(input);
 #if defined(_WIN32)
+    int fd = fileno(input);
     {
         INPUT_RECORD ir;
         int n;
         static int prior_key = '0';
         for (;;) {
             if (prior_key > 0xff) {
-                prior_key = rl_getc(ifp->stdio_file);
+                prior_key = rl_getc(input);
                 return prior_key;
             }
-            if (PeekConsoleInput((HANDLE)_get_osfhandle(ifp->fd),
&ir, 1, &n)) {
+            if (PeekConsoleInput((HANDLE)_get_osfhandle(fd), &ir, 1, &n)) {
                 if (n == 1) {
                     if (ir.EventType == KEY_EVENT &&
ir.Event.KeyEvent.bKeyDown) {
-                        prior_key = rl_getc(ifp->stdio_file);
+                        prior_key = rl_getc(input);
                         return prior_key;
                     } else {
-
ReadConsoleInput((HANDLE)_get_osfhandle(ifp->fd), &ir, 1, &n);
+                        ReadConsoleInput((HANDLE)_get_osfhandle(fd),
&ir, 1, &n);
                     }
                 } else {
-                    HANDLE h = (HANDLE)_get_osfhandle(ifp->fd);
+                    HANDLE h = (HANDLE)_get_osfhandle(fd);
                     rb_w32_wait_events(&h, 1, INFINITE);
                 }
             } else {
@@ -172,21 +173,27 @@ readline_getc(FILE *input)
         }
     }
 #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;
-    }
-#endif
-    return FIX2INT(c);
+    return rl_getc(input);
+}
+
+static void *
+getc_func(void *data1)
+{
+    struct getc_struct *p = data1;
+    FILE *input = p->input;
+    p->ret = getc_body(input);
+    return NULL;
+}
+
+static int readline_getc(FILE *);
+static int
+readline_getc(FILE *input)
+{
+    struct getc_struct data;
+    data.input = input;
+    data.ret = -1;
+    rb_thread_call_without_gvl(getc_func, &data, RUBY_UBF_IO, NULL);
+    return data.ret;
 }
 #elif defined HAVE_RL_EVENT_HOOK
 #define BUSY_WAIT 0

arton さんが書いた Windows 用のコードが必要かどうかはよくわからないのですが、
いちおう残してあります。テストはしていません。
-- 
[田中 哲][たなか あきら][Tanaka Akira]
_______________________________________________
ruby-dev mailing list
ruby-dev@ruby-lang.org
http://lists.ruby-lang.org/cgi-bin/mailman/listinfo/ruby-dev