Merge pull request #654 from alesliehughes/master
[mono.git] / mono / utils / mono-threads.c
1 /*
2  * mono-threads.c: Low-level threading
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * Copyright 2011 Novell, Inc (http://www.novell.com)
8  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9  */
10
11 #include <mono/utils/mono-compiler.h>
12 #include <mono/utils/mono-semaphore.h>
13 #include <mono/utils/mono-threads.h>
14 #include <mono/utils/mono-tls.h>
15 #include <mono/utils/hazard-pointer.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/domain-internals.h>
18
19 #include <errno.h>
20
21 #if defined(__MACH__)
22 #include <mono/utils/mach-support.h>
23 #endif
24
25 #define THREADS_DEBUG(...)
26 //#define THREADS_DEBUG(...) g_message(__VA_ARGS__)
27
28 /*
29 Mutex that makes sure only a single thread can be suspending others.
30 Suspend is a very racy operation since it requires restarting until
31 the target thread is not on an unsafe region.
32
33 We could implement this using critical regions, but would be much much
34 harder for an operation that is hardly performance critical.
35
36 The GC has to acquire this lock before starting a STW to make sure
37 a runtime suspend won't make it wronly see a thread in a safepoint
38 when it is in fact not.
39 */
40 static mono_mutex_t global_suspend_lock;
41
42
43 static int thread_info_size;
44 static MonoThreadInfoCallbacks threads_callbacks;
45 static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
46 static MonoNativeTlsKey thread_info_key, small_id_key;
47 static MonoLinkedListSet thread_list;
48 static gboolean disable_new_interrupt = FALSE;
49 static gboolean mono_threads_inited = FALSE;
50
51 static inline void
52 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
53 {
54         if (retain != 0)
55                 mono_hazard_pointer_clear (hp, 0);
56         if (retain != 1)
57                 mono_hazard_pointer_clear (hp, 1);
58         if (retain != 2)
59                 mono_hazard_pointer_clear (hp, 2);
60 }
61
62 /*
63 If return non null Hazard Pointer 1 holds the return value.
64 */
65 MonoThreadInfo*
66 mono_thread_info_lookup (MonoNativeThreadId id)
67 {
68                 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
69
70         if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
71                 mono_hazard_pointer_clear_all (hp, -1);
72                 return NULL;
73         } 
74
75         mono_hazard_pointer_clear_all (hp, 1);
76         return mono_hazard_pointer_get_val (hp, 1);
77 }
78
79 static gboolean
80 mono_thread_info_insert (MonoThreadInfo *info)
81 {
82         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
83
84         if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
85                 mono_hazard_pointer_clear_all (hp, -1);
86                 return FALSE;
87         } 
88
89         mono_hazard_pointer_clear_all (hp, -1);
90         return TRUE;
91 }
92
93 static gboolean
94 mono_thread_info_remove (MonoThreadInfo *info)
95 {
96         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
97         gboolean res;
98
99         THREADS_DEBUG ("removing info %p\n", info);
100         res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
101         mono_hazard_pointer_clear_all (hp, -1);
102         return res;
103 }
104
105 static void
106 free_thread_info (gpointer mem)
107 {
108         MonoThreadInfo *info = mem;
109
110         mono_mutex_destroy (&info->suspend_lock);
111         MONO_SEM_DESTROY (&info->resume_semaphore);
112         MONO_SEM_DESTROY (&info->finish_resume_semaphore);
113         mono_threads_platform_free (info);
114
115         g_free (info);
116 }
117
118 int
119 mono_thread_info_register_small_id (void)
120 {
121         int small_id = mono_thread_small_id_alloc ();
122         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (small_id + 1));
123         return small_id;
124 }
125
126 static void*
127 register_thread (MonoThreadInfo *info, gpointer baseptr)
128 {
129         int small_id = mono_thread_info_register_small_id ();
130         gboolean result;
131         mono_thread_info_set_tid (info, mono_native_thread_id_get ());
132         info->small_id = small_id;
133
134         mono_mutex_init_suspend_safe (&info->suspend_lock);
135         MONO_SEM_INIT (&info->resume_semaphore, 0);
136         MONO_SEM_INIT (&info->finish_resume_semaphore, 0);
137
138         /*set TLS early so SMR works */
139         mono_native_tls_set_value (thread_info_key, info);
140
141         THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
142
143         if (threads_callbacks.thread_register) {
144                 if (threads_callbacks.thread_register (info, baseptr) == NULL) {
145                         g_warning ("thread registation failed\n");
146                         g_free (info);
147                         return NULL;
148                 }
149         }
150
151         mono_threads_platform_register (info);
152
153         /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
154         result = mono_thread_info_insert (info);
155         g_assert (result);
156         return info;
157 }
158
159 static void
160 unregister_thread (void *arg)
161 {
162         MonoThreadInfo *info = arg;
163         int small_id = info->small_id;
164         g_assert (info);
165
166         THREADS_DEBUG ("unregistering info %p\n", info);
167
168         /*
169          * TLS destruction order is not reliable so small_id might be cleaned up
170          * before us.
171          */
172         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
173
174         /*
175         The unregister callback is reposible for calling mono_threads_unregister_current_thread
176         since it usually needs to be done in sync with the GC does a stop-the-world.
177         */
178         if (threads_callbacks.thread_unregister)
179                 threads_callbacks.thread_unregister (info);
180         else
181                 mono_threads_unregister_current_thread (info);
182
183         /*now it's safe to free the thread info.*/
184         mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE);
185         mono_thread_small_id_free (small_id);
186 }
187
188 /**
189  * Removes the current thread from the thread list.
190  * This must be called from the thread unregister callback and nowhere else.
191  * The current thread must be passed as TLS might have already been cleaned up.
192 */
193 void
194 mono_threads_unregister_current_thread (MonoThreadInfo *info)
195 {
196         gboolean result;
197         g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ());
198         result = mono_thread_info_remove (info);
199         g_assert (result);
200
201 }
202
203 MonoThreadInfo*
204 mono_thread_info_current (void)
205 {
206         return mono_native_tls_get_value (thread_info_key);
207 }
208
209 int
210 mono_thread_info_get_small_id (void)
211 {
212         gpointer val = mono_native_tls_get_value (small_id_key);
213         if (!val)
214                 return -1;
215         return GPOINTER_TO_INT (val) - 1;
216 }
217
218 MonoLinkedListSet*
219 mono_thread_info_list_head (void)
220 {
221         return &thread_list;
222 }
223
224 MonoThreadInfo*
225 mono_thread_info_attach (void *baseptr)
226 {
227         MonoThreadInfo *info;
228         if (!mono_threads_inited)
229         {
230                 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a
231                  * thread is created before an embedding API user initialized Mono. */
232                 THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n");
233                 return NULL;
234         }
235         info = mono_native_tls_get_value (thread_info_key);
236         if (!info) {
237                 info = g_malloc0 (thread_info_size);
238                 THREADS_DEBUG ("attaching %p\n", info);
239                 if (!register_thread (info, baseptr))
240                         return NULL;
241         } else if (threads_callbacks.thread_attach) {
242                 threads_callbacks.thread_attach (info);
243         }
244         return info;
245 }
246
247 void
248 mono_thread_info_dettach (void)
249 {
250         MonoThreadInfo *info;
251         if (!mono_threads_inited)
252         {
253                 /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
254                  * is created before an embedding API user initialized Mono. */
255                 THREADS_DEBUG ("mono_thread_info_dettach called before mono_threads_init\n");
256                 return;
257         }
258         info = mono_native_tls_get_value (thread_info_key);
259         if (info) {
260                 THREADS_DEBUG ("detaching %p\n", info);
261                 unregister_thread (info);
262                 mono_native_tls_set_value (thread_info_key, NULL);
263         }
264 }
265
266 void
267 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
268 {
269         gboolean res;
270         threads_callbacks = *callbacks;
271         thread_info_size = info_size;
272 #ifdef HOST_WIN32
273         res = mono_native_tls_alloc (&thread_info_key, NULL);
274 #else
275         res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
276 #endif
277         g_assert (res);
278
279         res = mono_native_tls_alloc (&small_id_key, NULL);
280         g_assert (res);
281
282         mono_mutex_init_suspend_safe (&global_suspend_lock);
283
284         mono_lls_init (&thread_list, NULL);
285         mono_thread_smr_init ();
286         mono_threads_init_platform ();
287
288 #if defined(__MACH__)
289         mono_mach_init (thread_info_key);
290 #endif
291
292         mono_threads_inited = TRUE;
293
294         g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
295 }
296
297 void
298 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
299 {
300         runtime_callbacks = *callbacks;
301 }
302
303 MonoThreadInfoCallbacks *
304 mono_threads_get_callbacks (void)
305 {
306         return &threads_callbacks;
307 }
308
309 MonoThreadInfoRuntimeCallbacks *
310 mono_threads_get_runtime_callbacks (void)
311 {
312         return &runtime_callbacks;
313 }
314
315 /*
316 The return value is only valid until a matching mono_thread_info_resume is called
317 */
318 static MonoThreadInfo*
319 mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel)
320 {
321         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
322         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
323         if (!info)
324                 return NULL;
325
326         mono_mutex_lock (&info->suspend_lock);
327
328         /*thread is on the process of detaching*/
329         if (mono_thread_info_run_state (info) > STATE_RUNNING) {
330                 mono_hazard_pointer_clear (hp, 1);
331                 return NULL;
332         }
333
334         THREADS_DEBUG ("suspend %x IN COUNT %d\n", tid, info->suspend_count);
335
336         if (info->suspend_count) {
337                 ++info->suspend_count;
338                 mono_hazard_pointer_clear (hp, 1);
339                 mono_mutex_unlock (&info->suspend_lock);
340                 return info;
341         }
342
343         if (!mono_threads_core_suspend (info)) {
344                 mono_mutex_unlock (&info->suspend_lock);
345                 mono_hazard_pointer_clear (hp, 1);
346                 return NULL;
347         }
348
349         if (interrupt_kernel) 
350                 mono_threads_core_interrupt (info);
351
352         ++info->suspend_count;
353         info->thread_state |= STATE_SUSPENDED;
354         mono_mutex_unlock (&info->suspend_lock);
355         mono_hazard_pointer_clear (hp, 1);
356
357         return info;
358 }
359
360 void
361 mono_thread_info_self_suspend (void)
362 {
363         gboolean ret;
364         MonoThreadInfo *info = mono_thread_info_current ();
365         if (!info)
366                 return;
367
368         mono_mutex_lock (&info->suspend_lock);
369
370         THREADS_DEBUG ("self suspend IN COUNT %d\n", info->suspend_count);
371
372         g_assert (info->suspend_count == 0);
373         ++info->suspend_count;
374
375         info->thread_state |= STATE_SELF_SUSPENDED;
376
377         ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL);
378         g_assert (ret);
379
380         mono_mutex_unlock (&info->suspend_lock);
381
382         while (MONO_SEM_WAIT (&info->resume_semaphore) != 0) {
383                 /*if (EINTR != errno) ABORT("sem_wait failed"); */
384         }
385
386         g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */
387         MONO_SEM_POST (&info->finish_resume_semaphore);
388 }
389
390 static gboolean
391 mono_thread_info_resume_internal (MonoThreadInfo *info)
392 {
393         gboolean result;
394         if (mono_thread_info_suspend_state (info) == STATE_SELF_SUSPENDED) {
395                 MONO_SEM_POST (&info->resume_semaphore);
396                 while (MONO_SEM_WAIT (&info->finish_resume_semaphore) != 0) {
397                         /* g_assert (errno == EINTR); */
398                 }
399                 result = TRUE;
400         } else {
401                 result = mono_threads_core_resume (info);
402         }
403         info->thread_state &= ~SUSPEND_STATE_MASK;
404         return result;
405 }
406
407 gboolean
408 mono_thread_info_resume (MonoNativeThreadId tid)
409 {
410         gboolean result = TRUE;
411         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
412         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
413         if (!info)
414                 return FALSE;
415
416         mono_mutex_lock (&info->suspend_lock);
417
418         THREADS_DEBUG ("resume %x IN COUNT %d\n",tid, info->suspend_count);
419
420         if (info->suspend_count <= 0) {
421                 mono_mutex_unlock (&info->suspend_lock);
422                 mono_hazard_pointer_clear (hp, 1);
423                 return FALSE;
424         }
425
426         /*
427          * The theory here is that if we manage to suspend the thread it means it did not
428          * start cleanup since it take the same lock. 
429         */
430         g_assert (mono_thread_info_get_tid (info));
431
432         if (--info->suspend_count == 0)
433                 result = mono_thread_info_resume_internal (info);
434
435         mono_mutex_unlock (&info->suspend_lock);
436         mono_hazard_pointer_clear (hp, 1);
437
438         return result;
439 }
440
441 /*
442 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
443 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
444 */
445 static gboolean
446 is_thread_in_critical_region (MonoThreadInfo *info)
447 {
448         MonoMethod *method;
449         MonoJitInfo *ji = mono_jit_info_table_find (
450                 info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
451                 MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
452
453         if (!ji)
454                 return FALSE;
455
456         method = ji->method;
457
458         return threads_callbacks.mono_method_is_critical (method);
459 }
460
461 /*
462 WARNING:
463 If we are trying to suspend a target that is on a critical region
464 and running a syscall we risk looping forever if @interrupt_kernel is FALSE.
465 So, be VERY carefull in calling this with @interrupt_kernel == FALSE.
466 */
467 MonoThreadInfo*
468 mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel)
469 {
470         MonoThreadInfo *info = NULL;
471         int sleep_duration = 0;
472
473         /*FIXME: unify this with self-suspend*/
474         g_assert (id != mono_native_thread_id_get ());
475
476         mono_thread_info_suspend_lock ();
477
478         for (;;) {
479                 if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel))) {
480                         g_warning ("failed to suspend thread %p, hopefully it is dead", (gpointer)id);
481                         mono_thread_info_suspend_unlock ();
482                         return NULL;
483                 }
484                 /*WARNING: We now are in interrupt context until we resume the thread. */
485                 if (!is_thread_in_critical_region (info))
486                         break;
487
488                 if (!mono_thread_info_resume (id)) {
489                         g_warning ("failed to result thread %p, hopefully it is dead", (gpointer)id);
490                         mono_thread_info_suspend_unlock ();
491                         return NULL;
492                 }
493                 THREADS_DEBUG ("restarted thread %p\n", (gpointer)id);
494
495                 if (!sleep_duration) {
496 #ifdef HOST_WIN32
497                         SwitchToThread ();
498 #else
499                         sched_yield ();
500 #endif
501                 }
502                 else {
503                         g_usleep (sleep_duration);
504                 }
505                 sleep_duration += 10;
506         }
507
508         mono_thread_info_suspend_unlock ();
509         return info;
510 }
511
512 /**
513 Inject an assynchronous call into the target thread. The target thread must be suspended and
514 only a single async call can be setup for a given suspend cycle.
515 This async call must cause stack unwinding as the current implementation doesn't save enough state
516 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
517 currently used only to deliver exceptions.
518 */
519 void
520 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
521 {
522         g_assert (info->suspend_count);
523         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
524         g_assert (!info->async_target);
525         info->async_target = target_func;
526         /* This is not GC tracked */
527         info->user_data = user_data;
528 }
529
530 /*
531 The suspend lock is held during any suspend in progress.
532 A GC that has safepoints must take this lock as part of its
533 STW to make sure no unsafe pending suspend is in progress.   
534 */
535 void
536 mono_thread_info_suspend_lock (void)
537 {
538         mono_mutex_lock (&global_suspend_lock);
539 }
540
541 void
542 mono_thread_info_suspend_unlock (void)
543 {
544         mono_mutex_unlock (&global_suspend_lock);
545 }
546
547 void
548 mono_thread_info_disable_new_interrupt (gboolean disable)
549 {
550         disable_new_interrupt = disable;
551 }
552
553 /*
554  * This is a very specific function whose only purpose is to
555  * break a given thread from socket syscalls.
556  *
557  * This only exists because linux won't fail a call to connect
558  * if the underlying is closed.
559  *
560  * TODO We should cleanup and unify this with the other syscall abort
561  * facility.
562  */
563 void
564 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
565 {
566         MonoThreadHazardPointers *hp;
567         MonoThreadInfo *info;
568         
569         if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ())
570                 return;
571
572         hp = mono_hazard_pointer_get ();        
573         info = mono_thread_info_lookup (tid); /*info on HP1*/
574         if (!info)
575                 return;
576
577         if (mono_thread_info_run_state (info) > STATE_RUNNING) {
578                 mono_hazard_pointer_clear (hp, 1);
579                 return;
580         }
581
582         mono_thread_info_suspend_lock ();
583
584         mono_threads_core_abort_syscall (info);
585
586         mono_hazard_pointer_clear (hp, 1);
587         mono_thread_info_suspend_unlock ();
588 }
589
590 /*
591 Disabled by default for now.
592 To enable this we need mini to implement the callbacks by MonoThreadInfoRuntimeCallbacks
593 which means mono-context and setup_async_callback, and we need a mono-threads backend.
594 */
595 gboolean
596 mono_thread_info_new_interrupt_enabled (void)
597 {
598         /*We need STW gc events to work correctly*/
599 #if defined (HAVE_BOEHM_GC) && !defined (USE_INCLUDED_LIBGC)
600         return FALSE;
601 #endif
602         /*port not done*/
603 #if defined(HOST_WIN32)
604         return FALSE;
605 #endif
606 #if defined (__i386__)
607         return !disable_new_interrupt;
608 #endif
609         return FALSE;
610 }