]> git.eshelyaron.com Git - emacs.git/commitdiff
Attempt to work around macOS vfork bug
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 19 May 2017 07:11:48 +0000 (00:11 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 19 May 2017 07:13:27 +0000 (00:13 -0700)
Problem reported by YAMAMOTO Mitsuharu in:
http://lists.gnu.org/archive/html/emacs-devel/2017-05/msg00342.html
This is related to the fix for Bug#26397.
* src/callproc.c (call_process_cleanup, call_process) [!MSDOS]:
Report internal error if wait_for_termination fails.
* src/sysdep.c (get_child_status): Return -1 if waitpid is
buggy, instead of aborting.
(wait_for_termination): Return bool success value.
All callers changed.

src/callproc.c
src/sysdep.c
src/syswait.h

index e967e45d03fd7c4e698635a63e27e206c4665bb9..7c85eed835fdf2542f75d971376ad9b13830a2f1 100644 (file)
@@ -202,10 +202,11 @@ call_process_cleanup (Lisp_Object buffer)
       message1 ("Waiting for process to die...(type C-g again to kill it instantly)");
 
       /* This will quit on C-g.  */
-      wait_for_termination (synch_process_pid, 0, 1);
-
+      bool wait_ok = wait_for_termination (synch_process_pid, NULL, true);
       synch_process_pid = 0;
-      message1 ("Waiting for process to die...done");
+      message1 (wait_ok
+               ? "Waiting for process to die...done"
+               : "Waiting for process to die...internal error");
     }
 #endif /* !MSDOS */
 }
@@ -866,9 +867,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
               make_number (total_read));
     }
 
+  bool wait_ok = true;
 #ifndef MSDOS
   /* Wait for it to terminate, unless it already has.  */
-  wait_for_termination (pid, &status, fd0 < 0);
+  wait_ok = wait_for_termination (pid, &status, fd0 < 0);
 #endif
 
   /* Don't kill any children that the subprocess may have left behind
@@ -878,6 +880,9 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
   SAFE_FREE ();
   unbind_to (count, Qnil);
 
+  if (!wait_ok)
+    return build_unibyte_string ("internal error");
+
   if (WIFSIGNALED (status))
     {
       const char *signame;
index ac6eed0e581172dd915324262f36a46eaf7f6719..70f4a9dd7ea0e62a065d147b2e26d6b1604525cd 100644 (file)
@@ -368,8 +368,8 @@ init_baud_rate (int fd)
    Use waitpid-style OPTIONS when waiting.
    If INTERRUPTIBLE, this function is interruptible by a signal.
 
-   Return CHILD if successful, 0 if no status is available;
-   the latter is possible only when options & NOHANG.  */
+   Return CHILD if successful, 0 if no status is available, and a
+   negative value (setting errno) if waitpid is buggy.  */
 static pid_t
 get_child_status (pid_t child, int *status, int options, bool interruptible)
 {
@@ -392,13 +392,14 @@ get_child_status (pid_t child, int *status, int options, bool interruptible)
       pid = waitpid (child, status, options);
       if (0 <= pid)
        break;
-
-      /* Check that CHILD is a child process that has not been reaped,
-        and that STATUS and OPTIONS are valid.  Otherwise abort,
-        as continuing after this internal error could cause Emacs to
-        become confused and kill innocent-victim processes.  */
       if (errno != EINTR)
-       emacs_abort ();
+       {
+         /* Most likely, waitpid is buggy and the operating system
+            lost track of the child somehow.  Return -1 and let the
+            caller try to figure things out.  Possibly the bug could
+            cause Emacs to kill the wrong process.  Oh well.  */
+         return pid;
+       }
     }
 
   /* If successful and status is requested, tell wait_reading_process_output
@@ -413,11 +414,13 @@ get_child_status (pid_t child, int *status, int options, bool interruptible)
    CHILD must be a child process that has not been reaped.
    If STATUS is non-null, store the waitpid-style exit status into *STATUS
    and tell wait_reading_process_output that it needs to look around.
-   If INTERRUPTIBLE, this function is interruptible by a signal.  */
-void
+   If INTERRUPTIBLE, this function is interruptible by a signal.
+   Return true if successful, false (setting errno) if CHILD cannot be
+   waited for because waitpid is buggy.  */
+bool
 wait_for_termination (pid_t child, int *status, bool interruptible)
 {
-  get_child_status (child, status, 0, interruptible);
+  return 0 <= get_child_status (child, status, 0, interruptible);
 }
 
 /* Report whether the subprocess with process id CHILD has changed status.
index 846a975b2413556142aa242c6b2f5084dc9a5722..055562ae48bba444e0f96e7017dd1cb4be461b41 100644 (file)
@@ -56,7 +56,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 
 /* Defined in sysdep.c.  */
-extern void wait_for_termination (pid_t, int *, bool);
+extern bool wait_for_termination (pid_t, int *, bool);
 extern pid_t child_status_changed (pid_t, int *, int);
 
 #endif /* EMACS_SYSWAIT_H */