summaryrefslogtreecommitdiff
path: root/ext/readline
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-10-27 12:04:14 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-10-27 12:04:14 +0000
commitd5dad14041a06dc3a2dc497c7812a4ac787aec5b (patch)
tree3c25dea1173d9e755313ec269ce6f27ba6187462 /ext/readline
parentd956453a9816cbc4f731f8c1a188c0bd53982646 (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/readline')
-rw-r--r--ext/readline/readline.c180
1 files changed, 103 insertions, 77 deletions
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
index 0f76d1a902..269ebc96eb 100644
--- a/ext/readline/readline.c
+++ b/ext/readline/readline.c
@@ -35,6 +35,7 @@
#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_completion_function(const char *text,
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;
#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)
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)
}
}
#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;
}
-#endif
- return FIX2INT(c);
+ 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");
+ }
+ return data.ret;
}
+
#elif defined HAVE_RL_EVENT_HOOK
#define BUSY_WAIT 0
@@ -287,6 +333,30 @@ readline_get(VALUE prompt)
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, VALUE self)
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, VALUE self)
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 input)
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 output)
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()
rb_gc_register_address(&readline_instream);
rb_gc_register_address(&readline_outstream);
-
- readline_s_set_input(mReadline, rb_stdin);
}