Bug #6131 ยป process.patch
include/ruby/win32.h | ||
---|---|---|
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);
|
process.c | ||
---|---|---|
#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
|
||
... | ... | |
#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;
|
||
... | ... | |
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;
|
||
}
|
||
... | ... | |
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)
|
||
{
|
||
... | ... | |
}
|
||
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) {
|
||
... | ... | |
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)
|
||
... | ... | |
* :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]
|
||
... | ... | |
* If a hash is given as +options+,
|
||
* it specifies
|
||
* process group,
|
||
* create new process group,
|
||
* resource limit,
|
||
* current directory,
|
||
* umask and
|
||
... | ... | |
* 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
|
test/ruby/test_process.rb | ||
---|---|---|
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
|
test/ruby/test_thread.rb | ||
---|---|---|
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)
|
win32/win32.c | ||
---|---|---|
#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);
|
||
... | ... | |
/* 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;
|
||
... | ... | |
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 */
|
||
... | ... | |
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;
|
||
... | ... | |
/* 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;
|
||
... | ... | |
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;
|