Group: comp.os.linux.networking
From: Knight
Date: Monday, March 24, 2008 1:12 AM
Subject: Re: Help: redirecting process input/output

On Mar 22, 6:35=A0am, David Schwartz wrote:
>
> By the way, your code is largely operating by luck. It has a very
> serious, and very subtle, bug that can lead to deadlock.
>
> You cannot assume that it is safe to refuse to read from one
> connection until you finish writing to another. If two processes do
> that, they can wind up each refusing to read until the other reads,
> which is fatal.
>
> You also didn't set the sockets non-blocking, which can also lead to
> deadlock for much the same reason.
>
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (FD_ISSET(c2p[0], &r)=
) {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((cou=
nt =3D read(c2p[0], buf, 1024))
> >> 0) {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 write(1, buf, count);
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (FD_ISSET(0, &r)) {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((cou=
nt =3D read(0, buf, 1024)) > 0)
> > {
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 write(p2c[1], buf, count);
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>
> Notice that you do not perform the second 'read' until the first
> 'write' completes? But your 'write' can only complete if there is
> sufficient space in the pipe, which may require the consuming process
> to 'read' from the pipe. But the consuming process might be blocked in
> 'write' waiting for space in the pipe which will only be made
> available by your second 'read'. So you are each waiting for the
> other.
>
> You must not wait to call the second 'read' until the first 'write'
> completes.
>
> You can get the same deadlock the other way around as well. You could
> be blocked in the first 'write', unable to find buffer space because
> the program you are trying to 'write' to cannot call 'read' until you
> perform the first 'read' on the next pass of your 'select' loop.
>
> Sorry for the bad news.
>
> The simplest fix is just to 'fork' and use one process for each
> direction. Each process blocks in 'read' and then blocks in 'write'.
> The way, one process blocking in 'write' won't keep the other one from
> 'read'ing.
>
> Otherwise, you have to use 'select' for your writes as well, and you
> must set the sockets non-blocking.
>
> DS

Sorry, I didn't understand this bit. The first write (in the parent)
is to file descriptor 1 (tty output) and not to the pipe. Similarly
the second read is from fd 0 (tty input).
I don't think you're saying they will block because of insufficient
space in the pipe, right?

Or is this the scenario you're visualizing: Parent writes to p2c[1]
but blocks due to insufficient space. Child was already blocked on a
write to its 1 (which used to be c2p[1] before all the close()/dup()
stuff). Now neither will advance because neither is reading?

BTW in my situation (embedded system, limited RAM) I think it will be
better to set sockets nonblocking, do select() for writes and reads
both, and retry them; rather than 2 forks.

Safety Articles | Usenet Groups | Usenet News | Bluegrass