2 * mono-threads.c: Low-level threading
5 * Rodrigo Kumpera (kumpera@gmail.com)
10 #include <mono/utils/mono-compiler.h>
11 #include <mono/utils/mono-semaphore.h>
12 #include <mono/utils/mono-threads.h>
13 #include <mono/utils/mono-tls.h>
14 #include <mono/utils/hazard-pointer.h>
15 #include <mono/metadata/gc-internal.h>
16 #include <mono/metadata/appdomain.h>
21 #define THREADS_DEBUG(...)
22 //#define THREADS_DEBUG(...) g_message(__VA_ARGS__)
25 void *(*start_routine) (void *);
28 MonoSemType registered;
31 static int thread_info_size;
32 static MonoThreadInfoCallbacks threads_callbacks;
33 static MonoNativeTlsKey thread_info_key;
34 static MonoLinkedListSet thread_list;
37 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
40 mono_hazard_pointer_clear (hp, 0);
42 mono_hazard_pointer_clear (hp, 1);
44 mono_hazard_pointer_clear (hp, 2);
48 mono_thread_info_insert (MonoThreadInfo *info)
50 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
52 if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
53 mono_hazard_pointer_clear_all (hp, -1);
57 mono_hazard_pointer_clear_all (hp, -1);
62 mono_thread_info_remove (MonoThreadInfo *info)
64 /*TLS is gone by now, so we can't rely on it to retrieve hp*/
65 MonoThreadHazardPointers *hp = mono_hazard_pointer_get_by_id (info->small_id);
68 THREADS_DEBUG ("removing info %p\n", info);
69 res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
70 mono_hazard_pointer_clear_all (hp, -1);
75 free_thread_info (gpointer mem)
77 MonoThreadInfo *info = mem;
83 register_thread (MonoThreadInfo *info, gpointer baseptr)
86 mono_thread_info_set_tid (info, mono_native_thread_id_get ());
87 info->small_id = mono_thread_small_id_alloc ();
89 THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
91 if (threads_callbacks.thread_register) {
92 if (threads_callbacks.thread_register (info, baseptr) == NULL) {
93 g_warning ("thread registation failed\n");
99 mono_native_tls_set_value (thread_info_key, info);
101 /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
102 result = mono_thread_info_insert (info);
108 unregister_thread (void *arg)
111 MonoThreadInfo *info = arg;
112 int small_id = info->small_id;
115 THREADS_DEBUG ("unregistering info %p\n", info);
117 if (threads_callbacks.thread_unregister)
118 threads_callbacks.thread_unregister (info);
120 result = mono_thread_info_remove (info);
123 mono_thread_small_id_free (small_id);
127 inner_start_thread (void *arg)
129 ThreadStartInfo *start_info = arg;
130 MonoThreadInfo* info;
131 void *t_arg = start_info->arg;
132 void *(*start_func) (void*) = start_info->start_routine;
136 info = g_malloc0 (thread_info_size);
138 register_thread (info, &post_result);
140 post_result = MONO_SEM_POST (&(start_info->registered));
141 g_assert (!post_result);
143 result = start_func (t_arg);
144 g_assert (!mono_domain_get ());
150 mono_thread_info_current (void)
152 return mono_native_tls_get_value (thread_info_key);
156 mono_thread_info_list_head (void)
162 mono_thread_info_attach (void *baseptr)
164 MonoThreadInfo *info = mono_native_tls_get_value (thread_info_key);
166 info = g_malloc0 (thread_info_size);
167 if (!register_thread (info, baseptr))
169 } else if (threads_callbacks.thread_attach) {
170 threads_callbacks.thread_attach (info);
176 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
179 threads_callbacks = *callbacks;
180 thread_info_size = info_size;
181 res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
182 mono_lls_init (&thread_list, free_thread_info);
183 mono_thread_smr_init ();
186 g_assert (sizeof (MonoNativeThreadId) == sizeof (uintptr_t));
190 mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
192 ThreadStartInfo *start_info;
195 start_info = g_malloc0 (sizeof (ThreadStartInfo));
198 MONO_SEM_INIT (&(start_info->registered), 0);
199 start_info->arg = arg;
200 start_info->start_routine = start_routine;
202 result = pthread_create (new_thread, attr, inner_start_thread, start_info);
204 while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
205 /*if (EINTR != errno) ABORT("sem_wait failed"); */
208 MONO_SEM_DESTROY (&(start_info->registered));