2 * mono-threads-mach-helper.c: ObjectiveC hacks to improve our changes with thread shutdown
5 * Rodrigo Kumpera (kumpera@gmail.com)
14 #include <objc/runtime.h>
15 #include <objc/message.h>
16 #include <mono/utils/mono-compiler.h>
19 * We cannot include mono-threads.h as this includes io-layer internal types
20 * which conflicts with objc.
21 * Hence the hack here.
23 void mono_threads_init_dead_letter (void) MONO_INTERNAL;
24 void mono_threads_install_dead_letter (void) MONO_INTERNAL;
25 void mono_thread_info_detach (void) MONO_INTERNAL;
27 static Class nsobject, nsthread, mono_dead_letter_class;
28 static SEL dealloc, release, currentThread, threadDictionary, init, alloc, objectForKey, setObjectForKey;
29 static id mono_dead_letter_key;
32 * Our Mach bindings have a problem in that they might need to attach
33 * the runtime after the the user tls keys have been destroyed.
35 * This happens when a bound object is retained by NSThread, which is
36 * released very late in the TLS cleanup process.
38 * At that point, attaching the runtime leaves us in no position to
39 * detach it later using TLS destructors as pthread is done with user
40 * keys. This leaves us with a dead thread registered, which can cause
41 * all sorts of terrible problems.
43 * The tipical crash is when another thread is created at the exact
44 * same address of the previous one, cause thread registration to abort
45 * due to duplicate entries.
47 * So what do we do here?
49 * Experimentation showns that threadDictionary is destroied after the
50 * problematic keys, so we add our dead letter object as an aditional
51 * way to be notified of thread death.
54 mono_dead_letter_dealloc (id self, SEL _cmd)
56 struct objc_super super;
57 super.receiver = self;
58 super.class = nsobject;
59 objc_msgSendSuper (&super, dealloc);
61 mono_thread_info_detach ();
65 mono_threads_install_dead_letter (void)
69 cur = objc_msgSend ((id)nsthread, currentThread);
72 dict = objc_msgSend (cur, threadDictionary);
73 if (dict && objc_msgSend (dict, objectForKey, mono_dead_letter_key) == nil) {
74 id value = objc_msgSend (objc_msgSend ((id)mono_dead_letter_class, alloc), init);
78 * See the 'Dispatch Objective-C Messages Using the Method Function’s Prototype' section in
79 * the '64-Bit Transition Guide for Cocoa Touch' as to why this is required.
82 void (*action)(id, SEL, id, id) = (void (*)(id, SEL, id, id)) objc_msgSend;
83 action (dict, setObjectForKey, value, mono_dead_letter_key);
86 objc_msgSend (dict, setObjectForKey, value, mono_dead_letter_key);
89 objc_msgSend (value, release);
94 mono_threads_init_dead_letter (void)
96 id nsstring = objc_getClass ("NSString");
97 id nsautoreleasepool = objc_getClass ("NSAutoreleasePool");
98 SEL stringWithUTF8String = sel_registerName ("stringWithUTF8String:");
99 SEL retain = sel_registerName ("retain");
102 nsthread = (Class)objc_getClass ("NSThread");
103 nsobject = (Class)objc_getClass ("NSObject");
105 init = sel_registerName ("init");
106 alloc = sel_registerName ("alloc");
107 release = sel_registerName ("release");
108 dealloc = sel_registerName ("dealloc");
111 currentThread = sel_registerName ("currentThread");
112 threadDictionary = sel_registerName ("threadDictionary");
113 setObjectForKey = sel_registerName ("setObject:forKey:");
114 objectForKey = sel_registerName ("objectForKey:");
116 // define the dead letter class
117 mono_dead_letter_class = objc_allocateClassPair (nsobject, "MonoDeadLetter", 0);
118 class_addMethod (mono_dead_letter_class, dealloc, (IMP)mono_dead_letter_dealloc, "v@:");
119 objc_registerClassPair (mono_dead_letter_class);
121 // create the dict key
122 pool = objc_msgSend (objc_msgSend (nsautoreleasepool, alloc), init);
126 id (*action)(id, SEL, char*) = (id (*)(id, SEL, char*)) objc_msgSend;
127 mono_dead_letter_key = action(nsstring, stringWithUTF8String, "mono-dead-letter");
130 mono_dead_letter_key = objc_msgSend (nsstring, stringWithUTF8String, "mono-dead-letter");
133 objc_msgSend (mono_dead_letter_key, retain);
134 objc_msgSend (pool, release);