On Sun, Jul 24, 2011 at 10:17 PM, Scott Ribe
<scott_r...@elevated-dev.com> wrote:
> I'm using NSTask to run a background process, monitor its output, and 
> ultimately present a message to the user. All has been fine with this 10.2 
> through 10.6, as far as I know. Now under 10.7 I saw a case where my code did 
> not receive quite all the stdout output from the background process. I saw 
> this once; I haven't tried running it a huge number of times, but it is 
> definitely not the common case. (And I've never seen it in dev mode running 
> under the debugger, only on a machine without dev tools. Also BTW, the output 
> of the bg process is plain ASCII, no worries about multi-byte sequences.) 
> Does anybody see anything wrong with this code (severely stripped for 
> legibility):

Interesting. THIS IS JUST ME SPECULATING OUT LOUD. I wonder if they've
changed how the readInBackgroundAndNotify works. In particular, my
guess here would be that:

1) Two "threads" are created to handle the stdout and stderr (may be
dispatch queues, but let's say threads for this thought experiment).

2) Your task generates output in stdout, and most of it gets consumed.

3) Your task generates its last data and closes its stderr then stdout.

4) The stdout thread reads the last data and readies a notification,
but doesn't get a chance to post it before being swapped.

5) The stderr thread sees a closed socket and posts a notification
before being swapped.

6) The stdout thread wakes up, and posts its notification.

Now you are in a situation where there are two notifications being
delivered, and their order is wrong for your code. Namely, when the
stderr notification arrives first you will do this:

a) see that stderr is closed.
b) try to read all the remaining data from stdout. There is none,
because it has been queued already.
c) remove yourself as a listener for stdout.
d) try to read all the remaining data from stderr.
e) remove yourself as a listener for stderr.

The problem is step (c)! There might be data in the notification queue
that you will never receive.

Here's how I'd write your methods:

> - (void) doSomeTask: (NSTask *) task

Same.

> - (void) processStdOut: (NSNotification *) ntc
> {
>        NSFileHandle *f = [ntc object];
>        NSData *d = [[ntc userInfo] objectForKey: 
> NSFileHandleNotificationDataItem];
>
>        if( [d length] == 0 )
{
        [[NSNotificationCenter defaultCenter]
                removeObserver: self
                name: NSFileHandleReadCompletionNotification
                object: curStdOut];

        curStdOut = nil;
}
>        else
>        {
>                [f readInBackgroundAndNotify];
>                [curStdOutStr appendString:
>                        [[[NSString alloc] initWithData: d encoding: 
> NSASCIIStringEncoding] autorelease]];
>        }
> }
>
>
> - (void) processStdErr: (NSNotification *) ntc
> {
>        NSFileHandle *f = [ntc object];
>        NSData *d = [[ntc userInfo] objectForKey: 
> NSFileHandleNotificationDataItem];
>
>        if( [d length] == 0 )
{
        [[NSNotificationCenter defaultCenter]
                removeObserver: self
                name: NSFileHandleReadCompletionNotification
                object: curStdErr];

        curStdErr = nil;
}
>        else
>        {
>                [f readInBackgroundAndNotify];
>                [curStdErrStr appendString:
>                        [[[NSString alloc] initWithData: d encoding: 
> NSASCIIStringEncoding] autorelease]];
>        }
> }

That is, abandon processPipeClose and let each pipe handle its own
close in the notification when you're sure all of its read
notifications have actually been delivered. As you've presented it,
processPipeClose isn't needed.
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to