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.
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 the runtime after
33 the the user tls keys have been destroyed.
35 This happens when a bound object is retained by NSThread, which is released very late in the
38 At that point, attaching the runtime leaves us in no position to detach it later using TLS destructors
39 as pthread is done with user keys. This leaves us with a dead thread registered, which can cause
40 all sorts of terrible problems.
42 The tipical crash is when another thread is created at the exact same address of the previous one, cause
43 thread registration to abort due to duplicate entries.
45 So what do we do here?
47 Experimentation showns that threadDictionary is destroied after the problematic keys, so we add our dead letter
48 object as an aditional way to be notified of thread death.
51 mono_dead_letter_dealloc (id self, SEL _cmd)
53 struct objc_super super;
54 super.receiver = self;
55 super.class = nsobject;
56 objc_msgSendSuper (&super, dealloc);
58 mono_thread_info_detach ();
62 mono_threads_install_dead_letter (void)
64 id cur = objc_msgSend ((id)nsthread, currentThread);
65 id dict = objc_msgSend (cur, threadDictionary);
66 if (objc_msgSend (dict, objectForKey, mono_dead_letter_key) == nil) {
67 id value = objc_msgSend (objc_msgSend ((id)mono_dead_letter_class, alloc), init);
68 objc_msgSend (dict, setObjectForKey, value, mono_dead_letter_key);
69 objc_msgSend (value, release);
74 mono_threads_init_dead_letter (void)
76 id nsstring = objc_getClass ("NSString");
77 id nsautoreleasepool = objc_getClass ("NSAutoreleasePool");
78 SEL stringWithUTF8String = sel_registerName ("stringWithUTF8String:");
79 SEL retain = sel_registerName ("retain");
81 nsthread = (Class)objc_getClass ("NSThread");
82 nsobject = (Class)objc_getClass ("NSObject");
84 init = sel_registerName ("init");
85 alloc = sel_registerName ("alloc");
86 release = sel_registerName ("release");
87 dealloc = sel_registerName ("dealloc");
90 currentThread = sel_registerName ("currentThread");
91 threadDictionary = sel_registerName ("threadDictionary");
92 setObjectForKey = sel_registerName ("setObject:forKey:");
93 objectForKey = sel_registerName ("objectForKey:");
95 //define the dead letter class
96 mono_dead_letter_class = objc_allocateClassPair (nsobject, "MonoDeadLetter", 0);
97 class_addMethod (mono_dead_letter_class, dealloc, (IMP)mono_dead_letter_dealloc, "v@:");
98 objc_registerClassPair (mono_dead_letter_class);
100 //create the dict key
101 id pool = objc_msgSend (objc_msgSend (nsautoreleasepool, alloc), init);
102 mono_dead_letter_key = objc_msgSend (nsstring, stringWithUTF8String, "mono-dead-letter");
103 objc_msgSend (mono_dead_letter_key, retain);
104 objc_msgSend (pool, release);