* process.c (retry_fork): extracted from rb_fork_err.
(send_child_error): ditto. (recv_child_error): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35985 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
588d10180f
commit
1ad3f4b05d
@ -1,3 +1,9 @@
|
|||||||
|
Sat Jun 9 21:50:04 2012 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* process.c (retry_fork): extracted from rb_fork_err.
|
||||||
|
(send_child_error): ditto.
|
||||||
|
(recv_child_error): ditto.
|
||||||
|
|
||||||
Sat Jun 9 17:21:48 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Sat Jun 9 17:21:48 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* iseq.c (iseq_load): type is a symbol, and invalid as ID in common.
|
* iseq.c (iseq_load): type is a symbol, and invalid as ID in common.
|
||||||
|
212
process.c
212
process.c
@ -2754,29 +2754,19 @@ chfunc_protect(VALUE arg)
|
|||||||
*
|
*
|
||||||
* +chfunc+ must not raise any exceptions.
|
* +chfunc+ must not raise any exceptions.
|
||||||
*/
|
*/
|
||||||
rb_pid_t
|
|
||||||
rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
|
static rb_pid_t
|
||||||
char *errmsg, size_t errmsg_buflen)
|
retry_fork(int *status, int *ep)
|
||||||
{
|
{
|
||||||
rb_pid_t pid;
|
rb_pid_t pid;
|
||||||
int err, state = 0;
|
int state = 0;
|
||||||
int ep[2];
|
|
||||||
VALUE io = Qnil;
|
|
||||||
|
|
||||||
#define prefork() ( \
|
#define prefork() ( \
|
||||||
rb_io_flush(rb_stdout), \
|
rb_io_flush(rb_stdout), \
|
||||||
rb_io_flush(rb_stderr) \
|
rb_io_flush(rb_stderr) \
|
||||||
)
|
)
|
||||||
prefork();
|
|
||||||
|
|
||||||
if (chfunc) {
|
prefork();
|
||||||
if (status) *status = 0;
|
|
||||||
if (pipe_nocrash(ep, fds)) return -1;
|
|
||||||
if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
|
|
||||||
preserving_errno((close(ep[0]), close(ep[1])));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (; before_fork(), (pid = fork()) < 0; prefork()) {
|
for (; before_fork(), (pid = fork()) < 0; prefork()) {
|
||||||
after_fork();
|
after_fork();
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
@ -2784,101 +2774,147 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU
|
|||||||
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||||
case EWOULDBLOCK:
|
case EWOULDBLOCK:
|
||||||
#endif
|
#endif
|
||||||
if (!status && !chfunc) {
|
if (!status && !ep) {
|
||||||
rb_thread_sleep(1);
|
rb_thread_sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* rb_protect() is required not only for non-NULL status
|
|
||||||
* but also for non-NULL chfunc because
|
|
||||||
* ep[0] and ep[1] should be closed on exceptions.
|
|
||||||
* If status is NULL, the catched exception is re-raised
|
|
||||||
* by rb_jump_tag() below, after closing them. */
|
|
||||||
rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
|
rb_protect((VALUE (*)())rb_thread_sleep, 1, &state);
|
||||||
if (status) *status = state;
|
if (status) *status = state;
|
||||||
if (!state) continue;
|
if (!state) continue;
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
default:
|
default:
|
||||||
if (chfunc) {
|
if (ep) {
|
||||||
preserving_errno((close(ep[0]), close(ep[1])));
|
preserving_errno((close(ep[0]), close(ep[1])));
|
||||||
}
|
}
|
||||||
if (state && !status) rb_jump_tag(state);
|
if (state && !status) rb_jump_tag(state);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pid) {
|
return pid;
|
||||||
forked_child = 1;
|
}
|
||||||
if (chfunc) {
|
|
||||||
struct chfunc_protect_t arg;
|
static void
|
||||||
arg.chfunc = chfunc;
|
send_child_error(int fd, int state, char *errmsg, size_t errmsg_buflen)
|
||||||
arg.arg = charg;
|
{
|
||||||
arg.errmsg = errmsg;
|
VALUE io = Qnil;
|
||||||
arg.buflen = errmsg_buflen;
|
int err;
|
||||||
close(ep[0]);
|
|
||||||
if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS);
|
if (write(fd, &state, sizeof(state)) == sizeof(state) && state) {
|
||||||
if (write(ep[1], &state, sizeof(state)) == sizeof(state) && state) {
|
VALUE errinfo = rb_errinfo();
|
||||||
VALUE errinfo = rb_errinfo();
|
io = rb_io_fdopen(fd, O_WRONLY|O_BINARY, NULL);
|
||||||
io = rb_io_fdopen(ep[1], O_WRONLY|O_BINARY, NULL);
|
rb_marshal_dump(errinfo, io);
|
||||||
rb_marshal_dump(errinfo, io);
|
rb_io_flush(io);
|
||||||
rb_io_flush(io);
|
|
||||||
}
|
|
||||||
err = errno;
|
|
||||||
if (write(ep[1], &err, sizeof(err)) < 0) err = errno;
|
|
||||||
if (errmsg && 0 < errmsg_buflen) {
|
|
||||||
errmsg[errmsg_buflen-1] = '\0';
|
|
||||||
errmsg_buflen = strlen(errmsg);
|
|
||||||
if (errmsg_buflen > 0 &&write(ep[1], errmsg, errmsg_buflen) < 0)
|
|
||||||
err = errno;
|
|
||||||
}
|
|
||||||
if (!NIL_P(io)) rb_io_close(io);
|
|
||||||
#if EXIT_SUCCESS == 127
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
#else
|
|
||||||
_exit(127);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
after_fork();
|
err = errno;
|
||||||
if (pid && chfunc) {
|
if (write(fd, &err, sizeof(err)) < 0) err = errno;
|
||||||
ssize_t size;
|
if (errmsg && 0 < errmsg_buflen) {
|
||||||
VALUE exc = Qnil;
|
errmsg[errmsg_buflen-1] = '\0';
|
||||||
close(ep[1]);
|
errmsg_buflen = strlen(errmsg);
|
||||||
if ((read(ep[0], &state, sizeof(state))) == sizeof(state) && state) {
|
if (errmsg_buflen > 0 && write(fd, errmsg, errmsg_buflen) < 0)
|
||||||
io = rb_io_fdopen(ep[0], O_RDONLY|O_BINARY, NULL);
|
err = errno;
|
||||||
exc = rb_marshal_load(io);
|
}
|
||||||
rb_set_errinfo(exc);
|
if (!NIL_P(io)) rb_io_close(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
recv_child_error(int fd, int *statep, VALUE *excp, int *errp, char *errmsg, size_t errmsg_buflen)
|
||||||
|
{
|
||||||
|
int err, state = 0;
|
||||||
|
VALUE io = Qnil;
|
||||||
|
ssize_t size;
|
||||||
|
VALUE exc = Qnil;
|
||||||
|
if ((read(fd, &state, sizeof(state))) == sizeof(state) && state) {
|
||||||
|
io = rb_io_fdopen(fd, O_RDONLY|O_BINARY, NULL);
|
||||||
|
exc = rb_marshal_load(io);
|
||||||
|
rb_set_errinfo(exc);
|
||||||
|
}
|
||||||
|
if (!*statep && state) *statep = state;
|
||||||
|
*excp = exc;
|
||||||
#define READ_FROM_CHILD(ptr, len) \
|
#define READ_FROM_CHILD(ptr, len) \
|
||||||
(NIL_P(io) ? read(ep[0], (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
|
(NIL_P(io) ? read(fd, (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
|
||||||
if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
|
if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
|
||||||
err = errno;
|
err = errno;
|
||||||
}
|
}
|
||||||
if (size == sizeof(err) &&
|
*errp = err;
|
||||||
errmsg && 0 < errmsg_buflen) {
|
if (size == sizeof(err) &&
|
||||||
ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
|
errmsg && 0 < errmsg_buflen) {
|
||||||
if (0 <= ret) {
|
ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
|
||||||
errmsg[ret] = '\0';
|
if (0 <= ret) {
|
||||||
}
|
errmsg[ret] = '\0';
|
||||||
}
|
}
|
||||||
if (NIL_P(io))
|
}
|
||||||
close(ep[0]);
|
if (NIL_P(io))
|
||||||
else
|
close(fd);
|
||||||
rb_io_close(io);
|
else
|
||||||
if (state || size) {
|
rb_io_close(io);
|
||||||
if (status) {
|
return size != 0;
|
||||||
rb_protect(proc_syswait, (VALUE)pid, status);
|
}
|
||||||
if (state) *status = state;
|
|
||||||
}
|
rb_pid_t
|
||||||
else {
|
rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
|
||||||
rb_syswait(pid);
|
char *errmsg, size_t errmsg_buflen)
|
||||||
if (state) rb_exc_raise(exc);
|
{
|
||||||
}
|
rb_pid_t pid;
|
||||||
errno = err;
|
int err, state = 0;
|
||||||
|
int ep[2];
|
||||||
|
VALUE exc;
|
||||||
|
int error_occured;
|
||||||
|
|
||||||
|
if (status) *status = 0;
|
||||||
|
|
||||||
|
if (!chfunc) {
|
||||||
|
pid = retry_fork(status, NULL);
|
||||||
|
if (pid < 0)
|
||||||
|
return pid;
|
||||||
|
if (!pid)
|
||||||
|
forked_child = 1;
|
||||||
|
after_fork();
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (pipe_nocrash(ep, fds)) return -1;
|
||||||
|
if (fcntl(ep[1], F_SETFD, FD_CLOEXEC)) {
|
||||||
|
preserving_errno((close(ep[0]), close(ep[1])));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
pid = retry_fork(status, ep);
|
||||||
|
if (pid < 0)
|
||||||
|
return pid;
|
||||||
|
if (!pid) {
|
||||||
|
struct chfunc_protect_t arg;
|
||||||
|
forked_child = 1;
|
||||||
|
close(ep[0]);
|
||||||
|
arg.chfunc = chfunc;
|
||||||
|
arg.arg = charg;
|
||||||
|
arg.errmsg = errmsg;
|
||||||
|
arg.buflen = errmsg_buflen;
|
||||||
|
if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS);
|
||||||
|
send_child_error(ep[1], state, errmsg, errmsg_buflen);
|
||||||
|
#if EXIT_SUCCESS == 127
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
#else
|
||||||
|
_exit(127);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
after_fork();
|
||||||
|
close(ep[1]);
|
||||||
|
error_occured = recv_child_error(ep[0], &state, &exc, &err, errmsg, errmsg_buflen);
|
||||||
|
if (state || error_occured) {
|
||||||
|
if (status) {
|
||||||
|
rb_protect(proc_syswait, (VALUE)pid, status);
|
||||||
|
if (state) *status = state;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_syswait(pid);
|
||||||
|
if (state) rb_exc_raise(exc);
|
||||||
|
}
|
||||||
|
errno = err;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pid;
|
||||||
}
|
}
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct chfunc_wrapper_t {
|
struct chfunc_wrapper_t {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user