9.6. Handling Terminated Processes - child_died

This function is used by the Controller, Log, and History programs, because each of them can start child processes. This function is necessary because we want to handle two possibilities: the user untoggles a button to terminate a child program, or the child program gets terminated some other way. In the second case, we want the button to untoggle when the child program exits. We handle both of these cases the same, by detecting a SIGCHLD (child has died) signal as set up in the common function program_startup. Then we use the Gamma wait function to recover the child's process ID.

   /*--------------------------------------------------------------------
    * Function:    child_died
    * Returns:     t or nil
    * Description: Attached to SIGCHLD, this function wait()s for the child
    *              to die, extracts its process ID, and looks it up in the
    *              list of known children.  It then updates the list and if
    *              there is a GUI button attached, evaluates the cmd argument
    *              to pop out the button. Since this is attached to SIGCHLD,
    *              wait() should never block, as the data must be available
    *              immediately in order for SIGCHLD to have occurred. However,
    *              the Linux OS 'system' call creates spurious SIGCHLD calls,
    *              and as a general safety measure, we use the WNOHANG option,
    *              and call wait() on any signal (task ID parameter is 0).
    *------------------------------------------------------------------*/
   function child_died (cmd)
   {
     local child_data;
     local child, button;
     
     child_data = wait (0, WNOHANG);
     
     if(list_p(child_data))
       {
         child = car (assoc_equal (car(child_data), Children));
         Children = nremove (child, Children);

The child must be removed from the Children association list of the parent program (explained in the commentary on start_process for the control.g program). We use the Gamma assoc_equal function to find the sub-list containing the process ID of the dead child. Then we use nremove to remove that sub-list from Children. Other Gamma functions used are variations of car for accessing parts of a list.

         if(cadr(child))
           princ (cadr(child), " died\n");
         if(button = caddr(child))
           if (!destroyed_p(button))
             eval (cmd);
       }
   }