entry widget broken in 3.99.1?
 
I've found a bug in process.c that prevents you from getting the exit status
of a child process under certain circumstances.
Description of problem:
In the handler for SIGCHLD, a call is made to waitpid() to check the status
of each of the child processes.  In the current version of process.c, a
non-zero return value is interpreted as meaning that the child has exited
and the child's status has been read:
static int internal_process_alivep(SCM process)
...
    res = waitpid(PROCPID(process), &info, WNOHANG);
    if (res == 0)
      /* process is still running */
      return TRUE;
    else {
      /* process has terminated and we must save this information */
      PROCESS(process)->exited      = TRUE;
      PROCESS(process)->exit_status = info;
      return FALSE; 
...
This is not always the case.  If (process-wait [process]) has been called to
wait on a particular child, it will read the status, and the waitpid() call
in the SIGCHLD handler will return a -1 (no such child).  The info field
doesn't contain any data and it is written over the exit_status that was
saved by (process-wait [process]) -- thus the exit_status field now contains
random garbage.
The fix:
Always check the return status from waitpid() to see if it returns the
requested pid:
    res = waitpid(PROCPID(process), &info, WNOHANG);
    if (res == 0)
      {
      /* process is still running */
      return TRUE;
      }
    else if (res == PROCPID(process))
      {
      /* process has terminated and we must save this information */
      PROCESS(process)->exited      = TRUE;
      PROCESS(process)->exit_status = info;
      return FALSE;
      }
    else
      {
      /* might not have found process because we've already waited for it */
      /* if so, then status has already been updated */
      return FALSE;
      }            
[All calls to waitpid() should be handled similarly]
I've included a context diff below.  It has only been tested on Linux
2.0.31, but judging by the man pages, it ought to work for Solaris 2.5 also.
Unfortunately, I re-indented bsome of the code while I was debugging, and
haven't un-done my formatting changes. So, there are cosmetic-only changes
reflected in some of the patch.  Sorry.
------------------------------cut here------------------------------
*** process.c.old	Fri Apr 10 02:13:18 1998
--- process.c	Thu May 14 09:05:51 1998
***************
*** 81,108 ****
  }
  
  static int internal_process_alivep(SCM process)
! {
!   int info, res;
  
    if (PROCESS(process)->exited) 
      return FALSE;
!   else {
      /* Use waitpid to gain the info. */
      res = waitpid(PROCPID(process), &info, WNOHANG);
      if (res == 0) 
        /* process is still running */
        return TRUE;
!     else {
        /* process has terminated and we must save this information */
        PROCESS(process)->exited      = TRUE;
        PROCESS(process)->exit_status = info;
        return FALSE;
      }
    }
! }
  
  static void process_terminate_handler(int sig) /* called when a child dies */
! {
    register int i;
    SCM proc;
  
--- 81,118 ----
  }
  
  static int internal_process_alivep(SCM process)
!   {
!   int info = 0, res = -1;
    
    if (PROCESS(process)->exited) 
      return FALSE;
!   else 
!     {
      /* Use waitpid to gain the info. */
      res = waitpid(PROCPID(process), &info, WNOHANG);
      if (res == 0) 
+       {
        /* process is still running */
        return TRUE;
!       }
!     else if (res == PROCPID(process))
!       {
        /* process has terminated and we must save this information */
        PROCESS(process)->exited      = TRUE;
        PROCESS(process)->exit_status = info;
        return FALSE;
        }
+     else
+       {
+       /* might not have found process because we've already waited for it */
+       /* if so, then status has already been updated */
+       return FALSE;
        }
!     }
!   }
  
  static void process_terminate_handler(int sig) /* called when a child dies */
