From: Jonathan P. <jp...@dc...> - 2005-04-15 12:40:44
|
Hi all, Please let me know what the best place for reporting bugs is, if this mailing list isn't appropriate. Following up from my earlier thread "Thread scheduling", I've identified the precise cause of the problems I've been seeing. The fundamental problem is bad interaction with Ruby's manual thread switching (using setjmp/longjmp) and the mechanism used in RubyCocoa to deal with Objective C object ownership. RubyCocoa manages ownership by bracketing every Cocoa invocation with an NSAutoreleasePool. Unfortunately, the NSAutoreleasePool stack is *per-NSThread*. Therefore, if a Ruby thread yields whilst an NSAutoreleasePool is being used, it's possible for another thread to get scheduled which then creates its own pool. This means that the object lifetimes are not what RubyCocoa expects. The same problem exists for the per-NSThread exception handler stack, as outlined in my previous messages. As I see it, this means it is never safe to use any objective c calls from the non-main Ruby thread. Setting rb_thread_critical for the lifetime of each NSAutoreleasePool or exception context should resolve the issue, but means that concurrency is prevented during all Cocoa calls. I shall investigate how this affects the application I'm working on. Another fix, which I have implemented out of interest, is to manually fiddle NSThread's exception and autorelease pool stacks when ruby switches threads. Unfortunately, this requires patching the ruby interpreter to provide the necessary hooks, and also means accessing some private member variables of the NSThread class. Thanks Jonathan |