Permalink
Browse files

* include/ruby/intern.h (rb_env_clear): declared.

  (rb_io_mode_modenum): declared.
  (rb_close_before_exec): declared.
  (struct rb_exec_arg): add options and redirect_fds field.
  (rb_check_argv): removed.
  (rb_exec_initarg): declared.
  (rb_exec_getargs): declared.
  (rb_exec_initarg2): declared.
  (rb_fork): add third argument: fds.

* io.c (max_file_descriptor): new static variable to record maximum
  file descriptor ruby used.
  (UPDATE_MAXFD): new macro.
  (UPDATE_MAXFD_PIPE): new macro.
  (rb_io_mode_modenum): externed.
  (rb_sysopen): update max_file_descriptor.
  (rb_close_before_exec): new function.
  (popen_exec): redirection removed because it is done by extended
  spawn mechanism.
  (pipe_open): generate a hash for spawn options to specify
  redirections.
  (pipe_open_v): use rb_exec_getargs.
  (pipe_open_s): use rb_exec_getargs.
  (rb_io_initialize): update max_file_descriptor..

* process.c (hide_obj): new function.
  (check_exec_redirect_fd): new function.
  (check_exec_redirect): new function.
  (check_exec_options_i): new function.
  (check_exec_fds): new function.
  (rb_check_exec_options): new function.
  (check_exec_env_i): new function.
  (rb_check_exec_env): new function.
  (rb_exec_getargs): new function.
  (rb_exec_initarg2): new function.
  (rb_exec_initarg): new function.
  (rb_f_exec): use rb_exec_initarg.
  (intcmp): new function.
  (run_exec_dup2): new function.
  (run_exec_close): new function.
  (run_exec_open): new function.
  (run_exec_pgroup): new function.
  (run_exec_rlimit): new function.
  (run_exec_options): new function.
  (rb_exec): call run_exec_options.
  (move_fds_to_avoid_crash): new function.
  (pipe_nocrash): new function.
  (rb_fork): use pipe_nocrash to avoid file descriptor conflicts.
  (rb_spawn): use rb_exec_initarg.
  (rlimit_resource_name2int): extracted from rlimit_resource_type.
  (rlimit_type_by_hname): new function.
  (rlimit_type_by_lname): new function.
  (rlimit_resource_type): use rlimit_type_by_hname.
  (proc_daemon): add fds argument for rb_fork.

* hash.c (rb_env_clear): renamed from env_clear and externed.

[ruby-dev:34086]



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16183 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
1 parent 9b694aa commit 278b63a3e459993c44aa0515239970fde517642a @akr akr committed Apr 24, 2008
Showing with 1,629 additions and 101 deletions.
  1. +61 −0 ChangeLog
  2. +3 −3 hash.c
  3. +9 −2 include/ruby/intern.h
  4. +89 −27 io.c
  5. +1,037 −69 process.c
  6. +430 −0 test/ruby/test_process.rb
