From: Tanaka Akira Date: 2013-08-08T22:37:10+09:00 Subject: [ruby-dev:47041] Re: [ruby-trunk - Bug #8749][Open] Readline.readline stops STDOUT? 2013/8/8 Tanaka Akira : > 2013年8月8日 8:05 Tanaka Akira : > >> でも、readline_getc では単に GVL を外して rl_getc を呼べばいいのではないか、という気もします。 > > こうするなら、こうですかねぇ。 おっと、これだと ^C が効きませんでした。 こうかな。 % svn diff --diff-cmd diff -x '-u -p' Index: ext/readline/readline.c =================================================================== --- ext/readline/readline.c (revision 42432) +++ 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 @@ -135,15 +136,19 @@ 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); + int fd = fileno(input); + char ch; + ssize_t ss; + int ret; + #if defined(_WIN32) { INPUT_RECORD ir; @@ -151,19 +156,19 @@ readline_getc(FILE *input) 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 +177,56 @@ 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; - } + + again: + ss = read(fd, &ch, 1); + if (ss == 0) + return EOF; + if (ss == -1) { + if (errno == EINTR) + return EOF; + if (errno == EWOULDBLOCK || errno == EAGAIN) { +#ifdef HAVE_POLL + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + ret = poll(&pfd, 1, -1); + if (ret < 0) + return EOF; +#else + rb_fdset_t rfds; + rb_fd_init(&rfds); + rb_fd_set(fd, &rfds); + ret = rb_fd_select(fd+1, &rfds, NULL, NULL, NULL); + rb_fd_term(&rfds); + if (ret < 0) + return EOF; #endif - return FIX2INT(c); + goto again; + } + } + return (unsigned char)ch; +} + +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 -- [田中 哲][たなか あきら][Tanaka Akira]