[前][次][番号順一覧][スレッド一覧]

ruby-changes:23934

From: akr <ko1@a...>
Date: Sat, 9 Jun 2012 21:51:12 +0900 (JST)
Subject: [ruby-changes:23934] akr:r35985 (trunk): * process.c (retry_fork): extracted from rb_fork_err.

akr	2012-06-09 21:51:01 +0900 (Sat, 09 Jun 2012)

  New Revision: 35985

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35985

  Log:
    * process.c (retry_fork): extracted from rb_fork_err.
      (send_child_error): ditto.
      (recv_child_error): ditto.

  Modified files:
    trunk/ChangeLog
    trunk/process.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35984)
+++ ChangeLog	(revision 35985)
@@ -1,3 +1,9 @@
+Sat Jun  9 21:50:04 2012  Tanaka Akira  <akr@f...>
+
+	* 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@r...>
 
 	* iseq.c (iseq_load): type is a symbol, and invalid as ID in common.
Index: process.c
===================================================================
--- process.c	(revision 35984)
+++ process.c	(revision 35985)
@@ -2754,29 +2754,19 @@
  *
  * +chfunc+ must not raise any exceptions.
  */
-rb_pid_t
-rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
-        char *errmsg, size_t errmsg_buflen)
+
+static rb_pid_t
+retry_fork(int *status, int *ep)
 {
     rb_pid_t pid;
-    int err, state = 0;
-    int ep[2];
-    VALUE io = Qnil;
+    int state = 0;
 
 #define prefork() (		\
 	rb_io_flush(rb_stdout), \
 	rb_io_flush(rb_stderr)	\
 	)
+
     prefork();
-
-    if (chfunc) {
-	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()) {
 	after_fork();
 	switch (errno) {
@@ -2784,101 +2774,147 @@
 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
 	  case EWOULDBLOCK:
 #endif
-	    if (!status && !chfunc) {
+	    if (!status && !ep) {
 		rb_thread_sleep(1);
 		continue;
 	    }
 	    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);
 		if (status) *status = state;
 		if (!state) continue;
 	    }
             /* fall through */
 	  default:
-	    if (chfunc) {
+	    if (ep) {
 		preserving_errno((close(ep[0]), close(ep[1])));
 	    }
 	    if (state && !status) rb_jump_tag(state);
 	    return -1;
 	}
     }
-    if (!pid) {
-        forked_child = 1;
-	if (chfunc) {
-	    struct chfunc_protect_t arg;
-	    arg.chfunc = chfunc;
-	    arg.arg = charg;
-	    arg.errmsg = errmsg;
-	    arg.buflen = errmsg_buflen;
-	    close(ep[0]);
-	    if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS);
-	    if (write(ep[1], &state, sizeof(state)) == sizeof(state) && state) {
-		VALUE errinfo = rb_errinfo();
-		io = rb_io_fdopen(ep[1], O_WRONLY|O_BINARY, NULL);
-		rb_marshal_dump(errinfo, 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);
+    return pid;
+}
+
+static void
+send_child_error(int fd, int state, char *errmsg, size_t errmsg_buflen)
+{
+    VALUE io = Qnil;
+    int err;
+
+    if (write(fd, &state, sizeof(state)) == sizeof(state) && state) {
+        VALUE errinfo = rb_errinfo();
+        io = rb_io_fdopen(fd, O_WRONLY|O_BINARY, NULL);
+        rb_marshal_dump(errinfo, io);
+        rb_io_flush(io);
+    }
+    err = errno;
+    if (write(fd, &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(fd, errmsg, errmsg_buflen) < 0)
+            err = errno;
+    }
+    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) \
+    (NIL_P(io) ? read(fd, (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
+    if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
+        err = errno;
+    }
+    *errp = err;
+    if (size == sizeof(err) &&
+        errmsg && 0 < errmsg_buflen) {
+        ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
+        if (0 <= ret) {
+            errmsg[ret] = '\0';
+        }
+    }
+    if (NIL_P(io))
+        close(fd);
+    else
+        rb_io_close(io);
+    return size != 0;
+}
+
+rb_pid_t
+rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
+        char *errmsg, size_t errmsg_buflen)
+{
+    rb_pid_t pid;
+    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;
+	}
+        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);
+            _exit(EXIT_FAILURE);
 #else
-	    _exit(127);
+            _exit(127);
 #endif
-	}
-    }
-    after_fork();
-    if (pid && chfunc) {
-	ssize_t size;
-	VALUE exc = Qnil;
-	close(ep[1]);
-	if ((read(ep[0], &state, sizeof(state))) == sizeof(state) && state) {
-	    io = rb_io_fdopen(ep[0], O_RDONLY|O_BINARY, NULL);
-	    exc = rb_marshal_load(io);
-	    rb_set_errinfo(exc);
-	}
-#define READ_FROM_CHILD(ptr, len) \
-	(NIL_P(io) ? read(ep[0], (ptr), (len)) : rb_io_bufread(io, (ptr), (len)))
-	if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
-	    err = errno;
-	}
-        if (size == sizeof(err) &&
-            errmsg && 0 < errmsg_buflen) {
-	    ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
-            if (0 <= ret) {
-                errmsg[ret] = '\0';
+        }
+        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;
         }
-	if (NIL_P(io))
-	    close(ep[0]);
-	else
-	    rb_io_close(io);
-	if (state || size) {
-	    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 {

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]