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