зеркало из https://github.com/github/ruby.git
process.c: removed preserving_errno
* process.c (try_with_sh, handle_fork_error): added argument for errno. * process.c (proc_exec_cmd, proc_exec_sh, exec_async_signal_safe): now return errno instead of -1. * process.c (rb_fork_ruby): merged retry_fork_ruby() and unified clean-up after fork regardless failure. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60762 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
73e41247b9
Коммит
fe3decb201
112
process.c
112
process.c
|
@ -143,11 +143,9 @@ int setregid(rb_gid_t rgid, rb_gid_t egid);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#define preserving_errno(stmts) \
|
||||
do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
|
||||
|
||||
static void check_uid_switch(void);
|
||||
static void check_gid_switch(void);
|
||||
static int exec_async_signal_safe(const struct rb_execarg *, char *, size_t);
|
||||
|
||||
#if 1
|
||||
#define p_uid_from_name p_uid_from_name
|
||||
|
@ -1214,7 +1212,7 @@ security(const char *str)
|
|||
#if defined(HAVE_WORKING_FORK)
|
||||
|
||||
/* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
|
||||
#define try_with_sh(prog, argv, envp) ((saved_errno == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
|
||||
#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
|
||||
static void
|
||||
exec_with_sh(const char *prog, char **argv, char **envp)
|
||||
{
|
||||
|
@ -1237,26 +1235,28 @@ proc_exec_cmd(const char *prog, VALUE argv_str, VALUE envp_str)
|
|||
char **argv;
|
||||
#ifndef _WIN32
|
||||
char **envp;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
argv = ARGVSTR2ARGV(argv_str);
|
||||
|
||||
if (!prog) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
rb_w32_uaspawn(P_OVERLAY, prog, argv);
|
||||
return errno;
|
||||
#else
|
||||
envp = envp_str ? (char **)RSTRING_PTR(envp_str) : NULL;
|
||||
if (envp_str)
|
||||
execve(prog, argv, envp); /* async-signal-safe */
|
||||
else
|
||||
execv(prog, argv); /* async-signal-safe (since SUSv4) */
|
||||
preserving_errno(try_with_sh(prog, argv, envp)); /* try_with_sh() is async-signal-safe. */
|
||||
err = errno;
|
||||
try_with_sh(err, prog, argv, envp); /* try_with_sh() is async-signal-safe. */
|
||||
return err;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This function should be async-signal-safe. Actually it is. */
|
||||
|
@ -1270,15 +1270,12 @@ proc_exec_sh(const char *str, VALUE envp_str)
|
|||
s++;
|
||||
|
||||
if (!*s) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
rb_w32_uspawn(P_OVERLAY, (char *)str, 0);
|
||||
return -1;
|
||||
#else
|
||||
#if defined(__CYGWIN32__)
|
||||
#elif defined(__CYGWIN32__)
|
||||
{
|
||||
char fbuf[MAXPATHLEN];
|
||||
char *shell = dln_find_exe_r("sh", 0, fbuf, sizeof(fbuf));
|
||||
|
@ -1295,9 +1292,8 @@ proc_exec_sh(const char *str, VALUE envp_str)
|
|||
execle("/bin/sh", "sh", "-c", str, (char *)NULL, (char **)RSTRING_PTR(envp_str)); /* async-signal-safe */
|
||||
else
|
||||
execl("/bin/sh", "sh", "-c", str, (char *)NULL); /* async-signal-safe (since SUSv4) */
|
||||
#endif
|
||||
return -1;
|
||||
#endif /* _WIN32 */
|
||||
return errno;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1306,8 +1302,9 @@ rb_proc_exec(const char *str)
|
|||
int ret;
|
||||
before_exec();
|
||||
ret = proc_exec_sh(str, Qfalse);
|
||||
preserving_errno(after_exec());
|
||||
return ret;
|
||||
after_exec();
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2589,9 +2586,7 @@ rb_f_exec(int argc, const VALUE *argv)
|
|||
rb_execarg_parent_start(execarg_obj);
|
||||
fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
|
||||
|
||||
rb_exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
|
||||
|
||||
err = errno;
|
||||
err = exec_async_signal_safe(eargp, errmsg, sizeof(errmsg));
|
||||
after_exec(); /* restart timer thread */
|
||||
|
||||
rb_exec_fail(eargp, err, errmsg);
|
||||
|
@ -3130,32 +3125,39 @@ rb_execarg_run_options(const struct rb_execarg *eargp, struct rb_execarg *sargp,
|
|||
/* This function should be async-signal-safe. Hopefully it is. */
|
||||
int
|
||||
rb_exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
|
||||
{
|
||||
errno = exec_async_signal_safe(eargp, errmsg, errmsg_buflen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
exec_async_signal_safe(const struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
|
||||
{
|
||||
#if !defined(HAVE_WORKING_FORK)
|
||||
struct rb_execarg sarg, *const sargp = &sarg;
|
||||
#else
|
||||
struct rb_execarg *const sargp = NULL;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
if (rb_execarg_run_options(eargp, sargp, errmsg, errmsg_buflen) < 0) { /* hopefully async-signal-safe */
|
||||
goto failure;
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (eargp->use_shell) {
|
||||
proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
|
||||
err = proc_exec_sh(RSTRING_PTR(eargp->invoke.sh.shell_script), eargp->envp_str); /* async-signal-safe */
|
||||
}
|
||||
else {
|
||||
char *abspath = NULL;
|
||||
if (!NIL_P(eargp->invoke.cmd.command_abspath))
|
||||
abspath = RSTRING_PTR(eargp->invoke.cmd.command_abspath);
|
||||
proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str); /* async-signal-safe */
|
||||
err = proc_exec_cmd(abspath, eargp->invoke.cmd.argv_str, eargp->envp_str); /* async-signal-safe */
|
||||
}
|
||||
#if !defined(HAVE_WORKING_FORK)
|
||||
preserving_errno(rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen));
|
||||
rb_execarg_run_options(sargp, NULL, errmsg, errmsg_buflen);
|
||||
#endif
|
||||
|
||||
failure:
|
||||
return -1;
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_WORKING_FORK
|
||||
|
@ -3226,11 +3228,11 @@ pipe_nocrash(int filedes[2], VALUE fds)
|
|||
#endif
|
||||
|
||||
static int
|
||||
handle_fork_error(int *status, int *ep, volatile int *try_gc_p)
|
||||
handle_fork_error(int err, int *status, int *ep, volatile int *try_gc_p)
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
switch (errno) {
|
||||
switch (err) {
|
||||
case ENOMEM:
|
||||
if ((*try_gc_p)-- > 0 && !rb_during_gc()) {
|
||||
rb_gc();
|
||||
|
@ -3253,7 +3255,9 @@ handle_fork_error(int *status, int *ep, volatile int *try_gc_p)
|
|||
break;
|
||||
}
|
||||
if (ep) {
|
||||
preserving_errno((close(ep[0]), close(ep[1])));
|
||||
close(ep[0]);
|
||||
close(ep[1]);
|
||||
errno = err;
|
||||
}
|
||||
if (state && !status) rb_jump_tag(state);
|
||||
return -1;
|
||||
|
@ -3548,6 +3552,7 @@ retry_fork_async_signal_safe(int *status, int *ep,
|
|||
rb_pid_t pid;
|
||||
volatile int try_gc = 1;
|
||||
struct child_handler_disabler_state old;
|
||||
int err;
|
||||
|
||||
while (1) {
|
||||
prefork();
|
||||
|
@ -3575,11 +3580,12 @@ retry_fork_async_signal_safe(int *status, int *ep,
|
|||
_exit(127);
|
||||
#endif
|
||||
}
|
||||
preserving_errno(disable_child_handler_fork_parent(&old));
|
||||
err = errno;
|
||||
disable_child_handler_fork_parent(&old);
|
||||
if (0 < pid) /* fork succeed, parent process */
|
||||
return pid;
|
||||
/* fork failed */
|
||||
if (handle_fork_error(status, ep, &try_gc))
|
||||
if (handle_fork_error(err, status, ep, &try_gc))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -3614,45 +3620,29 @@ rb_fork_async_signal_safe(int *status, int (*chfunc)(void*, char *, size_t), voi
|
|||
return pid;
|
||||
}
|
||||
|
||||
static rb_pid_t
|
||||
retry_fork_ruby(int *status, struct child_handler_disabler_state *old)
|
||||
{
|
||||
rb_pid_t pid;
|
||||
int try_gc = 1;
|
||||
|
||||
while (1) {
|
||||
prefork();
|
||||
before_fork_ruby();
|
||||
disable_child_handler_before_fork(old);
|
||||
pid = fork();
|
||||
if (pid == 0) /* fork succeed, child process */
|
||||
return pid;
|
||||
preserving_errno(after_fork_ruby());
|
||||
preserving_errno(disable_child_handler_fork_parent(old));
|
||||
if (0 < pid) /* fork succeed, parent process */
|
||||
return pid;
|
||||
/* fork failed */
|
||||
if (handle_fork_error(status, NULL, &try_gc))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rb_pid_t
|
||||
rb_fork_ruby(int *status)
|
||||
{
|
||||
rb_pid_t pid;
|
||||
int try_gc = 1, err;
|
||||
struct child_handler_disabler_state old;
|
||||
|
||||
if (status) *status = 0;
|
||||
|
||||
pid = retry_fork_ruby(status, &old);
|
||||
if (pid < 0)
|
||||
return pid;
|
||||
if (!pid) {
|
||||
after_fork_ruby();
|
||||
disable_child_handler_fork_parent(&old); /* yes, bad name */
|
||||
while (1) {
|
||||
prefork();
|
||||
before_fork_ruby();
|
||||
disable_child_handler_before_fork(&old);
|
||||
pid = fork();
|
||||
err = errno;
|
||||
after_fork_ruby();
|
||||
disable_child_handler_fork_parent(&old); /* yes, bad name */
|
||||
if (pid >= 0) /* fork succeed */
|
||||
return pid;
|
||||
/* fork failed */
|
||||
if (handle_fork_error(err, status, NULL, &try_gc))
|
||||
return -1;
|
||||
}
|
||||
return pid;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче