diff src/sysdep.c @ 163:0132846995bd r20-3b8

Import from CVS: tag r20-3b8
author cvs
date Mon, 13 Aug 2007 09:43:35 +0200
parents 6b37e6ddd302
children 2d532a89d707
line wrap: on
line diff
--- a/src/sysdep.c	Mon Aug 13 09:42:28 2007 +0200
+++ b/src/sysdep.c	Mon Aug 13 09:43:35 2007 +0200
@@ -226,11 +226,6 @@
 
 #endif /* NO_SUBPROCESSES */
 
-int wait_debugging;   /* Set nonzero to make following function work under dbx
-		         (at least for bsd).  */
-
-/* Wait for subprocess with process id `pid' to terminate and
-   make sure it will get eliminated (not remain forever as a zombie). */
 
 void
 wait_for_termination (int pid)
@@ -238,169 +233,157 @@
   /* #### With the new improved SIGCHLD handling stuff, there is much
      less danger of race conditions and some of the comments below
      don't apply.  This should be updated. */
+
+#if defined (NO_SUBPROCESSES)
   while (1)
     {
-#if !defined (NO_SUBPROCESSES)
-# ifdef VMS
-      int status;
-
-      status = SYS$FORCEX (&pid, 0, 0);
-      return;
-# else /* not VMS */
-      /* Note that, whenever any subprocess terminates (asynch. or synch.),
-	 the SIGCHLD handler will be called and it will call wait().
-	 Thus we cannot just call wait() ourselves, and we can't block
-	 SIGCHLD and then call wait(), because then if an asynch.
-	 process dies while we're waiting for our synch. process,
-	 Emacs will never notice that the asynch. process died.
-
-	 So, the general approach we take is to repeatedly block until
-	 a signal arrives, and then check if our process died
-	 using kill (pid, 0).  (We could also check the value of
-	 `synch_process_alive', since the SIGCHLD handler will reset
-	 that and we know that we're only being called on synchronous
-	 processes, but this approach is safer.  I don't trust
-	 the proper delivery of SIGCHLD.
-
-	 Note also that we cannot use any form of waitpid().
-	 A loop with WNOHANG will chew up CPU time; better to
-	 use sleep().  A loop without WNOWAIT will screw up
-	 the SIGCHLD handler (actually this is not true, if you
-	 duplicate the exit-status-reaping code; see below).
-	 A loop with WNOWAIT will result in a race condition
-	 if the process terminates between the process-status
-	 check and the call to waitpid(). */
-
-      /* Formerly, immediate_quit was set around this function call,
-	 but that could lead to problems if the QUIT happened when
-	 SIGCHLD was blocked -- it would remain blocked.  Yet another
-	 reason why immediate_quit is a bad idea.  In any case, there
-	 is no reason to resort to this because either the SIGIO or
-	 the SIGALRM will stop the block in EMACS_WAIT_FOR_SIGNAL(). */
+      /* No need to be tricky like below; we can just call wait(). */
+      /* #### should figure out how to write a wait_allowing_quit().
+	 Since hardly any systems don't have subprocess support,
+	 however, there doesn't seem to be much point. */
+      if (wait (0) == pid)
+	return;
+    }
+#elif defined (VMS)
+  int status = SYS$FORCEX (&pid, 0, 0);
+  return;
+
+#elif defined (HAVE_WAITPID)
+  /* Note that, whenever any subprocess terminates (asynch. or synch.),
+     the SIGCHLD handler will be called and it will call wait().  Thus
+     we cannot just call wait() ourselves, and we can't block SIGCHLD
+     and then call wait(), because then if an asynch.  process dies
+     while we're waiting for our synch. process, Emacs will never
+     notice that the asynch. process died.
+
+     So, the general approach we take is to repeatedly block until a
+     signal arrives, and then check if our process died using kill
+     (pid, 0).  (We could also check the value of `synch_process_alive',
+     since the SIGCHLD handler will reset that and we know that we're
+     only being called on synchronous processes, but this approach is
+     safer.  I don't trust the proper delivery of SIGCHLD.
+
+     Note also that we cannot use any form of waitpid().  A loop with
+     WNOHANG will chew up CPU time; better to use sleep().  A loop
+     without WNOWAIT will screw up the SIGCHLD handler (actually this
+     is not true, if you duplicate the exit-status-reaping code; see
+     below).  A loop with WNOWAIT will result in a race condition if
+     the process terminates between the process-status check and the
+     call to waitpid(). */
+
+  /* Formerly, immediate_quit was set around this function call, but
+     that could lead to problems if the QUIT happened when SIGCHLD was
+     blocked -- it would remain blocked.  Yet another reason why
+     immediate_quit is a bad idea.  In any case, there is no reason to
+     resort to this because either the SIGIO or the SIGALRM will stop
+     the block in EMACS_WAIT_FOR_SIGNAL(). */
+
+  /* Apparently there are bugs on some systems with the second method
+     used below (the EMACS_BLOCK_SIGNAL method), whereby zombie
+     processes get left around.  It appears in those cases that the
+     SIGCHLD handler is never getting invoked.  It's not clear whether
+     this is an Emacs bug or a kernel bug or both: on HPUX this
+     problem is observed only with XEmacs, but under Solaris 2.4 all
+     sorts of different programs have problems with zombies.  The
+     method we use here does not require a working SIGCHLD (but will
+     not break if it is working), and should be safe. */
+  /*
+     We use waitpid(), contrary to the remarks above.  There is no
+     race condition, because the three situations when sigchld_handler
+     is invoked should be handled OK:
+
+     - handler invoked before waitpid(): In this case, subprocess
+       status will be set by sigchld_handler.  waitpid() here will
+       return -1 with errno set to ECHILD, which is a valid exit
+       condition.
+
+     - handler invoked during waitpid(): as above, except that errno
+       here will be set to EINTR.  This will cause waitpid() to be
+       called again, and this time it will exit with ECHILD.
+
+     - handler invoked after waitpid(): The following code will reap
+       the subprocess. In the handler, wait() will return -1 because
+       there is no child to reap, and the handler will exit without
+       modifying child subprocess status.  */
+  int ret, status;
+
+  /* Because the SIGCHLD handler can potentially reap the synchronous
+     subprocess, we should take care of that.  */
+
+  /* Will stay in the do loop as long as:
+     1. Process is alive
+     2. Ctrl-G is not pressed */
+  do
+    {
       QUIT;
-#  ifdef HAVE_WAITPID
-      /* Apparently there are bugs on some systems with the second
-	 method used below (the EMACS_BLOCK_SIGNAL method), whereby
-	 zombie processes get left around.  It appears in those cases
-	 that the SIGCHLD handler is never getting invoked.  It's
-	 not clear whether this is an Emacs bug or a kernel bug or
-	 both: on HPUX this problem is observed only with XEmacs,
-	 but under Solaris 2.4 all sorts of different programs have
-	 problems with zombies.  The method we use here does not
-	 require a working SIGCHLD (but will not break if it is
-	 working), and should be safe. */
-      /* 
-	 We use waitpid() contrary to the remarks above.  There is 
-	 no race condition, because the three situations when 
-	 sigchld_handler is invoked should be handled OK:
-	 - handler invoked before waitpid(): In this case, subprocess 
-	   status will be set by sigchld_handler.  waitpid() here will 
-	   return -1 with errno set to ECHILD, which is a valid 
-	   exit condition.
-
-	 - handler invoked during waitpid(): as above, except that 
-	   errno here will be set to EINTR.  This will cause waitpid() to 
-	   be called again, and this time it will exit with ECHILD.
-
-	 - handler invoked after waitpid(): The following code will reap 
-	   the subprocess. In the handler, wait()  will return -1 
-	   because there is no child to reap, and the handler will exit
-	   without modifying child subprocess status.
-      */
-      {
-	/* Because the SIGCHLD handler can potentially reap the
-	synchronous subprocess, we should take care of that.  */
-	
-	int ret;
-	int w;
-	/* Will stay in the do loop as long as:
-	   1. Process is alive
-	   2. Ctrl-G is not pressed */
-	do
-	  {
-	    QUIT;
-	    ret = waitpid (pid, &w, 0);
-	    /* waitpid returns 0 if the process is still alive. */
-	  }
-	while (ret == 0 || (ret == -1 && errno == EINTR));
-	
-	/* On exiting the loop, ret will be -1, with errno set to 
-	   ECHILD if the child has already been reaped, eg in the 
-	   signal handler.  */
-
-	if (! (ret == pid || (ret == -1 && errno == ECHILD)))
-	  {
-	    /* We've had some error condition here.  Per POSIX, the
-	       only other possibilities are:
-	       EFAULT (bus error accessing arg 2) or EINVAL (incorrect
-	       arguments), which are both program bugs.
-	     
-	       Since implementations may add their own error
-	       indicators on top, we ignore it by default.
-	       */
-	    
-	    break;
-	  }
-
-	/* Set synch process globals.  This is can also happen 
-	   in sigchld_handler, and that code is duplicated. */
-	if (ret == pid)
-	  { /* Update the global sigchld stats. */
-	    synch_process_alive = 0;
-	    if (WIFEXITED (w))
-	      synch_process_retcode = WEXITSTATUS (w);
-	    else if (WIFSIGNALED (w))
-	      synch_process_death = signal_name (WTERMSIG (w));
-	  }
-	break;
-      }
-#  elif defined (EMACS_BLOCK_SIGNAL) && !defined (BROKEN_WAIT_FOR_SIGNAL) && defined (SIGCHLD)
-      if (!wait_debugging)
+      ret = waitpid (pid, &status, 0);
+      /* waitpid returns 0 if the process is still alive. */
+    }
+  while (ret == 0 || (ret == -1 && errno == EINTR));
+
+  if (ret == pid) /* Success */
+    /* Set synch process globals.  This is can also happen
+       in sigchld_handler, and that code is duplicated. */
+    {
+      synch_process_alive = 0;
+      if (WIFEXITED (status))
+	synch_process_retcode = WEXITSTATUS (status);
+      else if (WIFSIGNALED (status))
+	synch_process_death = signal_name (WTERMSIG (status));
+    }
+  /* On exiting the loop, ret will be -1, with errno set to ECHILD if
+     the child has already been reaped, e.g. in the signal handler.  */
+
+  /* Otherwise, we've had some error condition here.
+     Per POSIX, the only other possibilities are:
+     - EFAULT (bus error accessing arg 2) or
+     - EINVAL (incorrect arguments),
+     which are both program bugs.
+
+     Since implementations may add their own error indicators on top,
+     we ignore it by default.  */
+#elif defined (EMACS_BLOCK_SIGNAL) && !defined (BROKEN_WAIT_FOR_SIGNAL) && defined (SIGCHLD)
+  while (1)
+    {
+      static int wait_debugging = 0; /* Set nonzero to make following
+                           function work under dbx (at least for bsd).  */
+      QUIT;
+      if (wait_debugging)
+	return;
+
+      EMACS_BLOCK_SIGNAL (SIGCHLD);
+      /* Block SIGCHLD from happening during this check,
+	 to avoid race conditions. */
+      if (kill (pid, 0) < 0)
 	{
-	  EMACS_BLOCK_SIGNAL (SIGCHLD);
-	  /* Block SIGCHLD from happening during this check,
-	     to avoid race conditions. */
-	  if (kill (pid, 0) < 0)
-	    {
-	      EMACS_UNBLOCK_SIGNAL (SIGCHLD);
-	      return;
-	    }
-	  else
-	    /* WARNING: Whatever this macro does *must* not allow SIGCHLD
-	       to happen between the time that it's reenabled and when we
-	       begin to block.  Otherwise we may end up blocking for a
-	       signal that has already arrived and isn't coming again.
-	       Can you say "race condition"?
-	       
-	       I assume that the system calls sigpause() or sigsuspend()
-	       to provide this atomicness.  If you're getting hangs in
-	       sigpause()/sigsuspend(), then your OS doesn't
-	       implement this properly (this applies under hpux9,
-	       for example).  Try defining BROKEN_WAIT_FOR_SIGNAL. */
-	    EMACS_WAIT_FOR_SIGNAL (SIGCHLD);
-	  continue;
+	  EMACS_UNBLOCK_SIGNAL (SIGCHLD);
+	  return;
 	}
-#  else /* not HAVE_WAITPID and (not EMACS_BLOCK_SIGNAL or
-	   BROKEN_WAIT_FOR_SIGNAL) */
-      /* This approach is kind of cheesy but is guaranteed(?!) to work
-	 for all systems. */
+      else
+	/* WARNING: Whatever this macro does *must* not allow SIGCHLD
+	   to happen between the time that it's reenabled and when we
+	   begin to block.  Otherwise we may end up blocking for a
+	   signal that has already arrived and isn't coming again.
+	   Can you say "race condition"?
+
+	   I assume that the system calls sigpause() or sigsuspend()
+	   to provide this atomicness.  If you're getting hangs in
+	   sigpause()/sigsuspend(), then your OS doesn't implement
+	   this properly (this applies under hpux9, for example).
+	   Try defining BROKEN_WAIT_FOR_SIGNAL. */
+	EMACS_WAIT_FOR_SIGNAL (SIGCHLD);
+    }
+#else /* not HAVE_WAITPID and (not EMACS_BLOCK_SIGNAL or BROKEN_WAIT_FOR_SIGNAL) */
+  /* This approach is kind of cheesy but is guaranteed(?!) to work
+     for all systems. */
+  while (1)
+    {
+      QUIT;
       if (kill (pid, 0) < 0)
 	return;
       emacs_sleep (1);
-#  endif /* not HAVE_WAITPID and (not EMACS_BLOCK_SIGNAL or
-	   BROKEN_WAIT_FOR_SIGNAL) */
-# endif /* not VMS */
-#else /* NO_SUBPROCESSES */
-      /* No need to be tricky like above; we can just call wait(). */
-      int status;
-      /* #### should figure out how to write a wait_allowing_quit().
-	 Since hardly any systems don't have subprocess support,
-	 however, there doesn't seem to be much point. */
-      status = wait (0);
-      if (status == pid)
-	return;
-#endif /* NO_SUBPROCESSES */
     }
+#endif /* OS features */
 }
 
 
@@ -3299,6 +3282,16 @@
 
 /***** (these are primarily required for USG, it seems) *****/
 
+#ifndef HAVE_GETCWD
+char *
+getcwd (char *pathname, int size)
+{
+  return getwd (pathname);
+}
+#endif /* emulate getcwd */
+
+
+#if 0 /* mrb */
 /*
  *	Warning, this function may not duplicate BSD 4.2 action properly
  *	under error conditions.
@@ -3325,6 +3318,7 @@
   return pathname;
 }
 #endif /* HAVE_GETWD */
+#endif /* 0 - mrb */
 
 /*
  *	Emulate rename using unlink/link.  Note that this is