http://bugzilla.novell.com/show_bug.cgi?id=537764
http://bugzilla.novell.com/show_bug.cgi?id=537764#c21 Laurent Etiemble <[email protected]> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #320558|0 |1 is obsolete| | Attachment #320559|0 |1 is obsolete| | Attachment #330599|0 |1 is obsolete| | --- Comment #21 from Laurent Etiemble <[email protected]> 2009-12-07 21:47:55 UTC --- Created an attachment (id=331453) --> (http://bugzilla.novell.com/attachment.cgi?id=331453) Patch for proper foreign thread lifecycle tracking I have made some research to track down what was going during thread cleanup on Mac OS X (10.4 to 10.6). It appears that TSD are widely used by many libraries and frameworks to track the thread lifecycle. Here the analysis: *) Mac OS X 10.4.11: TSD are dynamically assigned to all callers of "pthread_key_create". When the TSD are cleanup, PTHREAD_DESTRUCTOR_ITERATIONS iterations are made on all the TSD. As long as a TSD is non-null, its destructor function is called. A destructor functions can be called up to PTHREAD_DESTRUCTOR_ITERATIONS times. All the TSD cleanup occur in the same loop. http://www.opensource.apple.com/source/Libc/Libc-391.5.22/pthreads/pthread_tsd.c *) Mac OS X 10.5.8: Apple has introduced non-portable extension to TSD management. The non-portable extensions brings the ability for libraries and framework to have fixed thread key values, requesting them through the "pthread_key_init_np" function. Two ranges exists: one for dynamic requested keys with "pthread_key_create" function, and one for static keys dedicated to libraries and frameworks. When the TSD are cleanup, PTHREAD_DESTRUCTOR_ITERATIONS iterations are made on all the thread keys, both dynamic and static ones. As long as a TSD is non-null, its destructor function is called. A destructor functions can be called up to PTHREAD_DESTRUCTOR_ITERATIONS times. All the TSD cleanup occur in the same loop. http://www.opensource.apple.com/source/Libc/Libc-498.1.7/pthreads/pthread_machdep.h http://www.opensource.apple.com/source/Libc/Libc-498.1.7/pthreads/pthread_tsd.c In Mono, the "deregister_foreign_thread" function maybe called before or after the thread exit notification poster of Cocoa. In the worst case scenario, "deregister_foreign_thread" function is called twice, but the GC is left in a consistent state. *) Mac OS X 10.6.2: Apple has extended the concept of static keys, as new libraries and frameworks used them (libdispatch for example). One major change come to the cleanup. When the TSD are cleanup, first PTHREAD_DESTRUCTOR_ITERATIONS iterations are made on the dynamic keys (obtained with "pthread_key_create" function). As long as a TSD is non-null, its destructor function is called. A destructor functions can be called up to PTHREAD_DESTRUCTOR_ITERATIONS times. Then PTHREAD_DESTRUCTOR_ITERATIONS iterations are made on the static keys (declared with "pthread_key_init_np" function). As long as a TSD is non-null, its destructor function is called. A destructor functions can be called up to PTHREAD_DESTRUCTOR_ITERATIONS times. http://www.opensource.apple.com/source/Libc/Libc-583/pthreads/pthread_machdep.h http://www.opensource.apple.com/source/Libc/Libc-583/pthreads/pthread_tsd.c In Mono, "deregister_foreign_thread" function is bound to a dynmiac key whereas the thread exit notification poster of Cocoa is bound to a static key. That means that the foreign thread is deregistered in the first cleanup pass. But when the notification occurs (in the second pass), there is no way to call Mono cleanup again as the dynamic keys have been discarded before the cleanup of the static keys. *) A workaround A solution is to use the non-portable TSD extensions of Apple when dealing with foreign thread. This way, the "deregister_foreign_thread" function is called within the same loop used by Objective-C runtime for its notification. This implies to use non-portable function and a statically assigned thread key. There are two important points: - the non-portable function "pthread_key_init_np" is only available starting with Mac OS X 10.5. As Mono must run on Mac OS X 10.4, this leads to a symbol lookup to detect the support of the function. - the static key must be chosen in a way that does not conflict with other ones. Currently, 768 slots are created for TSD. Static keys go from 0 to 255, the range 30 to 255 is reserved for non-libSystem use. Dynamic keys go from 256 to 512. Static key range from 30 to 90 is already assigned. A good pick is to use the value 255, as it is the higher limit of static key reserved for non-libSystem use. Maybe an official reservation is needed like the libdispatch project has done it. The implementation is therefore straightforward: -> On Mac OS X 10.4: We use dymanic TSD as usual (because "pthread_key_init_np" is not available). During the cleanup, we wait until the PTHREAD_DESTRUCTOR_ITERATIONS calls to "deregister_foreign_thread" before removing GC_thread instance by re-setting the TSD value each time. This assure that the GC_Thread instance is there even during the notification posting. -> On Mac OS X 10.5/10.6 We use static TSD. This only change the value of the thread_key used when calling pthread_setspecific. During the cleanup, we wait until the PTHREAD_DESTRUCTOR_ITERATIONS calls to "deregister_foreign_thread" before removing GC_thread instance by re-setting the TSD value each time. This assure that the GC_Thread instance is there even during the notification posting. This way of dealing with the foreign threads lifecycle ensures that thread are properly tracked from their first native/managed invocation until their full clean-up. -- Configure bugmail: http://bugzilla.novell.com/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the QA contact for the bug. _______________________________________________ mono-bugs maillist - [email protected] http://lists.ximian.com/mailman/listinfo/mono-bugs
