process.patch

Hiroshi Shirosaki, 04/03/2012 10:44 PM

Download (9.09 KB)

View differences:

include/ruby/win32.h
285 285
extern rb_pid_t waitpid (rb_pid_t, int *, int);
286 286
extern rb_pid_t rb_w32_spawn(int, const char *, const char*);
287 287
extern rb_pid_t rb_w32_aspawn(int, const char *, char *const *);
288
extern rb_pid_t rb_w32_aspawn_flags(int, const char *, char *const *, DWORD);
288 289
extern int kill(int, int);
289 290
extern int fcntl(int, int, ...);
290 291
extern rb_pid_t rb_w32_getpid(void);
process.c
1207 1207
#endif	/* _WIN32 */
1208 1208
}
1209 1209

  
1210
enum {
1211
    EXEC_OPTION_PGROUP,
1212
    EXEC_OPTION_RLIMIT,
1213
    EXEC_OPTION_UNSETENV_OTHERS,
1214
    EXEC_OPTION_ENV,
1215
    EXEC_OPTION_CHDIR,
1216
    EXEC_OPTION_UMASK,
1217
    EXEC_OPTION_DUP2,
1218
    EXEC_OPTION_CLOSE,
1219
    EXEC_OPTION_OPEN,
1220
    EXEC_OPTION_DUP2_CHILD,
1221
    EXEC_OPTION_CLOSE_OTHERS,
1222
    EXEC_OPTION_NEW_PGROUP
1223
};
1224

  
1210 1225
#if defined(_WIN32)
1211 1226
#define HAVE_SPAWNV 1
1212 1227
#endif
......
1252 1267
#endif
1253 1268

  
1254 1269
static rb_pid_t
1255
proc_spawn_n(int argc, VALUE *argv, VALUE prog)
1270
proc_spawn_n(int argc, VALUE *argv, VALUE prog, VALUE options)
1256 1271
{
1257 1272
    char **args;
1258 1273
    int i;
......
1264 1279
	args[i] = RSTRING_PTR(argv[i]);
1265 1280
    }
1266 1281
    args[i] = (char*) 0;
1267
    if (args[0])
1282
    if (args[0]) {
1283
#if defined(_WIN32)
1284
	DWORD flags = 0;
1285
	if (RTEST(rb_ary_entry(options, EXEC_OPTION_NEW_PGROUP))) {
1286
	    flags = CREATE_NEW_PROCESS_GROUP;
1287
	}
1288
	pid = rb_w32_aspawn_flags(P_NOWAIT, prog ? RSTRING_PTR(prog) : 0, args, flags);
1289
#else
1268 1290
	pid = proc_spawn_v(args, prog ? RSTRING_PTR(prog) : 0);
1291
#endif
1292
    }
1269 1293
    ALLOCV_END(v);
1270 1294
    return pid;
1271 1295
}
......
1313 1337
    return obj;
1314 1338
}
1315 1339

  
1316
enum {
1317
    EXEC_OPTION_PGROUP,
1318
    EXEC_OPTION_RLIMIT,
1319
    EXEC_OPTION_UNSETENV_OTHERS,
1320
    EXEC_OPTION_ENV,
1321
    EXEC_OPTION_CHDIR,
1322
    EXEC_OPTION_UMASK,
1323
    EXEC_OPTION_DUP2,
1324
    EXEC_OPTION_CLOSE,
1325
    EXEC_OPTION_OPEN,
1326
    EXEC_OPTION_DUP2_CHILD,
1327
    EXEC_OPTION_CLOSE_OTHERS
1328
};
1329

  
1330 1340
static VALUE
1331 1341
check_exec_redirect_fd(VALUE v, int iskey)
1332 1342
{
......
1510 1520
        }
1511 1521
        else
1512 1522
#endif
1523
#ifdef _WIN32
1524
        if (id == rb_intern("new_pgroup")) {
1525
            if (!NIL_P(rb_ary_entry(options, EXEC_OPTION_NEW_PGROUP))) {
1526
                rb_raise(rb_eArgError, "new_pgroup option specified twice");
1527
            }
1528
            val = RTEST(val) ? Qtrue : Qfalse;
1529
            rb_ary_store(options, EXEC_OPTION_NEW_PGROUP, val);
1530
        }
1531
        else
1532
#endif
1513 1533
#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
1514 1534
        if (strncmp("rlimit_", rb_id2name(id), 7) == 0 &&
1515 1535
            (rtype = rlimit_type_by_lname(rb_id2name(id)+7)) != -1) {
......
3006 3026
	pid = proc_spawn(RSTRING_PTR(prog));
3007 3027
    }
3008 3028
    else {
3009
	pid = proc_spawn_n(argc, argv, prog);
3029
	pid = proc_spawn_n(argc, argv, prog, earg->options);
3010 3030
    }
3011 3031
#  if defined(_WIN32)
3012 3032
    if (pid == -1)
......
3141 3161
 *        :pgroup => true or 0 : make a new process group
3142 3162
 *        :pgroup => pgid      : join to specified process group
3143 3163
 *        :pgroup => nil       : don't change the process group (default)
3164
 *      create new process group: Windows only
3165
 *        :new_pgroup => true  : the new process is the root process of a new process group
3166
 *        :new_pgroup => false : don't create a new process group (default)
3144 3167
 *      resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
3145 3168
 *        :rlimit_resourcename => limit
3146 3169
 *        :rlimit_resourcename => [cur_limit, max_limit]
......
3179 3202
 *  If a hash is given as +options+,
