ruby-changes:38117
From: akr <ko1@a...>
Date: Fri, 10 Apr 2015 01:33:19 +0900 (JST)
Subject: [ruby-changes:38117] akr:r50198 (trunk): * process.c: Release GVL when opening a file in spawn() to avoid whole
akr 2015-04-10 01:33:02 +0900 (Fri, 10 Apr 2015) New Revision: 50198 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=50198 Log: * process.c: Release GVL when opening a file in spawn() to avoid whole process blocking when opening a named pipe. (open_func): New function. (rb_execarg_parent_start1): Extracted from rb_execarg_parent_start and use rb_thread_call_without_gvl2 to release GVL when opening a file. (rb_execarg_parent_start): Invoke rb_execarg_parent_start1 via rb_protect and invoke rb_execarg_parent_end when error. Modified files: trunk/ChangeLog trunk/process.c trunk/test/ruby/test_process.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 50197) +++ ChangeLog (revision 50198) @@ -1,3 +1,13 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Apr 10 01:29:05 2015 Tanaka Akira <akr@f...> + + * process.c: Release GVL when opening a file in spawn() to avoid whole + process blocking when opening a named pipe. + (open_func): New function. + (rb_execarg_parent_start1): Extracted from rb_execarg_parent_start and + use rb_thread_call_without_gvl2 to release GVL when opening a file. + (rb_execarg_parent_start): Invoke rb_execarg_parent_start1 via + rb_protect and invoke rb_execarg_parent_end when error. + Thu Apr 9 22:19:19 2015 Tanaka Akira <akr@f...> * process.c (redirect_open): Removed. Index: process.c =================================================================== --- process.c (revision 50197) +++ process.c (revision 50198) @@ -322,7 +322,7 @@ redirect_dup2(int oldfd, int newfd) https://github.com/ruby/ruby/blob/trunk/process.c#L322 { int ret; ret = dup2(oldfd, newfd); - ttyprintf("dup2(%d, %d)\n", oldfd, newfd); + ttyprintf("dup2(%d, %d) => %d\n", oldfd, newfd, ret); return ret; } @@ -331,7 +331,25 @@ redirect_close(int fd) https://github.com/ruby/ruby/blob/trunk/process.c#L331 { int ret; ret = close(fd); - ttyprintf("close(%d)\n", fd); + ttyprintf("close(%d) => %d\n", fd, ret); + return ret; +} + +static int +parent_redirect_open(const char *pathname, int flags, mode_t perm) +{ + int ret; + ret = rb_cloexec_open(pathname, flags, perm); + ttyprintf("parent_open(\"%s\", 0x%x, 0%o) => %d\n", pathname, flags, perm, ret); + return ret; +} + +static int +parent_redirect_close(int fd) +{ + int ret; + ret = close(fd); + ttyprintf("parent_close(%d) => %d\n", fd, ret); return ret; } @@ -339,6 +357,8 @@ redirect_close(int fd) https://github.com/ruby/ruby/blob/trunk/process.c#L357 #define redirect_dup(oldfd) dup(oldfd) #define redirect_dup2(oldfd, newfd) dup2((oldfd), (newfd)) #define redirect_close(fd) close(fd) +#define parent_redirect_open(pathname, flags, perm) rb_cloexec_open((pathname), (flags), (perm)) +#define parent_redirect_close(fd) close(fd) #endif /* @@ -2265,8 +2285,27 @@ fill_envp_buf_i(st_data_t st_key, st_dat https://github.com/ruby/ruby/blob/trunk/process.c#L2285 static long run_exec_dup2_tmpbuf_size(long n); -void -rb_execarg_parent_start(VALUE execarg_obj) +struct open_struct { + int entered; + VALUE fname; + int oflags; + mode_t perm; + int ret; + int err; +}; + +static void * +open_func(void *ptr) +{ + struct open_struct *data = ptr; + const char *fname = RSTRING_PTR(data->fname); + data->entered = 1; + data->ret = parent_redirect_open(fname, data->oflags, data->perm); + return NULL; +} + +static VALUE +rb_execarg_parent_start1(VALUE execarg_obj) { struct rb_execarg *eargp = rb_execarg_get(execarg_obj); int unsetenv_others; @@ -2286,15 +2325,23 @@ rb_execarg_parent_start(VALUE execarg_ob https://github.com/ruby/ruby/blob/trunk/process.c#L2325 VALUE fd2v = RARRAY_AREF(param, 3); int fd2; if (NIL_P(fd2v)) { - const char *path; + struct open_struct open_data; FilePathValue(vpath); - path = StringValueCStr(vpath); - fd2 = rb_cloexec_open(path, flags, perm); - if (fd2 == -1) { - goto error; - } + do { + rb_thread_check_ints(); + open_data.entered = 0; + open_data.fname = vpath; + open_data.oflags = flags; + open_data.perm = perm; + open_data.ret = -1; + rb_thread_call_without_gvl2(open_func, (void *)&open_data, RUBY_UBF_IO, 0); + } while (!open_data.entered); + fd2 = open_data.ret; + if (fd2 == -1) + rb_sys_fail("open"); rb_update_max_fd(fd2); RARRAY_ASET(param, 3, INT2FIX(fd2)); + rb_thread_check_ints(); } else { fd2 = NUM2INT(fd2v); @@ -2370,11 +2417,18 @@ rb_execarg_parent_start(VALUE execarg_ob https://github.com/ruby/ruby/blob/trunk/process.c#L2417 } RB_GC_GUARD(execarg_obj); - return; + return Qnil; +} - error: - rb_execarg_parent_end(execarg_obj); - rb_sys_fail("open"); +void +rb_execarg_parent_start(VALUE execarg_obj) +{ + int state; + rb_protect(rb_execarg_parent_start1, execarg_obj, &state); + if (state) { + rb_execarg_parent_end(execarg_obj); + rb_jump_tag(state); + } } void @@ -2395,7 +2449,7 @@ rb_execarg_parent_end(VALUE execarg_obj) https://github.com/ruby/ruby/blob/trunk/process.c#L2449 fd2v = RARRAY_AREF(param, 3); if (!NIL_P(fd2v)) { fd2 = FIX2INT(fd2v); - close(fd2); + parent_redirect_close(fd2); RARRAY_ASET(param, 3, Qnil); } } Index: test/ruby/test_process.rb =================================================================== --- test/ruby/test_process.rb (revision 50197) +++ test/ruby/test_process.rb (revision 50198) @@ -558,6 +558,22 @@ class TestProcess < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_process.rb#L558 } end unless windows? # passing non-stdio fds is not supported on Windows + def test_execopts_redirect_open_fifo + with_tmpchdir {|d| + system("mknod fifo p") + return if !$?.success? + assert(FileTest.pipe?("fifo")) + t1 = Thread.new { + system(*ECHO["output to fifo"], :out=>"fifo") + } + t2 = Thread.new { + IO.popen([*CAT, :in=>"fifo"]) {|f| f.read } + } + v1, v2 = assert_join_threads([t1, t2]) + assert_equal("output to fifo\n", v2) + } + end + def test_execopts_redirect_pipe with_pipe {|r1, w1| with_pipe {|r2, w2| -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/