Re: NSRunLoop's -runMode:beforeDate: not exiting after an NSTask finishes
Re: NSRunLoop's -runMode:beforeDate: not exiting after an NSTask finishes
- Subject: Re: NSRunLoop's -runMode:beforeDate: not exiting after an NSTask finishes
- From: Jean-Daniel Dupas <email@hidden>
- Date: Thu, 5 Aug 2010 19:29:56 +0200
Le 5 août 2010 à 19:10, Jens Alfke a écrit :
> I’ve got a place in my code where I need to block waiting for an otherwise-asynchronous action to complete, so I use a fairly standard technique of running a nested runloop. But sometimes the runloop just keeps waiting forever even after the action’s completed, so my app locks up.
>
> The wait code looks like:
> while (_busy) {
> if (![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]])
> break;
> }
>
> where _busy is an instance variable that will be set to NO by a notification observer method when the async action notifies me that it’s complete.
>
> What I see happening when the bug strikes is that the underlying async code completes (it gets a notification from an NSTask it started), but the runloop keeps going forever, without returning from my above -runMode: call. This doesn’t jibe with my understanding of -runMode: — the docs say it returns after an input source is processed.
>
> Here [fig. 1] is the backtrace from gdb at the moment the NSTask notification is received. The runloop is inside a function “__CFRunLoopDoBlocks”, which in turn calls a block belonging to NSConcreteTask. Presumably this is some implementation detail of NSTask, that it uses a block to delay the actual launch.
>
> What I’m guessing is that running a delayed block does not count as an “input source”. That’s kind of frustrating, because it makes the runloop’s behavior highly dependent on internal details of framework classes — in this case, how was I to know that NSTask used a block and not an input source to handle this? And presumably that means the behavior has changed in 10.6, which would explain some weird NSTask related problems I’ve seen over the past year.
> Anyway. How the heck do I work around this? It seems that I need some kind of call that will give the runloop a swift kick and get it to exit the runMode: method. But I don’t see any explicit API for that.
CFRunLoopWakeUp([[NSRunLoop currentRunLoop ] getCFRunLoop])
and if it is not enough:
CFRunLoopStop([[NSRunLoop currentRunLoop ] getCFRunLoop])
If you want a greater control about how the runloop behave, just use the CFRunLoop API in your wait loop (especially CFRunLoopRunInMode() which is roughly equivalent to runMode:beforeDate: but return a status instead of a boolean).
-- Jean-Daniel
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden