xcodemultithreadingnsrunloopnsfilehandlenspipe

NSFileHandle behaving strangely when run without debugger - some NSRunLoop issue?


I'm writing a plugin for Adobe Premiere on Mac, which opens an external application and then uses NSPipe and NSFileHandle to read the standard output from the external application. I know the recommended ways to do this involve either using NSNotificationCenter along with NSFileHandle's read​In​Background​And​Notify command, or to use NSFilehandle's setReadabilityHandler method to read the output a line at a time as it arrives:

NSTask appTask... // my task which is launching the external app
NSPipe* myPipe = [[NSPipe alloc] init];
[appTask setStandardOutput:[myPipe fileHandleForReading]];
[[myPipe fileHandleForWriting] setReadabilityHandler:^(NSFileHandle *file) {
    NSData* dataRead = [file availableData];
    if (dataRead != nil) {
        printf("Read a line\n");
    }
}];

This works fine and well when I launch Premiere from Xcode with the debugger attached. However, when I run Premiere on its own, the block (or notification if I'm using that method) doesn't get called when the external app puts a line in its standard output. I assume there's some weird way that when its run through Xcode the thread its running on has a run loop that is somehow not active when the plugin is launched from Premiere running on its own.

One way I could solve this would be to just have a loop that checked a few times each second whether there was something to be read from the pipe's NSFileHandle running in a background thread. However, I can find NO WAY to check if there's something to be read from an NSFileHandle without just blocking until there's something ready (which blocking just stays blocked for some reason even when there is something ready, when not launched via Xcode).

So I'm hoping for one of two solutions: 1) Some way to correct whatever is wrong with the NSRunLoop that the notifications/callback block aren't getting triggered when there's something ready in the pipe's NSFileHandle. or 2) Some way to check if there's something ready to be read in the pipe's NSFileHandle without it just blocking until something is ready to be read.

Thanks for any help!!!!


Solution

  • Well, looks like the actual problem was that, when launching everything from within Xcode, my external app would immediately flush the stdout buffer when I printed to stdout, but when launching things without Xcode I needed to add the following line to flush it manually:

    fflush(stdout);

    So the problem was with that, not with the code in my plugin not properly waiting for and reading from the pipe!