For Programmers: Free Programming Magazines  


Home > Archive > Unix Programming > January 2008 > Race condition in detecting child exit and capturing child stdout









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Race condition in detecting child exit and capturing child stdout
Dom Fulton

2008-01-21, 8:19 am

(was: Setting a socket to unbuffered?)

Sorry guys, but I've been though your posts in detail and, unless I'm
being very dumb, I can't see that they address the fundamental problem
here. Of course, I didn't know what the fundamental problem was, so
that didn't help. The problem is:

Is it possible, in a race-free way, *both* to completely capture the
stdout from a child process, *and* to retrieve the exit status from
that child process? Note that the child is completely arbitrary; I
have no access to its source code.

There are two issues. The first is knowing when a child has completed
stdout output; the second is the race condition between getting this
information, and getting the child's exit status.

1 - How do I know when the child has completed stdout anyway?
-------------------------------------------------------------

Barry suggests:

>Whoever is reading from the child (either the parent if you set up a
>pipe, or the client if you use a second socket) will read EOF when the
>child has finished its output and exits.


but, unfortunately, this doesn't work. Not in my test program, anyway
- the client read/recv on the socket just hangs up waiting for the
next byte when the child exits. Maybe if I set the socket to
non-blocking I might be able to get an error status, but I don't think
it's likely.

2 - The race condition
----------------------

