Re: How does one effect O_NONBLOCK?!
- From: Edd <edd@xxxxxxxxxxxxxxxx>
- Date: Sun, 1 Jun 2008 14:41:32 -0700 (PDT)
On Jun 1, 10:13 pm, j...@xxxxxxxxxxx (Jens Thoms Toerring) wrote:
Edd <e...@xxxxxxxxxxxxxxxx> wrote:
I'm trying to create a wrapper around fork/execve to run an external
process and interact with its standard streams through pipes.
My method: once I've created 3 pipes (for stdout, stderr and stdin)
and forked(), I close() the unneeded ends of the pipes in both the
child and parent processes and then dup2() the 3 descriptors into the
corresponding ends of the pipes in the child before execve()-ing.
In the parent I set up a loop in which select() is called to deal with
the 3 pipes "simultaneously".
I can read stuff that the child is writing to its stdout and stderr
fine, but I'm having trouble detecting when I should pump stuff down
the stdin pipe.
The following is a sketch of my select()-loop, showing stdin related
stuff only:
If I understand it correctly with "stdin stuff" you mean the write
end side of the pipe that's connected to stdin of the child process.
Correct?
Yes, exactly.
fd_set s;
FD_ZERO(&s); FD_SET(fd, &s); /* fd is the write end of the stdin
pipe */
while (select(fd + 1, NULL, &s, NULL, NULL) > 0)
{
if (FD_ISSET(fd, &s))
{
/*
code to read from parent stdin and pump it to the child
...
*/
}
/*
Some other checks, eventually leading to a break statement
...
*/
FD_ZERO(&s); FD_SET(fd, &s);
}
The FD_ISSET() check inside the loop yields a positive result each
time, rather than when the child is asking for input.
As long as the child hasn't closed its stdin and there is still
room in the pipe you can write without blocking, so select()
returns true for that file descriptor. If you want to know the
exact moment the child is doing a blocking read() (if it does
that at all, see below) then I guess there's no way to do that.
Ah, for some reason, this is what I was expecting select() to do.
I have no idea what the child does, but it also might call
select(), waiting for input from the parent to become ready
for reading. In that case it would never even call read()
until you already have written something to it's stdin.
So I am a bit confused what exactly you want to achieve. Is
it really a problem if you send something to the child and it
isn't blocked in calling read()?
No, it's no problem. I was under the impression that I would be told
by select() when to start sending. But as you've explained, that's not
going to happen.
I keep seeing
the term "non-blocking" mentioned in relation to this, but I'm unsure
how to set this up. O_NONBLOCK and fcntl() are somewhere in the mix, I
believe. I'm going cross-eyed reading man-pages and Googling!
Hopefully somebody can put me out of my misery with a little bit of
example code or something? :)
I don't think setting file descriptors in the parent to non-
blocking would help at all. You call select() before you try
to read or write, so neither read() or write() will block.
Thus setting the file descriptors non-blocking doesn't make
much sense IMHO.
I see that now, thanks.
As far as I can see there might be a rather different problem
that's going to bother you. Since you obviously intend to run
arbitrary programs as the child process you may find that
a lot of them won't react as you may assume. By redirecting
the stdout of the child to a pipe and if it uses the normal
C standard output functions (printf() etc. or their C++ equi-
valents) their output will not appear in a line-by-line
fashion anymore like it happens when you run a program from a
terminal but instead the output will come in in large chunks.
That's because the output functions normally do buffering,
storing a line-length of output when writing to a terminal
but using the whole available buffer when writing to a file.
And a pipe looks like a file and not like a terminal. So you
may have to use a pseudo-terminal between the parent and the
child process in order to make the child process believe it's
writing to a terminal and not a file...
I see. But what negative effects could this have? For a child process
that doesn't explicitly an regularly flush its output, I should expect
data to be sent through in larger chunks. But the output buffer size
isn't something that's typically considered when writing a "console
application", so should this matter?
I can see that it would perhaps be the case that the data written to
the child's stdout and stderr might appear in the parent interleaved
in a different way than it was originally sent. Would pseudo-terminals
help with this particular issue?
Thanks for your patient comments. They have been very enlightening.
Kind regards,
Edd
.
- Follow-Ups:
- Re: How does one effect O_NONBLOCK?!
- From: Jens Thoms Toerring
- Re: How does one effect O_NONBLOCK?!
- From: Jens Thoms Toerring
- Re: How does one effect O_NONBLOCK?!
- References:
- How does one effect O_NONBLOCK?!
- From: Edd
- Re: How does one effect O_NONBLOCK?!
- From: Jens Thoms Toerring
- How does one effect O_NONBLOCK?!
- Prev by Date: Re: How does one effect O_NONBLOCK?!
- Next by Date: Re: How does one effect O_NONBLOCK?!
- Previous by thread: Re: How does one effect O_NONBLOCK?!
- Next by thread: Re: How does one effect O_NONBLOCK?!
- Index(es):
Relevant Pages
|