Merge pull request #665 from andreas-auerswald/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/utils/mono-memory-model.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/domain-internals.h>
19
20 #include <errno.h>
21
22 #if defined(__MACH__)
23 #include <mono/utils/mach-support.h>
24 #endif
25
26 #define THREADS_DEBUG(...)
27 //#define THREADS_DEBUG(...) g_message(__VA_ARGS__)
28
29 /*
30 Mutex that makes sure only a single thread can be suspending others.
31 Suspend is a very racy operation since it requires restarting until
32 the target thread is not on an unsafe region.
33
34 We could implement this using critical regions, but would be much much
35 harder for an operation that is hardly performance critical.
36
37 The GC has to acquire this lock before starting a STW to make sure
38 a runtime suspend won't make it wronly see a thread in a safepoint
39 when it is in fact not.
40 */
41 static MonoSemType global_suspend_semaphore;
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_SEM_DESTROY (&info->suspend_semaphore);
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_SEM_INIT (&info->suspend_semaphore, 1);
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_SEM_INIT (&global_suspend_semaphore, 1);
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_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
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_SEM_POST (&info->suspend_semaphore);
340                 return info;
341         }
342
343         if (!mono_threads_core_suspend (info)) {
344                 MONO_SEM_POST (&info->suspend_semaphore);
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_SEM_POST (&info->suspend_semaphore);
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_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
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_SEM_POST (&info->suspend_semaphore);
381
382         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);
383
384         g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */
385         MONO_SEM_POST (&info->finish_resume_semaphore);
386 }
387
388 static gboolean
389 mono_thread_info_resume_internal (MonoThreadInfo *info)
390 {
391         gboolean result;
392         if (mono_thread_info_suspend_state (info) == STATE_SELF_SUSPENDED) {
393                 MONO_SEM_POST (&info->resume_semaphore);
394                 MONO_SEM_WAIT_UNITERRUPTIBLE (&info->finish_resume_semaphore);
395                 result = TRUE;
396         } else {
397                 result = mono_threads_core_resume (info);
398         }
399         info->thread_state &= ~SUSPEND_STATE_MASK;
400         return result;
401 }
402
403 gboolean
404 mono_thread_info_resume (MonoNativeThreadId tid)
405 {
406         gboolean result = TRUE;
407         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
408         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
409         if (!info)
410                 return FALSE;
411
412         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
413
414         THREADS_DEBUG ("resume %x IN COUNT %d\n",tid, info->suspend_count);
415
416         if (info->suspend_count <= 0) {
417                 MONO_SEM_POST (&info->suspend_semaphore);
418                 mono_hazard_pointer_clear (hp, 1);
419                 return FALSE;
420         }
421
422         /*
423          * The theory here is that if we manage to suspend the thread it means it did not
424          * start cleanup since it take the same lock. 
425         */
426         g_assert (mono_thread_info_get_tid (info));
427
428         if (--info->suspend_count == 0)
429                 result = mono_thread_info_resume_internal (info);
430
431         MONO_SEM_POST (&info->suspend_semaphore);
432         mono_hazard_pointer_clear (hp, 1);
433         mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);
434
435         return result;
436 }
437
438 void
439 mono_thread_info_finish_suspend (void)
440 {
441         mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);
442 }
443
444 /*
445 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
446 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
447 */
448 static gboolean
449 is_thread_in_critical_region (MonoThreadInfo *info)
450 {
451         MonoMethod *method;
452         MonoJitInfo *ji;
453
454         if (info->inside_critical_region)
455                 return TRUE;
456
457         ji = mono_jit_info_table_find (
458                 info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
459                 MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
460
461         if (!ji)
462                 return FALSE;
463
464         method = ji->method;
465
466         return threads_callbacks.mono_method_is_critical (method);
467 }
468
469 /*
470 WARNING:
471 If we are trying to suspend a target that is on a critical region
472 and running a syscall we risk looping forever if @interrupt_kernel is FALSE.
473 So, be VERY carefull in calling this with @interrupt_kernel == FALSE.
474 */
475 MonoThreadInfo*
476 mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel)
477 {
478         MonoThreadInfo *info = NULL;
479         int sleep_duration = 0;
480
481         /*FIXME: unify this with self-suspend*/
482         g_assert (id != mono_native_thread_id_get ());
483
484         mono_thread_info_suspend_lock ();
485
486         for (;;) {
487                 if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel))) {
488                         g_warning ("failed to suspend thread %p, hopefully it is dead", (gpointer)id);
489                         mono_thread_info_suspend_unlock ();
490                         return NULL;
491                 }
492                 /*WARNING: We now are in interrupt context until we resume the thread. */
493                 if (!is_thread_in_critical_region (info))
494                         break;
495
496                 if (!mono_thread_info_resume (id)) {
497                         g_warning ("failed to result thread %p, hopefully it is dead", (gpointer)id);
498                         mono_thread_info_suspend_unlock ();
499                         return NULL;
500                 }
501                 THREADS_DEBUG ("restarted thread %p\n", (gpointer)id);
502
503                 if (!sleep_duration) {
504 #ifdef HOST_WIN32
505                         SwitchToThread ();
506 #else
507                         sched_yield ();
508 #endif
509                 }
510                 else {
511                         g_usleep (sleep_duration);
512                 }
513                 sleep_duration += 10;
514         }
515
516         mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE);
517
518         mono_thread_info_suspend_unlock ();
519         return info;
520 }
521
522 /**
523 Inject an assynchronous call into the target thread. The target thread must be suspended and
524 only a single async call can be setup for a given suspend cycle.
525 This async call must cause stack unwinding as the current implementation doesn't save enough state
526 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
527 currently used only to deliver exceptions.
528 */
529 void
530 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
531 {
532         g_assert (info->suspend_count);
533         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
534         g_assert (!info->async_target);
535         info->async_target = target_func;
536         /* This is not GC tracked */
537         info->user_data = user_data;
538 }
539
540 /*
541 The suspend lock is held during any suspend in progress.
542 A GC that has safepoints must take this lock as part of its
543 STW to make sure no unsafe pending suspend is in progress.   
544 */
545 void
546 mono_thread_info_suspend_lock (void)
547 {
548         MONO_SEM_WAIT_UNITERRUPTIBLE (&global_suspend_semaphore);
549 }
550
551 void
552 mono_thread_info_suspend_unlock (void)
553 {
554         MONO_SEM_POST (&global_suspend_semaphore);
555 }
556
557 void
558 mono_thread_info_disable_new_interrupt (gboolean disable)
559 {
560         disable_new_interrupt = disable;
561 }
562
563 /*
564  * This is a very specific function whose only purpose is to
565  * break a given thread from socket syscalls.
566  *
567  * This only exists because linux won't fail a call to connect
568  * if the underlying is closed.
569  *
570  * TODO We should cleanup and unify this with the other syscall abort
571  * facility.
572  */
573 void
574 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
575 {
576         MonoThreadHazardPointers *hp;
577         MonoThreadInfo *info;
578         
579         if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ())
580                 return;
581
582         hp = mono_hazard_pointer_get ();        
583         info = mono_thread_info_lookup (tid); /*info on HP1*/
584         if (!info)
585                 return;
586
587         if (mono_thread_info_run_state (info) > STATE_RUNNING) {
588                 mono_hazard_pointer_clear (hp, 1);
589                 return;
590         }
591
592         mono_thread_info_suspend_lock ();
593
594         mono_threads_core_abort_syscall (info);
595
596         mono_hazard_pointer_clear (hp, 1);
597         mono_thread_info_suspend_unlock ();
598 }
599
600 /*
601 Disabled by default for now.
602 To enable this we need mini to implement the callbacks by MonoThreadInfoRuntimeCallbacks
603 which means mono-context and setup_async_callback, and we need a mono-threads backend.
604 */
605 gboolean
606 mono_thread_info_new_interrupt_enabled (void)
607 {
608         /*We need STW gc events to work correctly*/
609 #if defined (HAVE_BOEHM_GC) && !defined (USE_INCLUDED_LIBGC)
610         return FALSE;
611 #endif
612         /*port not done*/
613 #if defined(HOST_WIN32)
614         return FALSE;
615 #endif
616 #if defined (__i386__)
617         return !disable_new_interrupt;
618 #endif
619         return FALSE;
620 }