Re: How does one effect O_NONBLOCK?!



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
.



Relevant Pages

  • Re: continuous write to hard disk
    ... | herd" problem and the only cause for scheduling latency with the O ... Parent sets up some shared memory. ... Parent sets up pipes and forks child B. ... Child B blocks in readon pipe for message from parent. ...
    (comp.os.linux.development.system)
  • Re: Python, Tkinter and popen problem
    ... but that is not `both way': popen connects the parent to the child ... The pipe works one way: from the child to the parent ... A child process always inherits stdin, stdout and stderr from the parent ...
    (comp.lang.python)
  • Re: Forking
    ... On Wednesday 03 March 2004 20:47, Price, Jason generously enriched virtual ... pipe takes two filehandles: ... inherit filehandles of the parent process as a copy. ... waits for the child to teminate and returns its pid once it died. ...
    (perl.beginners)
  • Re: Questions about perl daemons with child processes and open files / signals
    ... but not when used in the parent? ... process the pipe in the child process. ... The parent sits in the waitpid, waiting for the child to exit. ...
    (comp.lang.perl.misc)
  • pipe from child to parent: the parent exits, but the child does not
    ... Each child writes then the 3 fetched int values ... via the pipe to the parent. ... So I have prepared a simple test case program, which forks NKIDS ...
    (comp.unix.programmer)