[Mono-bugs] [Bug 537764] Mono crashes on OS X Snow Leopard

bugzilla_noreply at novell.com bugzilla_noreply at novell.com
Mon Dec 7 16:47:58 EST 2009


http://bugzilla.novell.com/show_bug.cgi?id=537764

http://bugzilla.novell.com/show_bug.cgi?id=537764#c21


Laurent Etiemble <laurent.etiemble at gmail.com> 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 <laurent.etiemble at gmail.com> 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.


More information about the mono-bugs mailing list