Re: Getting last data from child process in Leopard
Re: Getting last data from child process in Leopard
- Subject: Re: Getting last data from child process in Leopard
- From: "Jordan K. Hubbard" <email@hidden>
- Date: Tue, 25 Mar 2008 19:03:20 -0700
On Mar 25, 2008, at 6:39 PM, Steve Checkoway wrote:
Jordan K. Hubbard wrote:
Your signal handler ("deadbeef") also should not be attempting to
read from the pty since there are a lot of operations not
considered safe from signal handlers (your results are guaranteed
to be "undefined", if not outright incorrect).
According to the man page for sigaction(2), read(2) is one of the
base interfaces that is "either reentrant or not interruptible by
signals and are async-signal safe [and therefore] applications may
invoke them, without restriction, from signal-catching functions.
I chose my words fairly carefully in saying "there are a lot of
operations not considered safe" and I didn't call read(2) specifically
unsafe since, technically, it is. However, there's a difference
between the letter of the law and best practices, and best practices
have always been to do as little as humanly possible from a signal
handler (setting a flag, for example). Given that, I'll always
recommend that people not try to be clever in their signal handlers,
particularly where file I/O is concerned given that even with async
safety in the calls, it's impossible to know _when_ the file operation
will take place and races abound.
Programmers are rarely as clever as they think they are, so it's
better to advise them to stay away from the fringes of what is
possible, but unwise, to do with the Unix APIs.
The right thing to do is check for EAGAIN in your read() loop and
go back and retry for the data in that case. Given that you're
using O_NONBLOCK, it's even more important to make sure you handle
all the async event cases.
Do you mean EINTR? "If a signal is caught during the systems calls
listed below [including read(2)], the call may be forced to
terminate with the error EINTR, the call may return with a data
transfer shorter than requested, or the call may be restarted."
Nope, I do mean EAGAIN. In the context of non-blocking I/O, it's
precisely what he needs to check for in this case, at least on MacOSX
(other Unix variants may return EINTR instead - this is one of the
grey areas of Unix behavior). If you try his example checking for
EINTR on Leopard, at least, you'll still fail to catch that last
"BYE" (try it).
I didn't manage to get the signal to interrupt the read(), but
that's probably because of the nonblocking IO. I'm not sure why you
think you need unbuffered IO to avoid deadlocks or to deliver data
quickly. As you probably noticed, printf() on the child side was
buffering anyway.
Try shortening the sleep(2) intervals. You can get the race condition
to happen fairly easily - I didn't express that change in my diffs
since I didn't think it was relevant to the advice I was trying to
give him...
- Jordan
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden