* 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]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35250 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shirosaki 2012-04-07 14:10:30 +00:00
parent fc83ebb037
commit 42109a02f0
6 changed files with 117 additions and 26 deletions

View file

@ -1207,6 +1207,21 @@ rb_proc_exec(const char *str)
#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
@ -1252,7 +1267,7 @@ proc_spawn_v(char **argv, char *prog)
#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;
@ -1264,8 +1279,17 @@ proc_spawn_n(int argc, VALUE *argv, VALUE prog)
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;
}
@ -1313,20 +1337,6 @@ hide_obj(VALUE obj)
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)
{
@ -1510,6 +1520,16 @@ rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val)
}
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) {
@ -3006,7 +3026,7 @@ rb_spawn_process(struct rb_exec_arg *earg, VALUE prog, char *errmsg, size_t errm
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)
@ -3141,6 +3161,9 @@ rb_f_system(int argc, VALUE *argv)
* :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]
@ -3179,6 +3202,7 @@ rb_f_system(int argc, VALUE *argv)
* If a hash is given as +options+,
* it specifies
* process group,
* create new process group,
* resource limit,
* current directory,
* umask and
@ -3200,6 +3224,17 @@ rb_f_system(int argc, VALUE *argv)
* 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