3180 3203
 *  it specifies
3181 3204
 *  process group,
3205
 *  create new process group,
3182 3206
 *  resource limit,
3183 3207
 *  current directory,
3184 3208
 *  umask and
......
3200 3224
 *    pid = spawn(command, :pgroup=>true) # process leader
3201 3225
 *    pid = spawn(command, :pgroup=>10) # belongs to the process group 10
3202 3226
 *
3227
 *  The <code>:new_pgroup</code> key in +options+ specifies to pass
3228
 *  +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
3229
 *  Windows API. This option is only for Windows.
3230
 *  true means the new process is the root process of the new process group.
3231
 *  The new process has CTRL+C disabled. This flag is necessary for
3232
 *  <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
3233
 *  :new_pgroup is false by default.
3234
 *
3235
 *    pid = spawn(command, :new_pgroup=>true)  # new process group
3236
 *    pid = spawn(command, :new_pgroup=>false) # same process group
3237
 *
3203 3238
 *  The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
3204 3239
 *  <em>foo</em> should be one of resource types such as <code>core</code>.
3205 3240
 *  The corresponding value should be an integer or an array which have one or
test/ruby/test_process.rb
1360 1360
      assert(io.close_on_exec?)
1361 1361
    }
1362 1362
  end
1363

  
1364
  def test_execopts_new_pgroup
1365
    return unless windows?
1366

  
1367
    assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>true) }
1368
    assert_nothing_raised { system(*TRUECOMMAND, :new_pgroup=>false) }
1369
    assert_nothing_raised { spawn(*TRUECOMMAND, :new_pgroup=>true) }
1370
    assert_nothing_raised { IO.popen([*TRUECOMMAND, :new_pgroup=>true]) {} }
1371
  end
1363 1372
end
test/ruby/test_thread.rb
685 685
    t0 = Time.now.to_f
686 686
    pid = nil
687 687
    cmd = 'r,=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; r.read'
688
    s, err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true) do |in_p, out_p, err_p, cpid|
688
    opt = {}
689
    opt[:new_pgroup] = true if /mswin|mingw/ =~ RUBY_PLATFORM
690
    s, err = EnvUtil.invoke_ruby(['-e', cmd], "", true, true, opt) do |in_p, out_p, err_p, cpid|
689 691
      out_p.gets
690 692
      pid = cpid
691 693
      Process.kill(:SIGINT, pid)
win32/win32.c
72 72

  
73 73
#define TO_SOCKET(x)	_get_osfhandle(x)
74 74

  
75
static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
75
static struct ChildRecord *CreateChild(const WCHAR *, const WCHAR *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE, DWORD);
76 76
static int has_redirection(const char *);
77 77
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
78 78
static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
......
1087 1087
/* License: Ruby's */
1088 1088
static struct ChildRecord *
1089 1089
CreateChild(const WCHAR *cmd, const WCHAR *prog, SECURITY_ATTRIBUTES *psa,
1090
	    HANDLE hInput, HANDLE hOutput, HANDLE hError)
1090
	    HANDLE hInput, HANDLE hOutput, HANDLE hError, DWORD dwCreationFlags)
1091 1091
{
1092 1092
    BOOL fRet;
1093
    DWORD  dwCreationFlags;
1094 1093
    STARTUPINFOW aStartupInfo;
1095 1094
    PROCESS_INFORMATION aProcessInformation;
1096 1095
    SECURITY_ATTRIBUTES sa;
......
1137 1136
	aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1138 1137
    }
1139 1138

  
1140
    dwCreationFlags = (CREATE_NEW_PROCESS_GROUP | NORMAL_PRIORITY_CLASS);
1139
    dwCreationFlags |= NORMAL_PRIORITY_CLASS;
1141 1140

  
1142 1141
    if (lstrlenW(cmd) > 32767) {
1143 1142
	child->pid = 0;		/* release the slot */
......
1290 1289
    wshell = shell ? acp_to_wstr(shell, NULL) : NULL;
1291 1290
    if (v2) ALLOCV_END(v2);
1292 1291

  
1293
    ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL), mode);
1292
    ret = child_result(CreateChild(wcmd, wshell, NULL, NULL, NULL, NULL, 0), mode);
1294 1293
    free(wshell);
1295 1294
    free(wcmd);
1296 1295
    return ret;
......
1298 1297

  
1299 1298
/* License: Artistic or GPL */
1300 1299
rb_pid_t
1301
rb_w32_aspawn(int mode, const char *prog, char *const *argv)
1300
rb_w32_aspawn_flags(int mode, const char *prog, char *const *argv, DWORD flags)
1302 1301
{
1303 1302
    int c_switch = 0;
1304 1303
    size_t len;
......
1357 1356
    if (v) ALLOCV_END(v);
1358 1357
    wprog = prog ? acp_to_wstr(prog, NULL) : NULL;
1359 1358

  
1360
    ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL), mode);
1359
    ret = child_result(CreateChild(wcmd, wprog, NULL, NULL, NULL, NULL, flags), mode);
1361 1360
    free(wprog);
1362 1361
    free(wcmd);
1363 1362
    return ret;
1364 1363
}
1365 1364

  
1365
rb_pid_t
1366
rb_w32_aspawn(int mode, const char *prog, char *const *argv)
1367
{
1368
    return rb_w32_aspawn_flags(mode, prog, argv, 0);
1369
}
1370

  
1366 1371
/* License: Artistic or GPL */
1367 1372
typedef struct _NtCmdLineElement {
1368 1373
    struct _NtCmdLineElement *next;