зеркало из https://github.com/github/ruby.git
* 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:
Родитель
fc83ebb037
Коммит
42109a02f0
40
ChangeLog
40
ChangeLog
|
@ -1,3 +1,43 @@
|
|||
Sat Apr 7 22:35:36 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
|
||||
|
||||
* 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]
|
||||
|
||||
Sat Apr 7 22:32:00 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
|
||||
|
||||
* test/ruby/test_thread.rb
|
||||
|
|
|
@ -285,6 +285,7 @@ extern int gettimeofday(struct timeval *, struct timezone *);
|
|||
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);
|
||||
|
|
69
process.c
69
process.c
|
@ -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
|
||||
|
|
|
@ -1360,4 +1360,13 @@ class TestProcess < Test::Unit::TestCase
|
|||
assert(io.close_on_exec?)
|
||||
}
|
||||
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
|
||||
|
|
|
@ -681,12 +681,13 @@ class TestThreadGroup < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_thread_timer_and_interrupt
|
||||
skip 'Process.kill cannot kill a subprocess' if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||
bug5757 = '[ruby-dev:44985]'
|
||||
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)
|
||||
|
|
|
@ -72,7 +72,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);
|
||||
|
@ -1087,10 +1087,9 @@ child_result(struct ChildRecord *child, int mode)
|
|||
/* License: Ruby's */
|
||||
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;
|
||||
|
@ -1137,7 +1136,7 @@ CreateChild(const WCHAR *cmd, const WCHAR *prog, SECURITY_ATTRIBUTES *psa,
|
|||
aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
}
|
||||
|
||||
dwCreationFlags = NORMAL_PRIORITY_CLASS;
|
||||
dwCreationFlags |= NORMAL_PRIORITY_CLASS;
|
||||
|
||||
if (lstrlenW(cmd) > 32767) {
|
||||
child->pid = 0; /* release the slot */
|
||||
|
@ -1290,7 +1289,7 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
|
|||
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;
|
||||
|
@ -1298,7 +1297,7 @@ rb_w32_spawn(int mode, const char *cmd, const char *prog)
|
|||
|
||||
/* License: Artistic or GPL */
|
||||
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;
|
||||
|
@ -1357,12 +1356,18 @@ rb_w32_aspawn(int mode, const char *prog, char *const *argv)
|
|||
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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче