home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / new / util / edit / jade / src / unix_processes.c < prev    next >
C/C++ Source or Header  |  1994-04-19  |  26KB  |  996 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 void readfromproc(int);
  37. _PR int  writetoproc(VALUE, u_char *);
  38. _PR void proc_mark(VALUE);
  39. _PR void proc_sweep(void);
  40. _PR void proc_prin(VALUE, VALUE);
  41. _PR void sys_proc_init(void);
  42. _PR void sys_proc_kill(void);
  43.  
  44. #define USE_SIGACTION
  45.  
  46. #ifdef USE_SIGACTION
  47. static struct sigaction ChldAct;
  48. static sigset_t ChldSet;
  49. #endif
  50.  
  51. struct Proc
  52. {
  53.     u_char    pr_Type;
  54.     char    pr_Status;    /* PR_?? value */
  55.     struct Proc *pr_Next;
  56.     pid_t    pr_Pid;
  57.     /* pr_Stdin is where we write, pr_Stdout where we read, they may be the
  58.        same.  */
  59.     int        pr_Stdin, pr_Stdout;
  60.     VALUE    pr_OutputStream;
  61.     int        pr_ExitStatus;
  62.     VALUE    pr_ExitFunc;
  63.     VALUE    pr_File;
  64.     VALUE    pr_Argv;
  65. };
  66.  
  67. /* <= 0 means process not running, > 0 means could be running...  */
  68. #define PR_STOPPED  2        /* waiting to be continued */
  69. #define PR_RUNNING  1        /* running merrily */
  70. #define PR_DEAD        0        /* nothing happening on this obj */
  71. #define PR_EXITED  -1        /* process dead but no EOF from pty */
  72.  
  73. /* Handy debugging macro */
  74. #if 0
  75. # define DB(x) fprintf x
  76. #else
  77. # define DB(x)
  78. #endif
  79.  
  80. static struct Proc *ProcChain;
  81. static int ProcRunCount;
  82.  
  83. static void
  84. callexitfunc(struct Proc *pr)
  85. {
  86.     if(!NILP(pr->pr_ExitFunc))
  87.     {
  88.     int oldgci = GCinhibit;
  89.     GCinhibit = TRUE;
  90.     calllisp1(pr->pr_ExitFunc, pr);
  91.     GCinhibit = oldgci;
  92.     }
  93. }
  94.  
  95. /*
  96.  * Checks if any of my children are zombies, takes appropriate action.
  97.  */
  98. static void
  99. checkforzombies(void)
  100. {
  101.     int status;
  102.     pid_t pid;
  103.     if(!ProcRunCount)
  104.     return;
  105.     while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)
  106.     {
  107.     struct Proc *pr = ProcChain;
  108. #ifdef DEBUG
  109.     settitlefmt("SIGCHLD: pid %d -- status 0x%x", pid, status);
  110. #endif
  111.     while(pr)
  112.     {
  113.         if((pr->pr_Status > 0) && (pr->pr_Pid == pid))
  114.         break;
  115.         pr = pr->pr_Next;
  116.     }
  117.     if(pr)
  118.     {
  119.         if(WIFSTOPPED(status))
  120.         pr->pr_Status = PR_STOPPED;
  121.         else
  122.         {
  123.         pr->pr_ExitStatus = status;
  124.         ProcRunCount--;
  125. #if 0
  126.         if(pr->pr_Stdout)
  127.             close(pr->pr_Stdout);
  128.         if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  129.             close(pr->pr_Stdin);
  130.         pr->pr_Stdout = pr->pr_Stdin = 0;
  131.         pr->pr_Status = PR_DEAD;
  132. #else
  133.         /* It seems that I can't just nuke the pty once the child's
  134.            dead -- there can be data pending on it still. So, I set
  135.            pr_Status to an in-between value and hope to get an eof
  136.            over pr_Stdin RSN
  137.            Another consideration is what happens if the process I ran
  138.            on the pty forked another process which is still using
  139.            my pty. This means that I don't get an EOF until it
  140.            exits (if it does). hmmm...    */
  141.  
  142.         if(pr->pr_Stdout || pr->pr_Stdin)
  143.             pr->pr_Status = PR_EXITED;
  144.         else
  145.         {
  146.             pr->pr_Status = PR_DEAD;
  147.             callexitfunc(pr);
  148.             pr->pr_File = pr->pr_Argv = sym_nil;
  149.         }
  150. #endif
  151.         }
  152.     }
  153.     }
  154. }
  155.  
  156. /*
  157.  * This semaphorey thing protects all operations done on process structures
  158.  * from SIGCHLD and the process reaping it causes.
  159.  */
  160. static int ProcMutex = -1;
  161. static bool GotSig;
  162. INLINE void
  163. protect_procs(void)
  164. {
  165.     ProcMutex++;
  166. }
  167. void
  168. unprotect_procs(void)
  169. {
  170.     if((ProcMutex == 0) && GotSig)
  171.     {
  172.     /* Have to leave (ProcMutex == 0) while looking for zombies.  */
  173.     GotSig = FALSE;
  174.     checkforzombies();
  175.     }
  176.     ProcMutex--;
  177. }
  178.  
  179. static void
  180. sigchld_handler(int sig)
  181. {
  182.     if(ProcMutex < 0)
  183.     checkforzombies();
  184.     else
  185.     GotSig = TRUE;
  186. #ifndef USE_SIGACTION
  187.     signal(SIGCHLD, sigchld_handler);
  188. #endif
  189. }
  190.  
  191. void
  192. readfromproc(int fd)
  193. {
  194.     struct Proc *pr = ProcChain;
  195.     protect_procs();
  196.     while(pr)
  197.     {
  198.     if((pr->pr_Status != PR_DEAD) && (pr->pr_Stdout == fd))
  199.         break;
  200.     pr = pr->pr_Next;
  201.     }
  202.     if(pr)
  203.     {
  204.     u_char buf[1025];
  205.     int actual;
  206.     cursor(CurrVW, CURS_OFF);
  207.     do {
  208.         if((actual = read(fd, buf, 1024)) > 0)
  209.         {
  210.         buf[actual] = 0;
  211.         streamputs(pr->pr_OutputStream, buf, FALSE);
  212.         }
  213.     } while((actual > 0) || (errno == EINTR));
  214.  
  215.     /* what happens when a child closes the pty slave (or dies)???
  216.        it seems that I get EIO on Linux. This might handle most
  217.        situations (or should I change !EWOULDBLOCK to EIO??)  */
  218.     if((actual <= 0) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
  219.     {
  220.         /* assume eof  */
  221.         FD_CLR(pr->pr_Stdout, &FdReadSet);
  222.         FdReadAction[pr->pr_Stdout] = NULL;
  223.         close(pr->pr_Stdout);
  224.         if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  225.         close(pr->pr_Stdin);
  226.         pr->pr_Stdout = pr->pr_Stdin = 0;
  227.  
  228.         /* This means that the process has already exited and we were
  229.            just waiting for the dregs of its output.  */
  230.         if(pr->pr_Status < 0)
  231.         {
  232.         pr->pr_Status = PR_DEAD;
  233.         callexitfunc(pr);
  234.         pr->pr_File = pr->pr_Argv = sym_nil;
  235.         }
  236.     }
  237.     refreshworld();
  238.     cursor(CurrVW, CURS_ON);
  239.     }
  240.     unprotect_procs();
  241. }
  242.  
  243. int
  244. writetoproc(VALUE pr, u_char *buf)
  245. {
  246.     int act = 0;
  247.     if(!PROCESSP(pr))
  248.     return(0);
  249.     protect_procs();
  250.     if(VPROC(pr)->pr_Status == PR_RUNNING)
  251.     {
  252.     if(VPROC(pr)->pr_Stdin)
  253.     {
  254.         /* This will block. Needs to handle EINTR as well (oh well...)  */
  255.         act = write(VPROC(pr)->pr_Stdin, buf, strlen(buf));
  256.     }
  257.     if(act < 0)
  258.     {
  259.         settitlefmt("Error: %s", VSTR(geterrstring()));
  260.         act = 0;
  261.     }
  262.     }
  263.     else
  264.     cmd_signal(sym_process_error, list_2(pr, MKSTR("Not running")));
  265.     unprotect_procs();
  266.     return(act);
  267. }
  268.  
  269. static bool
  270. signalprocess(struct Proc *pr, int sig)
  271. {
  272.     bool rc = TRUE;
  273.     protect_procs();
  274.     if(pr->pr_Stdin)
  275.     {
  276.     pid_t gid;
  277. #ifdef SIGNALS_VIA_CHARS
  278.     switch(sig)
  279.     {
  280.         struct termios term;
  281.     case SIGINT:
  282.         tcgetattr(pr->pr_Stdin, &term);
  283.         write(pr->pr_Stdin, &term.c_cc[VINTR], 1);
  284.         break;
  285.     case SIGQUIT:
  286.         tcgetattr(pr->pr_Stdin, &term);
  287.         write(pr->pr_Stdin, &term.c_cc[VQUIT], 1);
  288.         break;
  289.     case SIGTSTP:
  290.         /* This doesn't work?? sending SIGSTOP directly does :) */
  291.         tcgetattr(pr->pr_Stdin, &term);
  292.         write(pr->pr_Stdin, &term.c_cc[VSUSP], 1);
  293.         break;
  294.     default:
  295. #endif
  296.         gid = tcgetpgrp(pr->pr_Stdin);
  297.         if(gid != -1)
  298.         killpg(gid, sig);
  299.         else if(pr->pr_Status != PR_DEAD)
  300.         killpg(pr->pr_Pid, sig);
  301.         else
  302.         rc = FALSE;
  303. #ifdef SIGNALS_VIA_CHARS
  304.     }
  305. #endif
  306.     }
  307.     else if(pr->pr_Status != PR_DEAD)
  308.     killpg(pr->pr_Pid, sig);
  309.     else
  310.     rc = FALSE;
  311.     unprotect_procs();
  312.     return(rc);
  313. }
  314.  
  315. /*
  316.  * This is only called during GC, when the process isn't being referenced.
  317.  * it will already have been taken out of the chain
  318.  */
  319. static void
  320. killproc(struct Proc *pr)
  321. {
  322.     protect_procs();
  323.     if(pr->pr_Status != PR_DEAD)
  324.     {
  325.     if(pr->pr_Status == PR_RUNNING)
  326.     {
  327.         /* is this too heavy-handed?? */
  328.         if(!signalprocess(pr, SIGKILL))
  329.         killpg(pr->pr_Pid, SIGKILL);
  330.         waitpid(pr->pr_Pid, &pr->pr_ExitStatus, 0);
  331.         ProcRunCount--;
  332.     }
  333.     if(pr->pr_Stdout)
  334.     {
  335.         FD_CLR(pr->pr_Stdout, &FdReadSet);
  336.         FdReadAction[pr->pr_Stdout] = NULL;
  337.         close(pr->pr_Stdout);
  338.     }
  339.     if(pr->pr_Stdin && (pr->pr_Stdin != pr->pr_Stdout))
  340.         close(pr->pr_Stdin);
  341.     }
  342.     mystrfree(pr);
  343.     unprotect_procs();
  344. }
  345.  
  346. static int
  347. getpty(char *slavenam)
  348. {
  349.     char c;
  350.     int i, master;
  351.     struct stat statb;
  352.     for(c = FIRST_PTY_LETTER; c < 'z'; c++)
  353.     {
  354.     for(i = 0; i < 16; i++)
  355.     {
  356.         sprintf(slavenam, "/dev/pty%c%x", c, i);
  357.         if(stat(slavenam, &statb) < 0)
  358.         goto none;
  359.