home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / new / util / edit / jade / src / unix_processes.c < prev    next >
C/C++ Source or Header  |  1994-10-03  |  35KB  |  1,407 lines

  1. /* unix_processes.c -- Subprocess handling for Unix
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.    If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <sys/types.h>
  24. #include <sys/wait.h>
  25. #include <sys/signal.h>
  26. #include <sys/fcntl.h>
  27. #include <sys/time.h>
  28. #include <sys/stat.h>
  29. #include <sys/ioctl.h>
  30. #include <errno.h>
  31. #include <unistd.h>
  32. #include <termios.h>
  33.  
  34. _PR void protect_procs(void);
  35. _PR void unprotect_procs(void);
  36. _PR bool proc_notification(void);
  37. static void check_for_zombies(void);
  38. static void read_from_process(int);
  39. _PR int     write_to_process(VALUE, u_char *, int);
  40. _PR void proc_mark(VALUE);
  41. _PR void proc_sweep(void);
  42. _PR void proc_prin(VALUE, VALUE);
  43. _PR void sigchld_restart(bool);
  44. _PR void proc_init(void);
  45. _PR void proc_kill(void);
  46.  
  47. static struct sigaction chld_sigact;
  48. static sigset_t chld_sigset;
  49.  
  50. struct Proc
  51. {
  52.     u_char    pr_Type;
  53.     char    pr_Status;    /* PR_?? value */
  54.     struct Proc *pr_Next;
  55.     /* Chain of all processes waiting to be notified of a change of state. */
  56.     struct Proc *pr_NotifyNext;
  57.     pid_t    pr_Pid;
  58.     /* pr_Stdin is where we write, pr_Stdout where we read, they may be the
  59.        same.  */
  60.     int        pr_Stdin, pr_Stdout;
  61.     VALUE    pr_OutputStream;
  62.     int        pr_ExitStatus;
  63.     VALUE    pr_NotifyFun;
  64.     VALUE    pr_Prog;
  65.     VALUE    pr_Args;
  66.     VALUE    pr_Dir;
  67.     VALUE    pr_ConnType;
  68. };
  69.  
  70. /* <= 0 means process not running, > 0 means could be running...  */
  71. #define PR_STOPPED  2        /* waiting to be continued */
  72. #define PR_RUNNING  1        /* running merrily */
  73. #define PR_DEAD        0        /* nothing happening on this obj */
  74. #define PR_EXITED  -1        /* process dead but no EOF from pty */
  75.  
  76. /* Connection types, pty-echo is a pty with the ECHO bit set in c_lflag */
  77. static VALUE sym_pipe, sym_pty, sym_pty_echo;
  78.  
  79. #define PR_CONN_PTY_P(p) \
  80.     (((p)->pr_ConnType == sym_pty) || ((p)->pr_ConnType == sym_pty_echo))
  81.  
  82. #define PR_CONN_PTY_ECHO_P(p) \
  83.     ((p)->pr_ConnType == sym_pty_echo)
  84.  
  85. #define PR_CONN_PIPE_P(p) \
  86.     ((p)->pr_ConnType == sym_pipe)
  87.  
  88. /* Handy debugging macro */
  89. #if 0
  90. # define DB(x) fprintf x
  91. #else
  92. # define DB(x)
  93. #endif
  94.  
  95. static struct Proc *process_chain;
  96. static struct Proc *notify_chain;
  97. static int process_run_count;
  98.  
  99. /* This semaphorey thing protects all operations done on process structures
  100.    from SIGCHLD and the process reaping it causes.  */
  101. static int process_mutex = -1;
  102. static bool got_sigchld;
  103.  
  104. INLINE void
  105. protect_procs(void)
  106. {
  107.     process_mutex++;
  108. }
  109.  
  110. void
  111. unprotect_procs(void)
  112. {
  113.     if((process_mutex == 0) && got_sigchld)
  114.     {
  115.     /* Have to leave (process_mutex == 0) while looking for zombies.  */
  116.     got_sigchld = FALSE;
  117.     check_for_zombies();
  118.     }
  119.     process_mutex--;
  120. }
  121.  
  122. /* PR's NotifyFun will be called when possible. This function is safe
  123.    to call from signal handlers.  */
  124. static void
  125. queue_notify(struct Proc *pr)
  126. {
  127.     if(pr->pr_NotifyNext == NULL)
  128.     {
  129.     pr->pr_NotifyNext = notify_chain;
  130.     notify_chain = pr;
  131.     }
  132. }
  133.  
  134. /* Dispatch all queued notification.  */
  135. bool
  136. proc_notification(void)
  137. {
  138.     if(!notify_chain)
  139.     return(FALSE);
  140.     protect_procs();
  141.     cursor(curr_vw, CURS_OFF);
  142.     while(notify_chain != NULL)
  143.     {
  144.     struct Proc *pr = notify_chain;
  145.     notify_chain = pr->pr_NotifyNext;
  146.     pr->pr_NotifyNext = NULL;
  147.     if(pr->pr_NotifyFun && !NILP(pr->pr_NotifyFun))
  148.         funcall(pr->pr_NotifyFun, sym_nil);
  149.     }
  150.     cursor(curr_vw, CURS_ON);
  151.     unprotect_procs();
  152.     return(TRUE);
  153. }
  154.  
  155. /* Checks if any of my children are zombies, takes appropriate action. */
  156. static void
  157. check_for_zombies(void)
  158. {
  159.     int status;
  160.     pid_t pid;
  161.     if(!process_run_count)
  162.     return;
  163.     while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)
  164.     {
  165.     struct Proc *pr = process_chain;
  166. #ifdef DEBUG
  167.     messagef("SIGCHLD: pid %d -- status 0x%x", pid, status);
  168. #endif
  169.     while(pr)
  170.     {
  171.         if((pr->pr_Status > 0) && (pr->pr_Pid == pid))
  172.         break;
  173.         pr = pr->pr_Next;
  174.     }
  175.     if(pr)
  176.     {
  177.         if(WIFSTOPPED(status))
  178.         {
  179.         pr->pr_Status = PR_STOPPED;
  180.         queue_notify(pr);
  181.         }
  182.         else
  183.         {
  184.         pr->pr_ExitStatus = status;
  185.         process_run_count--;
  186.         /* It seems that I can't just nuke the pty once the child's
  187.            dead -- there can be data pending on it still. So, I set
  188.            pr_Status to an in-between value and hope to get an eof
  189.            over pr_Stdin RSN  */
  190.         if((pr->pr_Stdout != 0) || (pr->pr_Stdin != 0))
  191.             pr->pr_Status = PR_EXITED;
  192.         else
  193.         {
  194.             /* No file handles open so just die */
  195.             pr->pr_Status = PR_DEAD;
  196.             queue_notify(pr);
  197.         }
  198.         }
  199.     }
  200.     }
  201. }
  202.  
  203. static void
  204. sigchld_handler(int sig)
  205. {
  206.     if(process_mutex < 0)
  207.     check_for_zombies();
  208.     else
  209.     got_sigchld = TRUE;
  210. }
  211.  
  212. static void
  213. read_from_process(int fd)
  214. {
  215.     struct Proc *pr = process_chain;
  216.     protect_procs();
  217.     while(pr)
  218.     {
  219.     if((pr->pr_Status != PR_DEAD) && (pr->pr_Stdout == fd))
  220.         break;
  221.     pr = pr->pr_Next;
  222.     }
  223.     if(pr)
  224.     {
  225.     u_char buf[1025];
  226.     int actual;
  227.     cursor(curr_vw, CURS_OFF);
  228.     do {
  229.         if((actual = read(fd, buf, 1024)) > 0)
  230.         {
  231.         buf[actual] = 0;
  232.         if(!NILP(pr->pr_OutputStream))
  233.             stream_puts(pr->pr_OutputStream, buf, actual, FALSE);
  234.         }
  235.     } while((actual > 0) || (errno == EINTR));
  236.  
  237.     if((actual <= 0) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
  238.     {
  239.         /* We assume EOF  */
  240. #ifdef HAVE_X11
  241.         FD_CLR(pr->pr_Stdout, &x11_fd_read_set);
  242.         x11_fd_read_action[pr->pr_Stdout] = NULL;
  243. #endif
  244.         close(pr->pr_Stdout);
  245.         if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  246.         close(pr->pr_Stdin);
  247.         pr->pr_Stdout = pr->pr_Stdin = 0;
  248.  
  249.         /* This means that the process has already exited and we were
  250.            just waiting for the dregs of its output.  */
  251.         if(pr->pr_Status < 0)
  252.         {
  253.         pr->pr_Status = PR_DEAD;
  254.         queue_notify(pr);
  255.         }
  256.     }
  257.     cursor(curr_vw, CURS_ON);
  258.     }
  259.     unprotect_procs();
  260. }
  261.  
  262. int
  263. write_to_process(VALUE pr, u_char *buf, int bufLen)
  264. {
  265.     int act = 0;
  266.     if(!PROCESSP(pr))
  267.     return(0);
  268.     protect_procs();
  269.     if(VPROC(pr)->pr_Status > 0)
  270.     {
  271.     if(VPROC(pr)->pr_Stdin == 0)
  272.         cmd_signal(sym_process_error, list_2(pr, MKSTR("No link to input")));
  273.     else
  274.     {
  275.         /* This will block */
  276.         act = write(VPROC(pr)->pr_Stdin, buf, bufLen);
  277.         if(act < 0)
  278.         {
  279.         signal_file_error(pr);
  280.         act = 0;
  281.         }
  282.     }
  283.     }
  284.     else
  285.     cmd_signal(sym_process_error, list_2(pr, MKSTR("Not running")));
  286.     unprotect_procs();
  287.     return(act);
  288. }
  289.  
  290. static bool
  291. signal_process(struct Proc *pr, int sig, bool do_grp)
  292. {
  293.     bool rc = TRUE;
  294.     protect_procs();
  295.     if(do_grp)
  296.     {
  297.     if(pr->pr_Stdin && PR_CONN_PTY_P(pr))
  298.     {
  299.         pid_t gid = tcgetpgrp(pr->pr_Stdin);
  300.         if(gid != -1)
  301.         kill(-gid, sig);
  302.         else if(pr->pr_Status != PR_DEAD)
  303.         kill(-pr->pr_Pid, sig);
  304.         else
  305.         rc = FALSE;
  306.     }
  307.     else
  308.     {
  309.         if(pr->pr_Status > 0)
  310.         kill(-pr->pr_Pid, sig);
  311.         else
  312.         rc = FALSE;
  313.     }
  314.     }
  315.     else
  316.     {
  317.     if(pr->pr_Status > 0)
  318.         kill(pr->pr_Pid, sig);
  319.     else
  320.         rc = FALSE;
  321.     }
  322.     unprotect_procs();
  323.     return(rc);
  324. }
  325.  
  326. /* This is only called during GC, when the process isn't being referenced.
  327.    it will already have been taken out of the chain.  */
  328. static void
  329. kill_process(struct Proc *pr)
  330. {
  331.     protect_procs();
  332.     if(pr->pr_Status != PR_DEAD)
  333.     {
  334.     if(pr->pr_Status == PR_RUNNING)
  335.     {
  336.         /* is this too heavy-handed?? */
  337.         if(!signal_process(pr, SIGKILL, TRUE))
  338.         kill(-pr->pr_Pid, SIGKILL);
  339.         waitpid(pr->pr_Pid, &pr->pr_ExitStatus, 0);
  340.         process_run_count--;
  341.     }
  342.     if(pr->pr_Stdout)
  343.     {
  344. #ifdef HAVE_X11
  345.         FD_CLR(pr->pr_Stdout, &x11_fd_read_set);
  346.         x11_fd_read_action[pr->pr_Stdout] = NULL;
  347. #endif
  348.         close(pr->pr_Stdout);
  349.     }
  350.     if(pr->pr_Stdin && (pr->pr_Stdin !=