I'm having trouble dealing with passing data through a child filter
process. My app is sending info to a socket, with an optional filter
sub process. The write routine either just passes output through to
the socket write or writes it down the pipe to the child and reads the
data from the child and writes it on to the socket.
output ----------------------------> socket
output ---------+ +----------> socket
In the child filter case, the child is fork/exec'd with two pipes
created for the child's stdin & stdout. All the appropriate dup2()
"plumbing" is performed to redirect the child's stdin & stdout back
to the parent. (Thanks to the FAQ and posts in this group!)
Because there is no guaranteed relationship between data to the
filter and data from it, deadlock is possible if the child blocks
with a large amount of output that the parent hasn't read and the
parent blocks on a write to the child's input pipe. I _thought_ I
had taken care of this by having the parent use select() on the
child's fds so as only to read from or write to the child when
possible. Writes are limited to PIPE_BUF bytes.
But on an HP-UX A.09.05 A 9000/712 system, I seem to be getting
into this deadlock, despite the use of select(). Debug code
shows the I get FD_ISSET on the input fd to the child, but suspend
on the write. I'm only writing 448 bytes at a time here, well
under PIPE_BUF, which is 8192 on this system (and under the Posix
512 to boot.) Am I missing something here?? I thought that if
I only write to a pipe when select() indicates writable and keep
the writes under PIPE_BUF, I would not block on the write... This
seems to work fine on our other systems.
I replaced the called filter with a wrapper script:
tee /tmp/fin | real_filter_command 2>>/tmp/ferror | tee /tmp/fout
and found that that /tmp/fin is always 8192 bytes (hmm, PIPE_BUF!)
long and /tmp/fout is usually 8192 also, although sometimes we get
a few k read back from the child before*. (The filter is a
3rd party conversion utility which writes a quite large preamble
out before it starts its processing of the input data.
Perhaps I've done Something Idiotic (TM) here, but sure seems like
select() just lied to me.