[comp.windows.x] "-e" option of xterm and immortal processes

battle@alphard.cs.utk.edu (David Battle) (01/03/90)

I like to run an instance of "top" in a window of its own started from my
".xsession" file and using the "-e" option of xterm.  The problem is that
when I log out, the window goes away, but the "top" keeps running, spewing
output to whatever pseudo-tty the window was attached to.  I am currently
killing it by grep'ing through the output of "ps" and killing processes whose
command strings begin with "top".  Is there a better way to do this?

					David L. Battle
					battle@battle.esd.ornl.gov
					battle@utkux1.utk.edu
					battle@utkvx2.BITNET

casey@gauss.llnl.gov (Casey Leedom) (01/03/90)

| From: battle@alphard.cs.utk.edu (David Battle)
| 
| I like to run an instance of "top" in a window of its own started from my
| ".xsession" file and using the "-e" option of xterm.  The problem is that
| when I log out, the window goes away, but the "top" keeps running, spewing
| output to whatever pseudo-tty the window was attached to.  I am currently
| killing it by grep'ing through the output of "ps" and killing processes
| whose command strings begin with "top".  Is there a better way to do this?

  Actually, I think it tries but is getting EIO errors since there's no
process on the master side of the pseudo tty.  I know that it gets EIO
errors when it tries to read from the slave side of the pseudo tty.
However, when I started up a second xterm, it started getting some of the
output of the rogue top process.  (After checking the xterm sources I see
that it only uses vhangup(2) to ensure a ``clean'' tty on SYSV systems.
Is there any reason for this?  Why isn't vhangup(2) being used on BSD
systems?  Is this a ``fixed in R4'' bug?)

  When xterm exits, it does two fundamental things to notify processes
using the window pseudo tty: 1. it sends a SIGHUP to the process group
named by the PID of the original xterm child process started up under the
window and 2. it closes its [master] end of the pseudo tty.  If the
process(es) are set up to deal the effects with either or both actions,
then things should be cleaned up fairly nicely.  In particular, if the
xterm child process is a shell, it's the responsibility of the shell to
pass the SIGHUP on to the shell's child processes that are using the
pseudo tty.  (This propagation isn't done typically for shell descendents
which are running in the background, but as noted above, subsequent xterms
which end up using the pseudo tty and don't perform a vhangup will end up
getting any output those shell descendents end up generating.  For
further problems and limitations of vhangup, see the vhangup(2) manual
page.)

  As it turns out, top, vi and several other programs, don't deal with
either SIGHUPS or EIOs generated from trying to access a pseudo tty whose
master end has been closed.  Patching top to deal with either fixes the
problem you have described.  Following is a patch for top that addresses
both.  My sources say that I have version 2.5 of top.

*** top.c-dist	Mon Jan  9 20:03:47 1989
--- top.c	Tue Jan  2 14:41:28 1990
***************
*** 270,275 ****
--- 270,276 ----
      char ch;
      char *iptr;
      char no_command = 1;
+     int ioerr;
      int readfds;
      struct timeval timeout;
      static char command_chars[] = "\f qh?en#sdkr";
***************
*** 572,577 ****
--- 573,579 ----
      old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP));
  #endif
      init_screen();
+     (void) signal(SIGHUP, leave);
      (void) signal(SIGINT, leave);
      (void) signal(SIGQUIT, leave);
      (void) signal(SIGTSTP, tstop);
***************
*** 831,837 ****
  		timeout.tv_usec = 0;
  
  		/* wait for either input or the end of the delay period */
! 		if (select(32, &readfds, (int *)NULL, (int *)NULL, &timeout) > 0)
  		{
  		    int newval;
  		    char *errmsg;
--- 833,842 ----
  		timeout.tv_usec = 0;
  
  		/* wait for either input or the end of the delay period */
! 		ioerr = select(32, &readfds, (int *)NULL, (int *)NULL, &timeout);
! 		if (ioerr < 0)
! 		    quit(EIO);
! 		if (ioerr > 0)
  		{
  		    int newval;
  		    char *errmsg;
***************
*** 841,847 ****
  
  		    /* now read it and convert to command index */
  		    /* (use "change" as a temporary to hold index) */
! 		    (void) read(0, &ch, 1);
  		    if ((iptr = index(command_chars, ch)) == NULL)
  		    {
  			/* illegal command */
--- 846,853 ----
  
  		    /* now read it and convert to command index */
  		    /* (use "change" as a temporary to hold index) */
! 		    if (read(0, &ch, 1) <= 0)
! 			quit(EIO);
  		    if ((iptr = index(command_chars, ch)) == NULL)
  		    {
  			/* illegal command */
***************
*** 892,898 ****
  				show_help();
  				standout("Hit any key to continue: ");
  				fflush(stdout);
! 				(void) read(0, &ch, 1);
  				break;
  	
  			    case CMD_errors:	/* show errors */
--- 898,905 ----
  				show_help();
  				standout("Hit any key to continue: ");
  				fflush(stdout);
! 				if (read(0, &ch, 1) <= 0)
! 				    quit(EIO);
  				break;
  	
  			    case CMD_errors:	/* show errors */
***************
*** 910,916 ****
  				    show_errors();
  				    standout("Hit any key to continue: ");
  				    fflush(stdout);
! 				    (void) read(0, &ch, 1);
  				}
  				break;
  	
--- 917,924 ----
  				    show_errors();
  				    standout("Hit any key to continue: ");
  				    fflush(stdout);
! 				    if (read(0, &ch, 1) <= 0)
! 					quit(EIO);
  				}
  				break;
  	

*** display.c-dist	Sat Jun 10 13:43:59 1989
--- display.c	Tue Jan  2 14:19:17 1990
***************
*** 826,837 ****
      register char ch;
      register char cnt = 0;
      register char maxcnt = 0;
  
      /* allow room for null terminator */
      size -= 1;
  
      /* read loop */
!     while ((fflush(stdout), read(0, ptr, 1) > 0))
      {
  	/* newline means we are done */
  	if ((ch = *ptr) == '\n')
--- 826,838 ----
      register char ch;
      register char cnt = 0;
      register char maxcnt = 0;
+     int ioerr;
  
      /* allow room for null terminator */
      size -= 1;
  
      /* read loop */
!     while ((fflush(stdout), (ioerr = read(0, ptr, 1)) > 0))
      {
  	/* newline means we are done */
  	if ((ch = *ptr) == '\n')
***************
*** 887,892 ****
--- 888,896 ----
  	    }
  	}
      }
+ 
+     if (ioerr < 0)
+ 	quit(EIO);
  
      /* all done -- null terminate the string */
      *ptr = '\0';