Assume that I have some way ('X') of knowing when the child has
completed sending stuff to stdout and stderr. I do have knowledge
('Y') of when the child exits; either 'waitpid' returns, or I get a
signal (I haven't tried the signalling option).

Problem: 'X' (if it exists) and 'Y' do not occur in a defined order.
Nothing else matters until I can sort this out. If the order is
undefined, then I am guaranteed to lose information, whatever I do.

Any ideas? This must be possible - a couple of you have mentioned
applications which do this. Or maybe they're just doing it in the same
cack-handed way that I am (the server sleeps for an arbitrary time
after the waitpid return, to allow any stdout to flush through back to
the client, and it then sends the exit status message back to the
client).

The only way out I can see is to accept that this is impossible and to
have two completely separate channels between the client and server.
One of them would be completely asynchronous and would just dump
output from the child back on the client's console, while the other
one carries the synchronous command/status protocol. However, I really
don't like this - it would be better to have the client actually see
all the output from a given command before the next command is issued
(the client is generally automated).

Thanks -

Dom
Ben Bacarisse

2008-01-21, 8:19 am

Dom Fulton <wes104@yahoo.com> writes:

> (was: Setting a socket to unbuffered?)


I was not reading that thread so I may have missed important stuff.
Ignore me if I am off-beam here.

> 1 - How do I know when the child has completed stdout anyway?
> -------------------------------------------------------------
>
> Barry suggests:
>
>
> but, unfortunately, this doesn't work. Not in my test program, anyway
> - the client read/recv on the socket just hangs up waiting for the
> next byte when the child exits. Maybe if I set the socket to
> non-blocking I might be able to get an error status, but I don't think
> it's likely.


Sounds very odd. Your question is about child processes and stdout so
what is the socket all about?

> 2 - The race condition
> ----------------------
>
> Assume that I have some way ('X') of knowing when the child has
> completed sending stuff to stdout and stderr. I do have knowledge
> ('Y') of when the child exits; either 'waitpid' returns, or I get a
> signal (I haven't tried the signalling option).
>
> Problem: 'X' (if it exists) and 'Y' do not occur in a defined order.


Also sounds odd. When the child exits, you know it has finished
sending stuff.

> Nothing else matters until I can sort this out.


It sounds a little unclear. As I say, just ignore me if this has all
been hashed out and I'm missing the point.

--
Ben.
Dom Fulton

2008-01-21, 8:19 am

On Mon, 21 Jan 2008 13:46:34 +0000, Ben Bacarisse
<ben.usenet@bsb.me.uk> wrote:


>Sounds very odd. Your question is about child processes and stdout so
>what is the socket all about?


Yeah, sorry. It occurred to me afterwards that a lot of context from
the original post was missing. This is a client-server app, where a
client requests that a server run a particular program for the client.
The user at the client needs to see all the output from the app which
is running on the server, and *also* needs to get the exit code from
the app. So, there's a socket (two, currently) connecting the client
and server, and the server forks a new process to deal with exec'ing
the required app. However, I don't think this is really relevant to
the problem; it just so happens that I have to push the child's exit
code, *and* stdout output, down one or more sockets.

>Also sounds odd. When the child exits, you know it has finished
>sending stuff.


sometime after the child exits, you know that it has called exit. The
problem is that any output the child has produced on stdout and/or
stderr may not have turned up by then - that's the synchronisation
problem. As well as the exit call, you also need to know that the last
output from the child is available somewhere. It so happens that the
child's output is connected to a socket, but unfortunately I don't get
an EOF on the socket when the child dies, so I can't detect the "child
has finished output" condition.

Probably not much clearer... :)

- Dom
Alex Fraser

2008-01-21, 7:28 pm

"Dom Fulton" <wes104@yahoo.com> wrote in message
news:kfs8p3hk8iu6250bd2ua9edn64v2lu6tej@
4ax.com...
[snip]
> 1 - How do I know when the child has completed stdout anyway?
> -------------------------------------------------------------
>
> Barry suggests:
>
>
> but, unfortunately, this doesn't work. Not in my test program, anyway
> - the client read/recv on the socket just hangs up waiting for the
> next byte when the child exits.


What Barry wrote is only true if the child has the only descriptor
associated with the socket. My guess is that isn't the case in your test
program.

This implies that you need to establish a new connection for each EXEC
command if you use this method. If that is likely to be a problem, consider
using a pipe or pty and single connection instead.

> 2 - The race condition
> ----------------------
>
> Assume that I have some way ('X') of knowing when the child has
> completed sending stuff to stdout and stderr. I do have knowledge
> ('Y') of when the child exits; either 'waitpid' returns, or I get a
> signal (I haven't tried the signalling option).
>
> Problem: 'X' (if it exists) and 'Y' do not occur in a defined order.
> Nothing else matters until I can sort this out. If the order is
> undefined, then I am guaranteed to lose information, whatever I do.


If using a pipe child->parent, keep reading that pipe until you read EOF. At
that point, you are sure to have captured all the child's output. Normally,
the child will either have already exited or will do soon, so a call to
waitpid() will return quickly.

Alex


Gordon Burditt

2008-01-21, 7:28 pm

>>Whoever is reading from the child (either the parent if you set up a
>
>but, unfortunately, this doesn't work. Not in my test program, anyway


Does the child have the *ONLY* write end of the pipe open?

If you call pipe(), you get two pipe ends, read and write. If you
then fork(), you have 4 pipe ends, two read and two write. You
should close off one read end and one write end. If there's another
write end open, you'll just hang reading the read end after the
child has exited.

>- the client read/recv on the socket just hangs up waiting for the
>next byte when the child exits. Maybe if I set the socket to
>non-blocking I might be able to get an error status, but I don't think
>it's likely.

Barry Margolin

2008-01-21, 7:28 pm

In article <kfs8p3hk8iu6250bd2ua9edn64v2lu6tej@4ax.com>,
Dom Fulton <wes104@yahoo.com> wrote:

> (was: Setting a socket to unbuffered?)
>
> Sorry guys, but I've been though your posts in detail and, unless I'm
> being very dumb, I can't see that they address the fundamental problem
> here. Of course, I didn't know what the fundamental problem was, so
> that didn't help. The problem is:
>
> Is it possible, in a race-free way, *both* to completely capture the
> stdout from a child process, *and* to retrieve the exit status from
> that child process? Note that the child is completely arbitrary; I
> have no access to its source code.
>
> There are two issues. The first is knowing when a child has completed
> stdout output; the second is the race condition between getting this
> information, and getting the child's exit status.
>
> 1 - How do I know when the child has completed stdout anyway?
> -------------------------------------------------------------
>
> Barry suggests:
>
>
> but, unfortunately, this doesn't work. Not in my test program, anyway
> - the client read/recv on the socket just hangs up waiting for the
> next byte when the child exits. Maybe if I set the socket to
> non-blocking I might be able to get an error status, but I don't think
> it's likely.


Sounds like the parent process (the server) isn't closing the stdout
socket after it forks the child. A socket doesn't REALLY close until
all descriptors associated with it are closed.

--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
William Ahern

2008-01-21, 7:28 pm

Dom Fulton <wes104@yahoo.com> wrote:
> On Mon, 21 Jan 2008 13:46:34 +0000, Ben Bacarisse
> <ben.usenet@bsb.me.uk> wrote:
>
[color=darkred]
> Yeah, sorry. It occurred to me afterwards that a lot of context from
> the original post was missing. This is a client-server app, where a
> client requests that a server run a particular program for the client.
> The user at the client needs to see all the output from the app which
> is running on the server, and *also* needs to get the exit code from
> the app. So, there's a socket (two, currently) connecting the client
> and server, and the server forks a new process to deal with exec'ing
> the required app. However, I don't think this is really relevant to
> the problem; it just so happens that I have to push the child's exit
> code, *and* stdout output, down one or more sockets.


So, are you dup'ing the socket(s) to the stdin/stdout of the child? I.e.
fork()+dup()+exec()?

Are you forgetting to close those sockets in the server after the fork()?

[color=darkred]
> sometime after the child exits, you know that it has called exit. The
> problem is that any output the child has produced on stdout and/or
> stderr may not have turned up by then - that's the synchronisation
> problem. As well as the exit call, you also need to know that the last
> output from the child is available somewhere. It so happens that the
> child's output is connected to a socket, but unfortunately I don't get
> an EOF on the socket when the child dies, so I can't detect the "child
> has finished output" condition.


Very likely because the socket has been duplicated, and when the child dies
the socket is still open with a valid descriptor in, for instance, the
parent server process. The behavior you describe betrays a bug.


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com