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. Do I need to kludge
something together by adding an input source? (A delayed-perform probably won’t
work, because I think those are implemented using timers, which are documented
as not causing -runMode: to exit.)
—Jens
PS: Oh yes, this is 10.6.4, on a 2009-model iMac.
[fig. 1: the backtrace:]
#0 -[KSDownloadAction taskExited:] (self=0x30f440, _cmd=0x29032,
notification=0x403040) at KSDownloadAction.m:323
#1 0x929201c3 in _nsnote_callback ()
#2 0x97fcb3c3 in __CFXNotificationPost ()
#3 0x97fcadca in _CFXNotificationPostNotification ()
#4 0x92915090 in -[NSNotificationCenter postNotificationName:object:userInfo:]
()
#5 0x929aebf5 in __-[NSConcreteTask launchWithDictionary:]_block_invoke_2 ()
#6 0x97ffc861 in __CFRunLoopDoBlocks ()
#7 0x97fad613 in __CFRunLoopRun ()
#8 0x97fac094 in CFRunLoopRunSpecific ()
#9 0x97fabec1 in CFRunLoopRunInMode ()
#10 0x9295a378 in -[NSRunLoop(NSRunLoop) runMode:beforeDate:] ()
#11 0x00011887 in -[KSRegistration updateSynchronously] (self=0x207ac0,
_cmd=0x28b9d) at KSRegistration.m:153
#12 0x00010f40 in main (argc=4, argv=0xbffff66c) at main.m:288
_______________________________________________
Cocoa-dev mailing list ([email protected])
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 [email protected]