View
@@ -1,3 +1,64 @@
+Thu Apr 24 23:25:17 2008 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/intern.h (rb_env_clear): declared.
+ (rb_io_mode_modenum): declared.
+ (rb_close_before_exec): declared.
+ (struct rb_exec_arg): add options and redirect_fds field.
+ (rb_check_argv): removed.
+ (rb_exec_initarg): declared.
+ (rb_exec_getargs): declared.
+ (rb_exec_initarg2): declared.
+ (rb_fork): add third argument: fds.
+
+ * io.c (max_file_descriptor): new static variable to record maximum
+ file descriptor ruby used.
+ (UPDATE_MAXFD): new macro.
+ (UPDATE_MAXFD_PIPE): new macro.
+ (rb_io_mode_modenum): externed.
+ (rb_sysopen): update max_file_descriptor.
+ (rb_close_before_exec): new function.
+ (popen_exec): redirection removed because it is done by extended
+ spawn mechanism.
+ (pipe_open): generate a hash for spawn options to specify
+ redirections.
+ (pipe_open_v): use rb_exec_getargs.
+ (pipe_open_s): use rb_exec_getargs.
+ (rb_io_initialize): update max_file_descriptor..
+
+ * process.c (hide_obj): new function.
+ (check_exec_redirect_fd): new function.
+ (check_exec_redirect): new function.
+ (check_exec_options_i): new function.
+ (check_exec_fds): new function.
+ (rb_check_exec_options): new function.
+ (check_exec_env_i): new function.
+ (rb_check_exec_env): new function.
+ (rb_exec_getargs): new function.
+ (rb_exec_initarg2): new function.
+ (rb_exec_initarg): new function.
+ (rb_f_exec): use rb_exec_initarg.
+ (intcmp): new function.
+ (run_exec_dup2): new function.
+ (run_exec_close): new function.
+ (run_exec_open): new function.
+ (run_exec_pgroup): new function.
+ (run_exec_rlimit): new function.
+ (run_exec_options): new function.
+ (rb_exec): call run_exec_options.
+ (move_fds_to_avoid_crash): new function.
+ (pipe_nocrash): new function.
+ (rb_fork): use pipe_nocrash to avoid file descriptor conflicts.
+ (rb_spawn): use rb_exec_initarg.
+ (rlimit_resource_name2int): extracted from rlimit_resource_type.
+ (rlimit_type_by_hname): new function.
+ (rlimit_type_by_lname): new function.
+ (rlimit_resource_type): use rlimit_type_by_hname.
+ (proc_daemon): add fds argument for rb_fork.
+
+ * hash.c (rb_env_clear): renamed from env_clear and externed.
+
+ [ruby-dev:34086]
+
Thu Apr 24 23:00:58 2008 Yusuke Endoh <mame@tsg.ne.jp>
* test/ruby/test_thread.rb: fix typos.
View
6 hash.c
@@ -2215,8 +2215,8 @@ env_select(VALUE ehash)
return result;
}
-static VALUE
-env_clear(void)
+VALUE
+rb_env_clear(void)
{
volatile VALUE keys;
long i;
@@ -2640,7 +2640,7 @@ Init_Hash(void)
rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
rb_define_singleton_method(envtbl,"delete", env_delete_m, 1);
rb_define_singleton_method(envtbl,"delete_if", env_delete_if, 0);
- rb_define_singleton_method(envtbl,"clear", env_clear, 0);
+ rb_define_singleton_method(envtbl,"clear", rb_env_clear, 0);
rb_define_singleton_method(envtbl,"reject", env_reject, 0);
rb_define_singleton_method(envtbl,"reject!", env_reject_bang, 0);
rb_define_singleton_method(envtbl,"select", env_select, 0);
View
@@ -353,6 +353,7 @@ VALUE rb_hash_delete(VALUE,VALUE);
struct st_table *rb_hash_tbl(VALUE);
int rb_path_check(const char*);
int rb_env_path_tainted(void);
+VALUE rb_env_clear(void);
/* io.c */
#define rb_defout rb_stdout
RUBY_EXTERN VALUE rb_fs;
@@ -377,6 +378,8 @@ VALUE rb_file_open(const char*, const char*);
VALUE rb_gets(void);
void rb_write_error(const char*);
void rb_write_error2(const char*, long);
+int rb_io_mode_modenum(const char *mode);
+void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds);
/* marshal.c */
VALUE rb_marshal_dump(VALUE, VALUE);
VALUE rb_marshal_load(VALUE);
@@ -444,12 +447,16 @@ struct rb_exec_arg {
int argc;
VALUE *argv;
const char *prog;
+ VALUE options;
+ VALUE redirect_fds;
};
int rb_proc_exec_n(int, VALUE*, const char*);
int rb_proc_exec(const char*);
-VALUE rb_check_argv(int, VALUE*);
+VALUE rb_exec_initarg(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e);
+VALUE rb_exec_getargs(int *argc_p, VALUE **argv_p, int accept_shell, VALUE *env_ret, VALUE *opthash_ret);
+void rb_exec_initarg2(VALUE prog, int argc, VALUE *argv, VALUE env, VALUE opthash, struct rb_exec_arg *e);
int rb_exec(const struct rb_exec_arg*);
-rb_pid_t rb_fork(int*, int (*)(void*), void*);
+rb_pid_t rb_fork(int*, int (*)(void*), void*, VALUE);
VALUE rb_f_exec(int,VALUE*);
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags);
void rb_syswait(rb_pid_t pid);
View
116 io.c
@@ -139,6 +139,18 @@ struct argf {
rb_encoding *enc, *enc2;
};
+static int max_file_descriptor = NOFILE;
+#define UPDATE_MAXFD(fd) \
+ do { \
+ if (max_file_descriptor < (fd)) max_file_descriptor = (fd); \
+ } while (0)
+#define UPDATE_MAXFD_PIPE(filedes) \
+ do { \
+ UPDATE_MAXFD((filedes)[0]); \
+ UPDATE_MAXFD((filedes)[1]); \
+ } while (0)
+
+
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
#define ARGF argf_of(argf)
@@ -3228,7 +3240,7 @@ rb_io_modenum_flags(int mode)
return flags;
}
-static int
+int
rb_io_mode_modenum(const char *mode)
{
int flags = 0;
@@ -3387,6 +3399,7 @@ rb_sysopen(char *fname, int flags, unsigned int mode)
rb_sys_fail(fname);
}
}
+ UPDATE_MAXFD(fd);
return fd;
}
@@ -3629,26 +3642,41 @@ popen_redirect(struct popen_arg *p)
}
}
+void
+rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
+{
+ int fd, ret;
+ int max = max_file_descriptor;
+ if (max < maxhint)
+ max = maxhint;
+ for (fd = lowfd; fd <= max; fd++) {
+ if (!NIL_P(noclose_fds) &&
+ RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd))))
+ continue;
+#ifdef FD_CLOEXEC
+ ret = fcntl(fd, F_GETFD);
+ if (ret != -1 && !(ret & FD_CLOEXEC)) {
+ fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
+ }
+#else
+ close(fd);
+#endif
+ }
+}
+
static int
popen_exec(void *pp)
{
struct popen_arg *p = (struct popen_arg*)pp;
- int fd;
rb_thread_atfork();
- popen_redirect(p);
- for (fd = 3; fd < NOFILE; fd++) {
-#ifdef FD_CLOEXEC
- if (fcntl(fd, F_GETFD) & FD_CLOEXEC) continue;
-#endif
- close(fd);
- }
return rb_exec(&p->exec);
}
#endif
static VALUE
-pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
+pipe_open(VALUE prog, int argc, VALUE *argv,
+ VALUE env, VALUE opthash, const char *mode)
{
int modef = rb_io_mode_flags(mode);
int pid = 0;
@@ -3659,6 +3687,7 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
#if defined(HAVE_FORK)
int status;
struct popen_arg arg;
+ VALUE env2 = 0;
#elif defined(_WIN32)
int openmode = rb_io_mode_modenum(mode);
const char *exename = NULL;
@@ -3667,45 +3696,72 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
FILE *fp = 0;
int fd = -1;
int write_fd = -1;
+ const char *cmd = 0;
+
+ if (prog)
+ cmd = StringValueCStr(prog);
#if defined(HAVE_FORK)
+ if (prog) {
+ env2 = rb_hash_new();
+ RBASIC(env2)->klass = 0;
+ }
arg.modef = modef;
arg.pair[0] = arg.pair[1] = -1;
arg.write_pair[0] = arg.write_pair[1] = -1;
switch (modef & (FMODE_READABLE|FMODE_WRITABLE)) {
case FMODE_READABLE|FMODE_WRITABLE:
if (pipe(arg.write_pair) < 0)
rb_sys_fail(cmd);
+ UPDATE_MAXFD_PIPE(arg.write_pair);
if (pipe(arg.pair) < 0) {
int e = errno;
close(arg.write_pair[0]);
close(arg.write_pair[1]);
errno = e;
rb_sys_fail(cmd);
}
+ UPDATE_MAXFD_PIPE(arg.pair);
+ if (env2) {
+ rb_hash_aset(env2, INT2FIX(0), INT2FIX(arg.write_pair[0]));
+ rb_hash_aset(env2, INT2FIX(1), INT2FIX(arg.pair[1]));
+ }
break;
case FMODE_READABLE:
if (pipe(arg.pair) < 0)
rb_sys_fail(cmd);
+ UPDATE_MAXFD_PIPE(arg.pair);
+ if (env2)
+ rb_hash_aset(env2, INT2FIX(1), INT2FIX(arg.pair[1]));
break;
case FMODE_WRITABLE:
if (pipe(arg.pair) < 0)
rb_sys_fail(cmd);
+ UPDATE_MAXFD_PIPE(arg.pair);
+ if (env2)
+ rb_hash_aset(env2, INT2FIX(0), INT2FIX(arg.pair[0]));
break;
default:
rb_sys_fail(cmd);
}
- if (cmd) {
- arg.exec.argc = argc;
- arg.exec.argv = argv;
- arg.exec.prog = cmd;
- pid = rb_fork(&status, popen_exec, &arg);
+ if (prog) {
+ VALUE close_others = ID2SYM(rb_intern("close_others"));
+ if (NIL_P(opthash) || !st_lookup(RHASH_TBL(opthash), close_others, 0))
+ rb_hash_aset(env2, close_others, Qtrue);
+ if (NIL_P(opthash))
+ opthash = env2;
+ else {
+ opthash = rb_assoc_new(env2, opthash);
+ RBASIC(opthash)->klass = 0;
+ }
+ rb_exec_initarg2(prog, argc, argv, env, opthash, &arg.exec);
+ pid = rb_fork(&status, popen_exec, &arg, arg.exec.redirect_fds);
}
else {
fflush(stdin); /* is it really needed? */
rb_io_flush(rb_stdout);
rb_io_flush(rb_stderr);
- pid = rb_fork(&status, 0, 0);
+ pid = rb_fork(&status, 0, 0, Qnil);
if (pid == 0) { /* child */
popen_redirect(&arg);
rb_io_synchronized(RFILE(orig_stdout)->fptr);
@@ -3812,27 +3868,29 @@ pipe_open(const char *cmd, int argc, VALUE *argv, const char *mode)
static VALUE
pipe_open_v(int argc, VALUE *argv, const char *mode)
{
- VALUE prog = rb_check_argv(argc, argv);
- const char *cmd;
-
- if (!RB_GC_GUARD(prog)) prog = argv[0];
- cmd = StringValueCStr(prog);
- return pipe_open(cmd, argc, argv, mode);
+ VALUE prog, env=Qnil, opthash=Qnil;
+ prog = rb_exec_getargs(&argc, &argv, Qfalse, &env, &opthash);
+ return pipe_open(prog, argc, argv, env, opthash, mode);
}
static VALUE
pipe_open_s(VALUE prog, const char *mode)
{
- const char *cmd = (rb_check_argv(1, &prog), RSTRING_PTR(prog));
+ const char *cmd = RSTRING_PTR(prog);
+ int argc = 1;
+ VALUE *argv = &prog;
+ VALUE env=Qnil, opthash=Qnil;
- if (strcmp("-", cmd) == 0) {
+ if (RSTRING_LEN(prog) == 1 && cmd[0] == '-') {
#if !defined(HAVE_FORK)
rb_raise(rb_eNotImpError,
"fork() function is unimplemented on this machine");
#endif
- cmd = 0;
+ return pipe_open(0, 0, 0, Qnil, Qnil, mode);
}
- return pipe_open(cmd, 0, &prog, mode);
+
+ rb_exec_getargs(&argc, &argv, Qtrue, &env, &opthash);
+ return pipe_open(prog, 0, 0, Qnil, Qnil, mode);
}
/*
@@ -3845,7 +3903,9 @@ pipe_open_s(VALUE prog, const char *mode)
* <code>IO</code> object. If _cmd_ is a +String+
* ``<code>-</code>'', then a new instance of Ruby is started as the
* subprocess. If <i>cmd</i> is an +Array+ of +String+, then it will
- * be used as the subprocess's +argv+ bypassing a shell. The default
+ * be used as the subprocess's +argv+ bypassing a shell.
+ * The array can contains a hash at first for environments and
+ * a hash at last for options similar to <code>spawn</code>. The default
* mode for the new file object is ``r'', but <i>mode</i> may be set
* to any of the modes listed in the description for class IO.
*
@@ -4873,6 +4933,7 @@ rb_io_initialize(int argc, VALUE *argv, VALUE io)
orig = rb_io_check_io(fnum);
if (NIL_P(orig)) {
fd = NUM2INT(fnum);
+ UPDATE_MAXFD(fd);
if (argc != 2) {
#if defined(HAVE_FCNTL) && defined(F_GETFL)
flags = fcntl(fd, F_GETFL);
@@ -6021,6 +6082,7 @@ rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
rb_scan_args(argc, argv, "02", &v1, &v2);
if (pipe(pipes) == -1)
rb_sys_fail(0);
+ UPDATE_MAXFD_PIPE(pipes);
args[0] = klass;
args[1] = INT2NUM(pipes[0]);
Oops, something went wrong.

0 comments on commit 278b63a

Please sign in to comment.