summaryrefslogtreecommitdiff
path: root/ruby.c
diff options
context:
space:
mode:
authorkosaki <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-17 21:09:10 +0000
committerkosaki <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-17 21:09:10 +0000
commitbc8687acd62584bf2ba9a951289f3f25a4de7229 (patch)
treedfe6baf6db8c28f6514d1b795b9c8eca308ee462 /ruby.c
parent9ec8d4ef30273fb96216a898de2af319479a2a5c (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.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/ruby.c b/ruby.c
index 044cf0d..16abaaf 100644
--- a/ruby.c
+++ b/ruby.c
@@ -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;