On Mar 18, 2011, at 11:07 PM, Ken Thomases wrote:

> I would say that your "...IgnoringErrors" methods are masking a real problem, 
> and you shouldn't have written them let alone used them.  (By the way, you 
> didn't post them except incidentally in your screenshot.)

(Ahh yep. I didn't want to spam the group with lots and lots of code and 
headers and other bits. I tried to pick the "relevant" code and then provided 
the link to the sourcefiles on bitbucket...)  

And in answer to this I was grasping at straws and I didn't really write this 
code, I was trying this since it was recommended in some previous posts by 
others (I can post the references if you are interested).  In the end I think 
this @try @catch just served to not crash the app and return nil for the 
result... But you are right I am keenly interested in what is going wrong and 
how to remedy it. (As I said previously the error would manifest itself every 
so often which was of course very annoying, but now moving to the Moriarty 
style of things, the errors suddenly became quite noticeable.)


> The exception is saying that the file descriptor backing the 
> NSPipe/NSFileHandle has been closed.  Retrying after some time can only 
> result in the frameworks co-opting a new, unrelated file object that happened 
> to get the same file descriptor.  That would explain why your reads sometimes 
> never get any data -- you're reading from a completely different file object.

I am sorry, but can you explain the paragraph in more detail? (Just to be clear 
sometimes I never get the exception and yet it still drops data... So the ugly 
bit of the @catch is never hit but it still was dropping the data...)


> I'm not sure why the file descriptor is being closed.  It may be a framework 
> bug having to do with garbage collection.
> 
> I'd try creating the file descriptors manually with the pipe(2) system call.  
> Then, construct NSFileHandles from them with 
> -initWithFileDescriptor:theReadFD closeOnDealloc:NO.

Sorry just so I don't stuff this up can I ask you to give me the exact code 
here... or point me to an example of this?


> (Pass [NSFileHandle fileHandleWithNullDevice] to -setStandardInput:, while 
> you're at it.)  After you launch the task, be sure to close the write ends of 
> your pipes.  And, of course, when everything is finished up, close the read 
> ends, too.

I'd like to try this thanks!


> By the way, there's nothing incorrect about getting the task-terminated 
> notification before the end-of-file for the task output or error file 
> handles.  There's no guarantee about the order of those events.

Yes, I gathered that. I also gathered that you should always get all three 
things right? ie
(i) The NSTaskDidTerminateNotification
(ii) and the NULL for the NSFileHandleReadCompletionNotification for stdOut
(iii) and the NULL for the NSFileHandleReadCompletionNotification for stdErr

Well when it was dropping the data I was missing one of these notifications and 
my empirical observation was that more commonly I was receiving the 
NSTaskDidTerminateNotification first and then either of the other notifications.

Whereas when things were working it was uncommon or I didn't get the 
NSTaskDidTerminateNotification first.... It was just a data point I was trying 
to give everyone so it might shed some light on the problem.


> On Mar 17, 2011, at 4:01 AM, Jason Harris wrote:
> 
>> - (BOOL) waitTillFinished
>> {
>>   // wait for task to exit:
>>   while (![self shouldFinishUp])
>>   {
>>       // If the task is terminated we should set up a pending termination 
>> which will terminate in a bit. This catches some
>>       // zombie NSTasks where either the outputData or errorData of 0 were 
>> never posted..
>>       BOOL terminated = ![task_ isRunning];
>>       if (terminated && !pendingTermination_)
>>       {
>>           DebugLog(@"...Found terminated for %@ ...", [self 
>> commandLineString]);
>>           [self setPendingTermination];
>>       }
>> 
>>       BOOL runLoopRan = [[NSRunLoop currentRunLoop] 
>> runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
>>       if (!runLoopRan)
>>           break;
>>       if (!isFinished_)
>>           DebugLog(@"...waitTillFinished still waiting for %@ ...", [self 
>> commandLineString]);
>>   }
>> 
>>   [self finishUp];
>>   DebugLog(@"...Exiting waitTillFinished for %@ ...", [self 
>> commandLineString]);
>>   return (result_ == 0);
>> }
>> 
>> 
>> + (ExecutionResult*) execute:(NSString*)cmd withArgs:(NSArray*)args 
>> onTask:(NSTask*)task
>> {
>>   ShellTask* shellTask = [[ShellTask alloc] initWithCommand:cmd andArgs:args 
>> onTask:task];
>> 
>>   [shellTask->task_ launch];            // Start the process
>>   DebugLog(@"launched %@", [shellTask commandLineString]);
>> 
>>   [shellTask waitTillFinished];
>> 
>>   DebugLog(@"Finished execute cmd for %@", [shellTask commandLineString]);
>> 
>>   NSString* outStr = [[NSString alloc] initWithData:shellTask->outputData_ 
>> encoding:NSUTF8StringEncoding];
>>   NSString* errStr = [[NSString alloc] initWithData:shellTask->errorData_  
>> encoding:NSUTF8StringEncoding];
>>   ExecutionResult* result = [ExecutionResult resultWithCmd:cmd args:args 
>> result:shellTask->result_ outStr:outStr errStr:errStr];
>>   result->theShellTask_ = shellTask;
>>   return result;
>> }
> 
>> BAD:
>> --------
>> 0x1014810/-[MacHgDocument initializeRepositoryData] Initializing log entry 
>> collection
>> 0x1250100/+[ShellTask execute:withArgs:onTask:]    launched localhg 
>> combinedinfo --cwd /Volumes/QuickSilver/Development/sandbox/RhodeCode
>> 0x1250100/-[ShellTask gotExit:]                    ...got Exit for localhg 
>> combinedinfo --cwd /Volumes/QuickSilver/Development/sandbox/RhodeCode ...
>> 0x1250100/-[ShellTask gotError:]                   ...got NULL Error Output 
>> for localhg combinedinfo --cwd 
>> /Volumes/QuickSilver/Development/sandbox/RhodeCode ...
>> 0x1250100/-[ShellTask waitTillFinished]            ...waitTillFinished still 
>> waiting for localhg combinedinfo --cwd 
>> /Volumes/QuickSilver/Development/sandbox/RhodeCode ...
>> 0x1250100/-[ShellTask finishUp]                    ...Finishing up for 
>> localhg combinedinfo --cwd 
>> /Volumes/QuickSilver/Development/sandbox/RhodeCode ...
> 
>> Now a couple things to note is that if the   [self 
>> performSelector:@selector(finishUp)  withObject:nil  afterDelay:10.0]    
>> fires in the BAD case then the outer call to waitTillFinished just sort of 
>> vanishes, since there is always a DebugLog call which prints "...Exiting 
>> waitTillFinished for ..." but is can be seen in the BAD transcript this just 
>> isn't present.
> 
> I see no evidence that it has "vanished".  It seems to me that 
> -waitTillFinished is still executing, presumably blocked in the run loop.  
> Note that, not only is the DebugLog at the end of -waitTillFinished not hit, 
> but neither is the one immediately after the call to it in 
> +execute:withArgs:onTask:.  In other words, it just hasn't returned.

Ahh so you are saying that the loop is still executing? Well if I put a break 
point in the loop in waitTillFinished then it doesn't break on this 
breakpoint... Maybe this is an XCode bug or something? Also I would imagine 
though if this were the case then stepping up through the call stack would have 
been normal. Ie would have got back to the loop. Instead it was like I hit 
continue when I reached __CFRunLoopRun...

Thanks for the comments though!

Cheers,
  Jas_______________________________________________

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