!   {
    register int i;
    SCM proc;
  
***************
*** 110,118 ****
    static int in_handler = 0;
  
    signal(SIGCHLD, process_terminate_handler); /* Necessary on System V */
!   if (in_handler++) /* Execution is re-entrant */ return;
    
!   do {
  #endif
      /* Find the process which is terminated 
       * Note that this loop can find:
--- 120,130 ----
    static int in_handler = 0;
  
    signal(SIGCHLD, process_terminate_handler); /* Necessary on System V */
!   if (in_handler++) /* Execution is re-entrant */ 
!     return;
    
!   do 
!     {
  #endif
      /* Find the process which is terminated 
       * Note that this loop can find:
***************
*** 124,130 ****
       *		     PURGE_PROCESS_TABLE
       * Sometimes I think that life is a little bit complicated.... 
       */
!     for(i = 0; i<MAX_PROC_NUM; i++) {
        proc = proc_arr[i];
        if (PROCESSP(proc) && !internal_process_alivep(proc))
          /* This process has exited. We can delete it from the table */
--- 136,143 ----
       *		     PURGE_PROCESS_TABLE
       * Sometimes I think that life is a little bit complicated.... 
       */
!     for(i = 0; i<MAX_PROC_NUM; i++) 
!       {
        proc = proc_arr[i];
        if (PROCESSP(proc) && !internal_process_alivep(proc))
          /* This process has exited. We can delete it from the table */
***************
*** 138,144 ****
       */
    } while (--in_handler > 0);
  #endif
! }
  
  
  static SCM make_process(void)
--- 151,157 ----
       */
      } while (--in_handler > 0);
  #endif
!   }
  
  
  static SCM make_process(void)
***************
*** 446,489 ****
  }
  
  static PRIMITIVE process_wait(SCM process)
! {
    PURGE_PROCESS_TABLE();
  
    if(NPROCESSP(process)) Err("process-wait: bad process", process);
    
    if (PROCESS(process)->exited) return Ntruth;
!   else {
!     int ret = waitpid(PROCPID(process), &PROCESS(process)->exit_status, 0);
  
      PROCESS(process)->exited = TRUE;
!     return (ret == 0) ? Ntruth : Truth;
    }
! }
  
  
  static PRIMITIVE process_xstatus(SCM process)
! {
!   int info, n;
  
    PURGE_PROCESS_TABLE();
  
!   if (NPROCESSP(process)) Err("process-exit-status: bad process", process);
    
!   if (PROCESS(process)->exited) n = PROCESS(process)->exit_status;
!   else {
!     if (waitpid(PROCPID(process), &info, WNOHANG) == 0) {
        /* Process is still running */
        return Ntruth;
      }
!     else {
        /* Process is now terminated */
        PROCESS(process)->exited      = TRUE;
        PROCESS(process)->exit_status = info;
        n = WEXITSTATUS(info);
      }
    }
    return STk_makeinteger((long) n);
! }
  
  static PRIMITIVE process_send_signal(SCM process, SCM signal)
  {
--- 459,519 ----
  }
  
  static PRIMITIVE process_wait(SCM process)
!   {
    PURGE_PROCESS_TABLE();
  
    if(NPROCESSP(process)) Err("process-wait: bad process", process);
    
    if (PROCESS(process)->exited) return Ntruth;
!   else 
!     {
!     int info=0, res=-1;
  
+     res = waitpid(PROCPID(process), &info, 0);
+ 
+     if (res == PROCPID(process))
+       {
+       PROCESS(process)->exit_status = info;
        PROCESS(process)->exited = TRUE;
!       return Truth;
        }
!     else
!       return Ntruth;
!     }
!   }
  
  
  static PRIMITIVE process_xstatus(SCM process)
!   {
!   int info, n, res;
  
    PURGE_PROCESS_TABLE();
  
!   if (NPROCESSP(process)) 
!     Err("process-exit-status: bad process", process);
    
!   if (PROCESS(process)->exited)
!     n = WEXITSTATUS(PROCESS(process)->exit_status);
!   else 
!     {
!     res = waitpid(PROCPID(process), &info, WNOHANG);
!     if (res == 0)
!       {
        /* Process is still running */
        return Ntruth;
        }
!     else if (res == PROCPID(process))
!       {
        /* Process is now terminated */
        PROCESS(process)->exited      = TRUE;
        PROCESS(process)->exit_status = info;
        n = WEXITSTATUS(info);
        }
+     else
+       return Ntruth;
      }
    return STk_makeinteger((long) n);
!   }
  
  static PRIMITIVE process_send_signal(SCM process, SCM signal)
  {
------------------------------cut here------------------------------
Received on Mon May 18 1998 - 21:54:02 CEST
This archive was generated by hypermail 2.3.0
: Mon Jul 21 2014 - 19:38:59 CEST