2 * mono-threads-posix.c: Low-level threading, posix version
5 * Rodrigo Kumpera (kumpera@gmail.com)
12 /* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */
13 #if defined (__MACH__)
14 #define _DARWIN_C_SOURCE 1
17 #include <mono/utils/mono-threads.h>
18 #include <mono/utils/mono-threads-posix-signals.h>
19 #include <mono/utils/mono-coop-semaphore.h>
20 #include <mono/metadata/gc-internals.h>
21 #include <mono/utils/w32handle.h>
25 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
26 #define USE_TKILL_ON_ANDROID 1
29 #ifdef USE_TKILL_ON_ANDROID
30 extern int tkill (pid_t tid
, int signal
);
33 #if defined(_POSIX_VERSION) || defined(__native_client__)
37 #include <sys/resource.h>
39 #if defined(__native_client__)
40 void nacl_shutdown_gc_thread(void);
44 win32_priority_to_posix_priority (MonoThreadPriority priority
, int policy
)
46 g_assert (priority
>= MONO_THREAD_PRIORITY_LOWEST
);
47 g_assert (priority
<= MONO_THREAD_PRIORITY_HIGHEST
);
49 /* Necessary to get valid priority range */
50 #ifdef _POSIX_PRIORITY_SCHEDULING
53 min
= sched_get_priority_min (policy
);
54 max
= sched_get_priority_max (policy
);
56 /* Partition priority range linearly (cross-multiply) */
57 if (max
> 0 && min
>= 0 && max
> min
)
58 return (int)((double) priority
* (max
- min
) / (MONO_THREAD_PRIORITY_HIGHEST
- MONO_THREAD_PRIORITY_LOWEST
));
76 mono_threads_platform_register (MonoThreadInfo
*info
)
78 gpointer thread_handle
;
80 info
->owned_mutexes
= g_ptr_array_new ();
81 info
->priority
= MONO_THREAD_PRIORITY_NORMAL
;
83 thread_handle
= mono_w32handle_new (MONO_W32HANDLE_THREAD
, NULL
);
84 if (thread_handle
== INVALID_HANDLE_VALUE
)
85 g_error ("%s: failed to create handle", __func__
);
87 /* We need to keep the handle alive, as long as the corresponding managed
88 * thread object is alive. The handle is going to be unref when calling
89 * the finalizer on the MonoThreadInternal object */
90 mono_w32handle_ref (thread_handle
);
92 g_assert (!info
->handle
);
93 info
->handle
= thread_handle
;
97 mono_threads_platform_create_thread (MonoThreadStart thread_fn
, gpointer thread_data
, gsize stack_size
, MonoNativeThreadId
*out_tid
)
103 res
= pthread_attr_init (&attr
);
106 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
107 if (stack_size
== 0) {
108 #if HAVE_VALGRIND_MEMCHECK_H
109 if (RUNNING_ON_VALGRIND
)
110 stack_size
= 1 << 20;
112 stack_size
= (SIZEOF_VOID_P
/ 4) * 1024 * 1024;
114 stack_size
= (SIZEOF_VOID_P
/ 4) * 1024 * 1024;
118 #ifdef PTHREAD_STACK_MIN
119 if (stack_size
< PTHREAD_STACK_MIN
)
120 stack_size
= PTHREAD_STACK_MIN
;
123 res
= pthread_attr_setstacksize (&attr
, stack_size
);
125 #endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
127 /* Actually start the thread */
128 res
= mono_gc_pthread_create (&thread
, &attr
, (gpointer (*)(gpointer
)) thread_fn
, thread_data
);
139 mono_threads_platform_yield (void)
141 return sched_yield () == 0;
145 mono_threads_platform_exit (int exit_code
)
147 #if defined(__native_client__)
148 nacl_shutdown_gc_thread();
151 mono_thread_info_detach ();
157 mono_threads_platform_unregister (MonoThreadInfo
*info
)
159 mono_threads_platform_set_exited (info
);
163 mono_threads_get_max_stack_size (void)
167 /* If getrlimit fails, we don't enforce any limits. */
168 if (getrlimit (RLIMIT_STACK
, &lim
))
170 /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
171 if (lim
.rlim_max
> (rlim_t
)INT_MAX
)
173 return (int)lim
.rlim_max
;
177 mono_threads_platform_open_thread_handle (HANDLE handle
, MonoNativeThreadId tid
)
179 mono_w32handle_ref (handle
);
185 mono_threads_platform_close_thread_handle (HANDLE handle
)
187 mono_w32handle_unref (handle
);
191 mono_threads_pthread_kill (MonoThreadInfo
*info
, int signum
)
193 THREADS_SUSPEND_DEBUG ("sending signal %d to %p[%p]\n", signum
, info
, mono_thread_info_get_tid (info
));
194 #ifdef USE_TKILL_ON_ANDROID
195 int result
, old_errno
= errno
;
196 result
= tkill (info
->native_handle
, signum
);
202 #elif defined(__native_client__)
203 /* Workaround pthread_kill abort() in NaCl glibc. */
205 #elif !defined(HAVE_PTHREAD_KILL)
206 g_error ("pthread_kill() is not supported by this platform");
208 return pthread_kill (mono_thread_info_get_tid (info
), signum
);
213 mono_native_thread_id_get (void)
215 return pthread_self ();
219 mono_native_thread_id_equals (MonoNativeThreadId id1
, MonoNativeThreadId id2
)
221 return pthread_equal (id1
, id2
);
225 * mono_native_thread_create:
227 * Low level thread creation function without any GC wrappers.
230 mono_native_thread_create (MonoNativeThreadId
*tid
, gpointer func
, gpointer arg
)
232 return pthread_create (tid
, NULL
, (void *(*)(void *)) func
, arg
) == 0;
236 mono_native_thread_set_name (MonoNativeThreadId tid
, const char *name
)
240 * We can't set the thread name for other threads, but we can at least make
241 * it work for threads that try to change their own name.
243 if (tid
!= mono_native_thread_id_get ())
247 pthread_setname_np ("");
251 strncpy (n
, name
, 63);
253 pthread_setname_np (n
);
255 #elif defined (__NetBSD__)
257 pthread_setname_np (tid
, "%s", (void*)"");
259 char n
[PTHREAD_MAX_NAMELEN_NP
];
261 strncpy (n
, name
, PTHREAD_MAX_NAMELEN_NP
);
262 n
[PTHREAD_MAX_NAMELEN_NP
- 1] = '\0';
263 pthread_setname_np (tid
, "%s", (void*)n
);
265 #elif defined (HAVE_PTHREAD_SETNAME_NP)
267 pthread_setname_np (tid
, "");
271 strncpy (n
, name
, 16);
273 pthread_setname_np (tid
, n
);
279 mono_threads_platform_set_exited (MonoThreadInfo
*info
)
281 gpointer mutex_handle
;
286 g_assert (info
->handle
);
288 if (mono_w32handle_issignalled (info
->handle
))
289 g_error ("%s: handle %p thread %p has already exited, it's handle is signalled", __func__
, info
->handle
, mono_thread_info_get_tid (info
));
290 if (mono_w32handle_get_type (info
->handle
) == MONO_W32HANDLE_UNUSED
)
291 g_error ("%s: handle %p thread %p has already exited, it's handle type is 'unused'", __func__
, info
->handle
, mono_thread_info_get_tid (info
));
293 pid
= wapi_getpid ();
294 tid
= pthread_self ();
296 for (i
= 0; i
< info
->owned_mutexes
->len
; i
++) {
297 mutex_handle
= g_ptr_array_index (info
->owned_mutexes
, i
);
298 wapi_mutex_abandon (mutex_handle
, pid
, tid
);
299 mono_thread_info_disown_mutex (info
, mutex_handle
);
302 g_ptr_array_free (info
->owned_mutexes
, TRUE
);
304 thr_ret
= mono_w32handle_lock_handle (info
->handle
);
305 g_assert (thr_ret
== 0);
307 mono_w32handle_set_signal_state (info
->handle
, TRUE
, TRUE
);
309 thr_ret
= mono_w32handle_unlock_handle (info
->handle
);
310 g_assert (thr_ret
== 0);
312 /* The thread is no longer active, so unref it */
313 mono_w32handle_unref (info
->handle
);
319 mono_threads_platform_describe (MonoThreadInfo
*info
, GString
*text
)
323 g_string_append_printf (text
, "thread handle %p state : ", info
->handle
);
325 mono_thread_info_describe_interrupt_token (info
, text
);
327 g_string_append_printf (text
, ", owns (");
328 for (i
= 0; i
< info
->owned_mutexes
->len
; i
++)
329 g_string_append_printf (text
, i
> 0 ? ", %p" : "%p", g_ptr_array_index (info
->owned_mutexes
, i
));
330 g_string_append_printf (text
, ")");
334 mono_threads_platform_own_mutex (MonoThreadInfo
*info
, gpointer mutex_handle
)
336 mono_w32handle_ref (mutex_handle
);
338 g_ptr_array_add (info
->owned_mutexes
, mutex_handle
);
342 mono_threads_platform_disown_mutex (MonoThreadInfo
*info
, gpointer mutex_handle
)
344 mono_w32handle_unref (mutex_handle
);
346 g_ptr_array_remove (info
->owned_mutexes
, mutex_handle
);
350 mono_threads_platform_get_priority (MonoThreadInfo
*info
)
352 return info
->priority
;
356 mono_threads_platform_set_priority (MonoThreadInfo
*info
, MonoThreadPriority priority
)
358 int policy
, posix_priority
;
359 struct sched_param param
;
362 tid
= mono_thread_info_get_tid (info
);
364 switch (pthread_getschedparam (tid
, &policy
, ¶m
)) {
368 g_warning ("pthread_getschedparam: error looking up thread id %x", (gsize
)tid
);
374 posix_priority
= win32_priority_to_posix_priority (priority
, policy
);
375 if (posix_priority
< 0)
378 param
.sched_priority
= posix_priority
;
379 switch (pthread_setschedparam (tid
, policy
, ¶m
)) {
383 g_warning ("%s: pthread_setschedprio: error looking up thread id %x", __func__
, (gsize
)tid
);
386 g_warning ("%s: priority %d not supported", __func__
, priority
);
389 g_warning ("%s: permission denied", __func__
);
395 info
->priority
= priority
;
400 static const gchar
* thread_typename (void)
405 static gsize
thread_typesize (void)
410 static MonoW32HandleOps thread_ops
= {
415 NULL
, /* special_wait */
418 thread_typename
, /* typename */
419 thread_typesize
, /* typesize */
423 mono_threads_platform_init (void)
425 mono_w32handle_register_ops (MONO_W32HANDLE_THREAD
, &thread_ops
);
427 mono_w32handle_register_capabilities (MONO_W32HANDLE_THREAD
, MONO_W32HANDLE_CAP_WAIT
);
430 #endif /* defined(_POSIX_VERSION) || defined(__native_client__) */
432 #if defined(USE_POSIX_BACKEND)
435 mono_threads_suspend_begin_async_suspend (MonoThreadInfo
*info
, gboolean interrupt_kernel
)
437 int sig
= interrupt_kernel
? mono_threads_posix_get_abort_signal () : mono_threads_posix_get_suspend_signal ();
439 if (!mono_threads_pthread_kill (info
, sig
)) {
440 mono_threads_add_to_pending_operation_set (info
);
447 mono_threads_suspend_check_suspend_result (MonoThreadInfo
*info
)
449 return info
->suspend_can_continue
;
453 This begins async resume. This function must do the following:
455 - Install an async target if one was requested.
456 - Notify the target to resume.
459 mono_threads_suspend_begin_async_resume (MonoThreadInfo
*info
)
461 mono_threads_add_to_pending_operation_set (info
);
462 return mono_threads_pthread_kill (info
, mono_threads_posix_get_restart_signal ()) == 0;
466 mono_threads_suspend_register (MonoThreadInfo
*info
)
468 #if defined (PLATFORM_ANDROID)
469 info
->native_handle
= gettid ();
474 mono_threads_suspend_free (MonoThreadInfo
*info
)
479 mono_threads_suspend_init (void)
481 mono_threads_posix_init_signals (MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART
);
484 #endif /* defined(USE_POSIX_BACKEND) */