How do I recover my pipe on my Parent's Death?

der Mouse mouse at thunder.mcrcim.mcgill.edu
Fri May 24 21:27:34 AEST 1991


In article <1991May21.213431.2193 at odetics.com>, frank at odetics.com (Frank Merrow) writes:

> I am attempting to monitor a number of file descriptors for input
> using select().  Below I have included a piece of my code.  Actually
> things work pretty good, EXCEPT for some reason when one of the
> processes (my parent in this case) dies.

> At any rate once the parent dies, select() immediately releases, but
> the ioctl() shows "nothing" in the pipe so I go back to the select()
> which immediately releases and so on.  What do I need to do to
> detect/clear the condition.
(Questions generally end with `?', not `.'.)

select() for input returns when a read() call will not block.  This is
not always the same as returning when there is something to read.  In
your case, you've reached EOF on the pipe; if you call read() you'll
see that it returns 0.  Naturally FIONREAD returns 0, because there's
nothing there.

As for detecting it, you already have: select() indicates that it's
ready for input, but there's nothing there.  To clear it, you can't;
that pipe is forever going to show EOF.  You can't do much with it but
close it.

> for (keep_going=TRUE;keep_going;)
>    {
>    if (select(numfds,&readfds,NULL,NULL,NULL) < 1)
>       fatal("select() error in main(xfs)");
>    PRINT_TRACE("select() released");
>    for (i=0;i < num_fd_list;i++)
>       {
>       if (ioctl(fd_list[i].fd,FIONREAD,&nbytes) != 0)
> 	 fatal("ioctl() error in main(xfs)");
>       if (nbytes > 0)
> 	 (*fd_list[i].routine) (i);
>       }
>    }

I note three problems with this code immediately.

1) The descriptor masks will normally be changed by select(), so you
   should reconstruct readfds each time around the loop.

2) The last three arguments to select() are pointers; unless you don't
   care about portability to non-prototype-capable compilers, you
   should pass pointers.

3) You should *use* the descriptor mask returned by select.  RTFM; when
   select returns the descriptor mask has been modified so that only
   those bits corresponding to ready-to-read file descriptors are set.

A sketch of what it might look like after these changes, assuming
numfds is correctly set (ie, is larger than all file descriptors in the
fd_list array):

for (keep_going=TRUE;keep_going;)
   {
   FD_ZERO(&readfds);
   for (i=0;i<num_fd_list;i++)
      FD_SET(fd_list[i].fd,&readfds);
   if (select(numfds,&readfds,(fd_set *)NULL,(fd_set *)NULL,(struct timeval *)NULL) < 1)
      fatal("select() error in main(xfs)");
   PRINT_TRACE("select() released");
   for (i=0;i < num_fd_list;i++)
      {
      if (FD_ISSET(fd_list[i].fd,&readfds))
	 (*fd_list[i].routine) (i);
      }
   }

If your system is so old that it doesn't have the FD_ZERO, FD_SET, etc,
macros, you can use an include file I wrote for just such systems:

#ifndef FD_SETSIZE

/* We presumably have a system without the 4.3 fd_set stuff.
   This includes older Sun releases which have a typedef for fd_set but
   none of the associated baggage like FD_SET, FD_CLR, etc. */

#define fd_set fixed_fd_set
typedef struct {
	  int fds[1];
	  } fixed_fd_set;
#define FD_SETSIZE (8*sizeof(int)) /* at least */
#define FD_SET(fd,set) ((set)->fds[0]|=(1<<(fd)))
#define FD_CLR(fd,set) ((set)->fds[0]&=~(1<<(fd)))
#define FD_ISSET(fd,set) ((set)->fds[0]&(1<<(fd)))
#define FD_ZERO(set) ((set)->fds[0]=0)

#endif

This include file is slightly nonportable (it passes a pointer to a
structure instead of a pointer to int), but I believe all systems that
run systems with select(), but without the correct macros, will accept
it and run just fine.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse at larry.mcrcim.mcgill.edu



More information about the Comp.unix.questions mailing list