Add missing file I forget. Fix the build.
[mono.git] / mono / utils / mono-threads-mach-helper.c
1 /*
2  * mono-threads-mach-helper.c: ObjectiveC hacks to improve our changes with thread shutdown
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * (C) 2014 Xamarin
8  */
9
10 #include "config.h"
11
12 #if defined(__MACH__)
13
14 #include <objc/runtime.h>
15 #include <objc/message.h>
16 #include <mono/utils/mono-compiler.h>
17
18 /*
19 We cannot include mono-threads.h as this includes io-layer internal types
20 which conflicts with objc.
21 Hence the hack here.
22 */
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;
26
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;
30
31 /*
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.
34
35 This happens when a bound object is retained by NSThread, which is released very late in the
36 TLS cleanup process.
37
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.
41
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.
44
45 So what do we do here?
46
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.
49 */
50 static void
51 mono_dead_letter_dealloc (id self, SEL _cmd)
52 {
53         struct objc_super super;
54         super.receiver = self;
55         super.class = nsobject;
56         objc_msgSendSuper (&super, dealloc);
57
58         mono_thread_info_detach ();
59 }
60
61 void
62 mono_threads_install_dead_letter (void)
63 {
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);
70         }
71 }
72
73 void
74 mono_threads_init_dead_letter (void)
75 {
76         id nsstring = objc_getClass ("NSString");
77         id nsautoreleasepool = objc_getClass ("NSAutoreleasePool");
78         SEL stringWithUTF8String = sel_registerName ("stringWithUTF8String:");
79         SEL retain = sel_registerName ("retain");
80
81         nsthread = (Class)objc_getClass ("NSThread");
82         nsobject = (Class)objc_getClass ("NSObject");
83
84         init = sel_registerName ("init");
85         alloc = sel_registerName ("alloc");
86         release = sel_registerName ("release");
87         dealloc = sel_registerName ("dealloc");
88         
89
90         currentThread = sel_registerName ("currentThread");
91         threadDictionary = sel_registerName ("threadDictionary");
92         setObjectForKey = sel_registerName ("setObject:forKey:");
93         objectForKey = sel_registerName ("objectForKey:");
94
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);
99
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);
105 }
106 #endif