diff options
author | kosaki <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-10-17 21:09:10 +0000 |
---|---|---|
committer | kosaki <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-10-17 21:09:10 +0000 |
commit | bc8687acd62584bf2ba9a951289f3f25a4de7229 (patch) | |
tree | dfe6baf6db8c28f6514d1b795b9c8eca308ee462 /ruby.c | |
parent | 9ec8d4ef30273fb96216a898de2af319479a2a5c (diff) |
* ruby.c (open_load_file): reset O_NONBLOCK after open.
Even if S_ISREG() is true, the file may be file on FUSE filesystem
or something. We can't assume O_NONBLOCK is safe.
Moreover, we should wait if the path is point to FIFO. That's
FIFO semantics. GVL should be transparent from ruby script.
Thus, just reopen without O_NONBLOCK for filling the requirements.
[Bug #11060][Bug #11559]
* ruby.c (loadopen_func): new for the above.
* file.c (ruby_is_fd_loadable): new. for checks loadable file type
of not.
* file.c (rb_file_load_ok): use ruby_is_fd_loadble()
* internal.h: add ruby_is_fd_loadble()
* common.mk: now, ruby.o depend on thread.h.
* test/ruby/test_require.rb
(TestRequire#test_loading_fifo_threading_success): new test.
This test successful case that loading from FIFO.
* test/ruby/test_require.rb
(TestRequire#test_loading_fifo_threading_raise): rename from
test_loading_fifo_threading. You souldn't rescue an exception
if you test raise or not.
Moreover, this case should be caught IOError because load(FIFO)
should be blocked until given any input.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52151 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ruby.c')
-rw-r--r-- | ruby.c | 57 |
1 files changed, 48 insertions, 9 deletions
@@ -16,6 +16,7 @@ #include <sys/cygwin.h> #endif #include "internal.h" +#include "ruby/thread.h" #include "eval_intern.h" #include "dln.h" #include <stdio.h> @@ -1725,21 +1726,36 @@ load_file_internal(VALUE argp_v) return (VALUE)tree; } +static void * +loadopen_func(void *arg) +{ + int fd; + fd = rb_cloexec_open((const char *)arg, O_RDONLY, 0); + if (fd >= 0) + rb_update_max_fd(fd); + + return (void *)(VALUE)fd; +} + static VALUE open_load_file(VALUE fname_v, int *xflag) { const char *fname = StringValueCStr(fname_v); VALUE f; + int e; if (RSTRING_LEN(fname_v) == 1 && fname[0] == '-') { f = rb_stdin; } else { - int fd, mode = O_RDONLY; -#if defined O_NONBLOCK && !(O_NONBLOCK & O_ACCMODE) + int fd; + /* open(2) may block if fname is point to FIFO and it's empty. Let's + use O_NONBLOCK. */ + int mode = O_RDONLY; +#if defined O_NONBLOCK && HAVE_FCNTL && !(O_NONBLOCK & O_ACCMODE) /* TODO: fix conflicting O_NONBLOCK in ruby/win32.h */ mode |= O_NONBLOCK; -#elif defined O_NDELAY && !(O_NDELAY & O_ACCMODE) +#elif defined O_NDELAY && HAVE_FCNTL && !(O_NDELAY & O_ACCMODE) mod |= O_NDELAY; #endif #if defined DOSISH || defined __CYGWIN__ @@ -1751,21 +1767,44 @@ open_load_file(VALUE fname_v, int *xflag) } } #endif + if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) { rb_load_fail(fname_v, strerror(errno)); } - rb_update_max_fd(fd); -#if !defined DOSISH && !defined __CYGWIN__ + rb_update_max_fd(fd); + +#ifdef HAVE_FCNTL + /* disabling O_NONBLOCK */ + if (fcntl(fd, F_SETFL, 0) < 0) { + e = errno; + close(fd); + rb_load_fail(fname_v, strerror(e)); + } +#endif + +#ifdef S_ISFIFO { struct stat st; - int e; - if ((fstat(fd, &st) != 0) && (e = errno, 1) || - (S_ISDIR(st.st_mode) && (e = EISDIR, 1))) { - (void)close(fd); + if (fstat(fd, &st) != 0) { + e = errno; + close(fd); rb_load_fail(fname_v, strerror(e)); } + if (S_ISFIFO(st.st_mode)) { + /* We need to wait if FIFO is empty. So, let's reopen it. */ + close(fd); + fd = (int)(VALUE)rb_thread_call_without_gvl(loadopen_func, + (void *)fname, RUBY_UBF_IO, 0); + if (fd < 0) + rb_load_fail(fname_v, strerror(errno)); + } } #endif + if (!ruby_is_fd_loadable(fd)) { + close(fd); + rb_load_fail(fname_v, strerror(errno)); + } + f = rb_io_fdopen(fd, mode, fname); } return f; |