3 * ObjectiveC hacks to improve our changes with thread shutdown
6 * Rodrigo Kumpera (kumpera@gmail.com)
16 #include <objc/runtime.h>
17 #include <objc/message.h>
18 #include <mono/utils/mono-compiler.h>
19 #include <mono/utils/mono-publib.h>
22 * We cannot include mono-threads.h as this includes io-layer internal types
23 * which conflicts with objc.
24 * Hence the hack here.
26 void mono_threads_init_dead_letter (void);
27 void mono_threads_install_dead_letter (void);
29 mono_thread_info_detach (void);
31 static Class nsobject
, nsthread
, mono_dead_letter_class
;
32 static SEL dealloc
, release
, currentThread
, threadDictionary
, init
, alloc
, objectForKey
, setObjectForKey
;
33 static id mono_dead_letter_key
;
36 * Our Mach bindings have a problem in that they might need to attach
37 * the runtime after the the user tls keys have been destroyed.
39 * This happens when a bound object is retained by NSThread, which is
40 * released very late in the TLS cleanup process.
42 * At that point, attaching the runtime leaves us in no position to
43 * detach it later using TLS destructors as pthread is done with user
44 * keys. This leaves us with a dead thread registered, which can cause
45 * all sorts of terrible problems.
47 * The tipical crash is when another thread is created at the exact
48 * same address of the previous one, cause thread registration to abort
49 * due to duplicate entries.
51 * So what do we do here?
53 * Experimentation showns that threadDictionary is destroied after the
54 * problematic keys, so we add our dead letter object as an aditional
55 * way to be notified of thread death.
58 mono_dead_letter_dealloc (id self
, SEL _cmd
)
60 struct objc_super super
;
61 super
.receiver
= self
;
62 #if !defined(__cplusplus) && !__OBJC2__
63 super
.class = nsobject
;
65 super
.super_class
= nsobject
;
67 void (*objc_msgSendSuper_op
)(struct objc_super
*, SEL
) = (void (*)(struct objc_super
*, SEL
)) objc_msgSendSuper
;
68 objc_msgSendSuper_op (&super
, dealloc
);
70 mono_thread_info_detach ();
74 mono_threads_install_dead_letter (void)
79 * See the 'Dispatch Objective-C Messages Using the Method Function’s Prototype' section in
80 * the '64-Bit Transition Guide for Cocoa Touch' as to why this is required.
82 * It doesn't hurt on other architectures either, so no need to #ifdef it only for ARM64.
85 id (*id_objc_msgSend
)(id
, SEL
) = (id (*)(id
, SEL
)) objc_msgSend
;
86 id (*id_objc_msgSend_id
)(id
, SEL
, id
) = (id (*)(id
, SEL
, id
)) objc_msgSend
;
87 void (*objc_msgSend_id_id
)(id
, SEL
, id
, id
) = (void (*)(id
, SEL
, id
, id
)) objc_msgSend
;
89 cur
= id_objc_msgSend ((id
)nsthread
, currentThread
);
92 dict
= id_objc_msgSend (cur
, threadDictionary
);
93 if (dict
&& id_objc_msgSend_id (dict
, objectForKey
, mono_dead_letter_key
) == nil
) {
94 id value
= id_objc_msgSend (id_objc_msgSend ((id
)mono_dead_letter_class
, alloc
), init
);
96 objc_msgSend_id_id (dict
, setObjectForKey
, value
, mono_dead_letter_key
);
98 id_objc_msgSend (value
, release
);
103 mono_threads_init_dead_letter (void)
105 id nsstring
= (id
) objc_getClass ("NSString");
106 id nsautoreleasepool
= (id
) objc_getClass ("NSAutoreleasePool");
107 SEL stringWithUTF8String
= sel_registerName ("stringWithUTF8String:");
108 SEL retain
= sel_registerName ("retain");
111 nsthread
= (Class
)objc_getClass ("NSThread");
112 nsobject
= (Class
)objc_getClass ("NSObject");
114 init
= sel_registerName ("init");
115 alloc
= sel_registerName ("alloc");
116 release
= sel_registerName ("release");
117 dealloc
= sel_registerName ("dealloc");
120 currentThread
= sel_registerName ("currentThread");
121 threadDictionary
= sel_registerName ("threadDictionary");
122 setObjectForKey
= sel_registerName ("setObject:forKey:");
123 objectForKey
= sel_registerName ("objectForKey:");
125 // define the dead letter class
126 mono_dead_letter_class
= objc_allocateClassPair (nsobject
, "MonoDeadLetter", 0);
127 class_addMethod (mono_dead_letter_class
, dealloc
, (IMP
)mono_dead_letter_dealloc
, "v@:");
128 objc_registerClassPair (mono_dead_letter_class
);
130 id (*id_objc_msgSend
)(id
, SEL
) = (id (*)(id
, SEL
)) objc_msgSend
;
132 // create the dict key
133 pool
= id_objc_msgSend (id_objc_msgSend (nsautoreleasepool
, alloc
), init
);
135 id (*objc_msgSend_char
)(id
, SEL
, const char*) = (id (*)(id
, SEL
, const char*)) objc_msgSend
;
136 mono_dead_letter_key
= objc_msgSend_char (nsstring
, stringWithUTF8String
, "mono-dead-letter");
138 id_objc_msgSend (mono_dead_letter_key
, retain
);
139 id_objc_msgSend (pool
, release
);