ruby-changes:23281
From: naruse <ko1@a...>
Date: Sun, 15 Apr 2012 06:48:04 +0900 (JST)
Subject: [ruby-changes:23281] naruse:r35332 (ruby_1_9_3): merge revision(s) 35249,35250: [Backport #6296]
naruse 2012-04-15 06:47:27 +0900 (Sun, 15 Apr 2012) New Revision: 35332 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35332 Log: merge revision(s) 35249,35250: [Backport #6296] * include/ruby/win32.h (rb_w32_aspawn_flags): add the declaration of new function. * process.c (enum): add EXEC_OPTION_PGROUP and move the position above for the usage in proc_spawn_n(). * process.c (proc_spawn_n): add an argument to pass new option `new_pgroup`. The option specifies CREATE_NEW_PROCESS_GROUP flag to CreateProcessW(). This flag is necessary for the usage of Process.kill on the subprocess on Windows. * process.c (rb_exec_arg_addopt): ditto. * process.c (rb_spawn_process): ditto. * process.c (documentation for rb_f_spawn): add documentation for new option `new_pgroup` of spawn. * test/ruby/test_process.rb (TestProcess#test_execopts_new_pgroup): add tests for option `new_pgroup`. * test/ruby/test_thread.rb (TestThreadGroup#test_thread_timer_and_interrupt): add option `new_pgroup: true` to spawn on Windows. It's needed for Process.kill on a subprocess. * win32/win32.c (CreateChild): add an argument to pass dwCreationFlags of CreateProcessW(). * win32/win32.c (rb_w32_spawn): ditto. * win32/win32.c (rb_w32_aspawn_flags): add new function to pass dwCreationFlags. * win32/win32.c (rb_w32_aspawn): refactor to move the content to rb_w32_aspawn_flags(). [ruby-core:43245][Bug #6131] * test/ruby/test_thread.rb (TestThreadGroup#test_thread_timer_and_interrupt): skip on Windows. Process.kill cannot kill a subprocess if CREATE_NEW_PROCESS_GROUP flag is not specified in a call to CreateProcessW(). * win32/win32.c (CreateChild): revert the usage of CREATE_NEW_PROCESS_GROUP flag for compatibility. [ruby-core:43245][Bug #6131] Modified files: branches/ruby_1_9_3/ChangeLog branches/ruby_1_9_3/include/ruby/win32.h branches/ruby_1_9_3/process.c branches/ruby_1_9_3/test/ruby/test_process.rb branches/ruby_1_9_3/test/ruby/test_thread.rb branches/ruby_1_9_3/version.h branches/ruby_1_9_3/win32/win32.c Index: ruby_1_9_3/include/ruby/win32.h =================================================================== --- ruby_1_9_3/include/ruby/win32.h (revision 35331) +++ ruby_1_9_3/include/ruby/win32.h (revision 35332) @@ -284,6 +284,7 @@ extern rb_pid_t waitpid (rb_pid_t, int *, int); extern rb_pid_t rb_w32_spawn(int, const char *, const char*); extern rb_pid_t rb_w32_aspawn(int, const char *, char *const *); +extern rb_pid_t rb_w32_aspawn_flags(int, const char *, char *const *, DWORD); extern int kill(int, int); extern int fcntl(int, int, ...); extern rb_pid_t rb_w32_getpid(void); Index: ruby_1_9_3/ChangeLog =================================================================== --- ruby_1_9_3/ChangeLog (revision 35331) +++ ruby_1_9_3/ChangeLog (revision 35332) @@ -1,3 +1,54 @@ +Sun Apr 15 06:40:28 2012 Hiroshi Shirosaki <h.shirosaki@g...> + + * include/ruby/win32.h (rb_w32_aspawn_flags): add the declaration of + new function. + + * process.c (enum): add EXEC_OPTION_PGROUP and move the position + above for the usage in proc_spawn_n(). + + * process.c (proc_spawn_n): add an argument to pass new option + `new_pgroup`. The option specifies CREATE_NEW_PROCESS_GROUP flag to + CreateProcessW(). This flag is necessary for the usage of + Process.kill on the subprocess on Windows. + + * process.c (rb_exec_arg_addopt): ditto. + + * process.c (rb_spawn_process): ditto. + + * process.c (documentation for rb_f_spawn): add documentation for new + option `new_pgroup` of spawn. + + * test/ruby/test_process.rb (TestProcess#test_execopts_new_pgroup): + add tests for option `new_pgroup`. + + * test/ruby/test_thread.rb + (TestThreadGroup#test_thread_timer_and_interrupt): + add option `new_pgroup: true` to spawn on Windows. It's needed for + Process.kill on a subprocess. + + * win32/win32.c (CreateChild): add an argument to pass + dwCreationFlags of CreateProcessW(). + + * win32/win32.c (rb_w32_spawn): ditto. + + * win32/win32.c (rb_w32_aspawn_flags): add new function to pass + dwCreationFlags. + + * win32/win32.c (rb_w32_aspawn): refactor to move the content to + rb_w32_aspawn_flags(). + [ruby-core:43245][Bug #6131] + +Sun Apr 15 06:40:28 2012 Hiroshi Shirosaki <h.shirosaki@g...> + + * test/ruby/test_thread.rb + (TestThreadGroup#test_thread_timer_and_interrupt): skip on Windows. + Process.kill cannot kill a subprocess if CREATE_NEW_PROCESS_GROUP + flag is not specified in a call to CreateProcessW(). + + * win32/win32.c (CreateChild): revert the usage of + CREATE_NEW_PROCESS_GROUP flag for compatibility. + [ruby-core:43245][Bug #6131] + Sun Apr 15 04:35:48 2012 Hiroshi Shirosaki <h.shirosaki@g...> * io.c (rb_io_eof): use eof() instead of io_fillbuf(). It's because Index: ruby_1_9_3/win32/win32.c =================================================================== --- ruby_1_9_3/win32/win32.c (revision 35331) +++ ruby_1_9_3/win32/win32.c (revision 35332) @@ -63,7 +63,7 @@ #define TO_SOCKET(x) _get_osfhandle(x) -static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE); +static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE, DWORD); static int has_redirection(const char *); int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout); static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags); @@ -1008,10 +1008,9 @@ static struct ChildRecord * CreateChild(const WCHAR *cmd, const WCHAR *prog, SECURITY_ATTRIBUTES *psa, - HANDLE hInput, HANDLE hOutput, HANDLE hError) + HANDLE hInput, HANDLE hOutput, HANDLE hError, DWORD dwCreationFlags) { BOOL fRet; - DWORD dwCreationFlags; STARTUPINFOW aStartupInfo; PROCESS_INFORMATION aProcessInformation; SECURITY_ATTRIBUTES sa; @@ -1058,7 +1057,7 @@ aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); } - dwCreationFlags = (CREATE_NEW_PROCESS_GROUP | NORMAL_PRIORITY_CLASS); + dwCreationFlags |= NORMAL_PRIORITY_CLASS; if (lstrlenW(cmd) > 32767) { child->pid = 0; /* release the slot */ @@ -1209,14 +1208,14 @@ wshell = shell ? acp_to_wstr(shell, NULL) : NULL; if (v2) ALLOCV_END(v2); - ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL), mode); + ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL, 0), mode); free(wshell); free(wcmd); return ret; } rb_pid_t -rb_w32_aspawn(int mode, const char *prog, char *const *argv) +rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags) { int c_switch = 0; size_t len; @@ -1275,12 +1274,19 @@ if (v) ALLOCV_END(v); wprog = prog ? acp_to_wstr(prog, NULL) : NULL; - ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL), mode); + ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL, flags), mode); free(wprog); free(wcmd); return ret; } +rb_pid_t +rb_w32_aspawn(int mode, const char *prog, char *const *argv) +{ + return rb_w32_aspawn_flags(mode, prog, argv, 0); +} + +/* License: Artistic or GPL */ typedef struct _NtCmdLineElement { struct _NtCmdLineElement *next; char *str; Index: ruby_1_9_3/process.c =================================================================== --- ruby_1_9_3/process.c (revision 35331) +++ ruby_1_9_3/process.c (revision 35332) @@ -1216,6 +1216,21 @@ #endif /* _WIN32 */ } +enum { + EXEC_OPTION_PGROUP, + EXEC_OPTION_RLIMIT, + EXEC_OPTION_UNSETENV_OTHERS, + EXEC_OPTION_ENV, + EXEC_OPTION_CHDIR, + EXEC_OPTION_UMASK, + EXEC_OPTION_DUP2, + EXEC_OPTION_CLOSE, + EXEC_OPTION_OPEN, + EXEC_OPTION_DUP2_CHILD, + EXEC_OPTION_CLOSE_OTHERS, + EXEC_OPTION_NEW_PGROUP +}; + #if defined(_WIN32) #define HAVE_SPAWNV 1 #endif @@ -1261,7 +1276,7 @@ #endif static rb_pid_t -proc_spawn_n(int argc, VALUE *argv, VALUE prog) +proc_spawn_n(int argc, VALUE *argv, VALUE prog, VALUE options) { char **args; int i; @@ -1273,8 +1288,17 @@ args[i] = RSTRING_PTR(argv[i]); } args[i] = (char*) 0; - if (args[0]) + if (args[0]) { +#if defined(_WIN32) + DWORD flags = 0; + if (RTEST(rb_ary_entry(options, EXEC_OPTION_NEW_PGROUP))) { + flags = CREATE_NEW_PROCESS_GROUP; + } + pid = rb_w32_aspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, args, flags); +#else pid = proc_spawn_v(args, prog ? RSTRING_PTR(prog) : 0); +#endif + } ALLOCV_END(v); return pid; } @@ -1322,20 +1346,6 @@ return obj; } -enum { - EXEC_OPTION_PGROUP, - EXEC_OPTION_RLIMIT, - EXEC_OPTION_UNSETENV_OTHERS, - EXEC_OPTION_ENV, - EXEC_OPTION_CHDIR, - EXEC_OPTION_UMASK, - EXEC_OPTION_DUP2, - EXEC_OPTION_CLOSE, - EXEC_OPTION_OPEN, - EXEC_OPTION_DUP2_CHILD, - EXEC_OPTION_CLOSE_OTHERS -}; - static VALUE check_exec_redirect_fd(VALUE v, int iskey) { @@ -1519,6 +1529,16 @@ } else #endif +#ifdef _WIN32 + if (id == rb_intern("new_pgroup")) { + if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_NEW_PGROUP))) { + rb_raise(rb_eArgError, "new_pgroup option specified twice"); + } + val = RTEST(val) ? Qtrue : Qfalse; + rb_ary_store(options, EXEC_OPTION_NEW_PGROUP, val); + } + else +#endif #if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM) if (strncmp("rlimit_", rb_id2name(id), 7) == 0 && (rtype = rlimit_type_by_lname(rb_id2name(id)+7)) != -1) { @@ -3050,7 +3070,7 @@ pid = proc_spawn(RSTRING_PTR(prog)); } else { - pid = proc_spawn_n(argc, argv, prog); + pid = proc_spawn_n(argc, argv, prog, earg->options); } # if defined(_WIN32) if (pid == -1) @@ -3185,6 +3205,9 @@ * :pgroup => true or 0 : make a new process group * :pgroup => pgid : join to specified process group * :pgroup => nil : don't change the process group (default) + * create new process group: Windows only + * :new_pgroup => true : the new process is the root process of a new process group + * :new_pgroup => false : don't create a new process group (default) * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit. * :rlimit_resourcename => limit * :rlimit_resourcename => [cur_limit, max_limit] @@ -3224,6 +3247,7 @@ * If a hash is given as +options+, * it specifies * process group, + * create new process group, * resource limit, * current directory, * umask and @@ -3245,6 +3269,17 @@ * pid = spawn(command, :pgroup=>true) # process leader * pid = spawn(command, :pgroup=>10) # belongs to the process group 10 * + * The <code>:new_pgroup</code> key in +options+ specifies to pass + * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is + * Windows API. This option is only for Windows. + * true means the new process is the root process of the new process group. + * The new process has CTRL+C disabled. This flag is necessary for + * <code>Process.kill(:SIGINT, pid)</code> on the subprocess. + * :new_pgroup is false by default. + * + * pid = spawn(command, :new_pgroup=>true) # new process group + * pid = spawn(command, :new_pgroup=>false) # same process group + * * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit. * <em>foo</em> should be one of resource types such as <code>core</code>. * The corresponding value should be an integer or an array which have one or Index: ruby_1_9_3/version.h =================================================================== --- ruby_1_9_3/version.h (revision 35331) +++ ruby_1_9_3/version.h (revision 35332) @@ -1,5 +1,5 @@ #define RUBY_VERSION "1.9.3" -#define RUBY_PATCHLEVEL 181 +#define RUBY_PATCHLEVEL 182 #define RUBY_RELEASE_DATE "2012-04-15" #define RUBY_RELEASE_YEAR 2012 Index: ruby_1_9_3/test/ruby/test_process.rb =================================================================== --- ruby_1_9_3/test/ruby/test_process.rb (revision 35331) +++ ruby_1_9_3/test/ruby/test_process.rb (revision 35332) @@ -1327,4 +1327,13 @@ end end end + + def test_execopts_new_pgroup + return unless windows? + + assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>true) } + assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>false) } + assert_nothing_raised { spawn(*TRUECOMMAND, :new_pgroup=>true) } + assert_nothing_raised { IO.popen([*TRUECOMMAND, :new_pgroup=>true]) {} } + end end Index: ruby_1_9_3/test/ruby/test_thread.rb =================================================================== --- ruby_1_9_3/test/ruby/test_thread.rb (revision 35331) +++ ruby_1_9_3/test/ruby/test_thread.rb (revision 35332) @@ -691,7 +691,9 @@ t0 = Time.now.to_f pid = nil cmd = 'r,=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; r.read' - s, err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true) do |in_p, out_p, err_p, cpid| + opt = {} + opt[:new_pgroup] = true if /mswin|mingw/ =~ RUBY_PLATFORM + s, err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true, opt) do |in_p, out_p, err_p, cpid| out_p.gets pid = cpid Process.kill(:SIGINT, pid) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/