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