3 * Low-level threading, posix version
6 * Rodrigo Kumpera (kumpera@gmail.com)
13 /* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */
14 #if defined (__MACH__)
15 #define _DARWIN_C_SOURCE 1
18 #if defined (__HAIKU__)
19 #include <os/kernel/OS.h>
22 #include <mono/utils/mono-threads.h>
23 #include <mono/utils/mono-coop-semaphore.h>
24 #include <mono/metadata/gc-internals.h>
25 #include <mono/utils/mono-threads-debug.h>
29 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
30 #define USE_TKILL_ON_ANDROID 1
33 #ifdef USE_TKILL_ON_ANDROID
34 extern int tkill (pid_t tid
, int signal
);
37 #if defined(_POSIX_VERSION) && !defined (TARGET_WASM)
41 #include <sys/resource.h>
44 mono_thread_platform_create_thread (MonoThreadStart thread_fn
, gpointer thread_data
, gsize
* const stack_size
, MonoNativeThreadId
*tid
)
51 res
= pthread_attr_init (&attr
);
53 g_error ("%s: pthread_attr_init failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
56 set_stack_size
= *stack_size
;
60 #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
61 if (set_stack_size
== 0) {
62 #if HAVE_VALGRIND_MEMCHECK_H
63 if (RUNNING_ON_VALGRIND
)
64 set_stack_size
= 1 << 20;
66 set_stack_size
= (SIZEOF_VOID_P
/ 4) * 1024 * 1024;
68 set_stack_size
= (SIZEOF_VOID_P
/ 4) * 1024 * 1024;
72 #ifdef PTHREAD_STACK_MIN
73 if (set_stack_size
< PTHREAD_STACK_MIN
)
74 set_stack_size
= PTHREAD_STACK_MIN
;
77 res
= pthread_attr_setstacksize (&attr
, set_stack_size
);
79 g_error ("%s: pthread_attr_setstacksize failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
80 #endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
82 /* Actually start the thread */
83 res
= mono_gc_pthread_create (&thread
, &attr
, (gpointer (*)(gpointer
)) thread_fn
, thread_data
);
85 res
= pthread_attr_destroy (&attr
);
87 g_error ("%s: pthread_attr_destroy failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
96 res
= pthread_attr_getstacksize (&attr
, stack_size
);
98 g_error ("%s: pthread_attr_getstacksize failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
101 res
= pthread_attr_destroy (&attr
);
103 g_error ("%s: pthread_attr_destroy failed, error: \"%s\" (%d)", __func__
, g_strerror (res
), res
);
109 mono_threads_platform_init (void)
114 mono_threads_platform_in_critical_region (MonoNativeThreadId tid
)
120 mono_threads_platform_yield (void)
122 return sched_yield () == 0;
126 mono_threads_platform_exit (gsize exit_code
)
128 pthread_exit ((gpointer
) exit_code
);
132 ves_icall_System_Threading_Thread_SystemMaxStackSize (MonoError
*error
)
136 /* If getrlimit fails, we don't enforce any limits. */
137 if (getrlimit (RLIMIT_STACK
, &lim
))
139 /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
140 if (lim
.rlim_max
> (rlim_t
)INT_MAX
)
142 return (int)lim
.rlim_max
;
146 mono_threads_pthread_kill (MonoThreadInfo
*info
, int signum
)
148 THREADS_SUSPEND_DEBUG ("sending signal %d to %p[%p]\n", signum
, info
, mono_thread_info_get_tid (info
));
152 #ifdef USE_TKILL_ON_ANDROID
153 int old_errno
= errno
;
155 result
= tkill (info
->native_handle
, signum
);
161 #elif defined (HAVE_PTHREAD_KILL)
162 result
= pthread_kill (mono_thread_info_get_tid (info
), signum
);
165 g_error ("pthread_kill () is not supported by this platform");
169 * ESRCH just means the thread is gone; this is usually not fatal.
171 * ENOTSUP can occur if we try to send signals (e.g. for sampling) to Grand
172 * Central Dispatch threads on Apple platforms. This is kinda bad, but
173 * since there's really nothing we can do about it, we just ignore it and
176 * All other error codes are ill-documented and usually stem from various
177 * OS-specific idiosyncracies. We want to know about these, so fail loudly.
178 * One example is EAGAIN on Linux, which indicates a signal queue overflow.
182 #if defined (__MACH__) && defined (ENOTSUP)
186 g_error ("%s: pthread_kill failed with error %d - potential kernel OOM or signal queue overflow", __func__
, result
);
192 mono_native_thread_id_get (void)
194 return pthread_self ();
198 mono_native_thread_id_equals (MonoNativeThreadId id1
, MonoNativeThreadId id2
)
200 return pthread_equal (id1
, id2
);
204 * mono_native_thread_create:
206 * Low level thread creation function without any GC wrappers.
209 mono_native_thread_create (MonoNativeThreadId
*tid
, gpointer func
, gpointer arg
)
211 return pthread_create (tid
, NULL
, (void *(*)(void *)) func
, arg
) == 0;
215 mono_native_thread_set_name (MonoNativeThreadId tid
, const char *name
)
219 * We can't set the thread name for other threads, but we can at least make
220 * it work for threads that try to change their own name.
222 if (tid
!= mono_native_thread_id_get ())
226 pthread_setname_np ("");
230 strncpy (n
, name
, sizeof (n
) - 1);
231 n
[sizeof (n
) - 1] = '\0';
232 pthread_setname_np (n
);
234 #elif defined (__HAIKU__)
236 haiku_tid
= get_pthread_thread_id (tid
);
238 rename_thread (haiku_tid
, "");
240 rename_thread (haiku_tid
, name
);
242 #elif defined (__NetBSD__)
244 pthread_setname_np (tid
, "%s", (void*)"");
246 char n
[PTHREAD_MAX_NAMELEN_NP
];
248 strncpy (n
, name
, sizeof (n
) - 1);
249 n
[sizeof (n
) - 1] = '\0';
250 pthread_setname_np (tid
, "%s", (void*)n
);
252 #elif defined (HAVE_PTHREAD_SETNAME_NP)
254 pthread_setname_np (tid
, "");
258 strncpy (n
, name
, sizeof (n
) - 1);
259 n
[sizeof (n
) - 1] = '\0';
260 pthread_setname_np (tid
, n
);
266 mono_native_thread_join (MonoNativeThreadId tid
)
270 return !pthread_join (tid
, &res
);
273 #endif /* defined(_POSIX_VERSION) */
275 #if defined(USE_POSIX_BACKEND)
278 mono_threads_suspend_begin_async_suspend (MonoThreadInfo
*info
, gboolean interrupt_kernel
)
280 int sig
= interrupt_kernel
? mono_threads_suspend_get_abort_signal () : mono_threads_suspend_get_suspend_signal ();
282 if (!mono_threads_pthread_kill (info
, sig
)) {
283 mono_threads_add_to_pending_operation_set (info
);
290 mono_threads_suspend_check_suspend_result (MonoThreadInfo
*info
)
292 return info
->suspend_can_continue
;
296 This begins async resume. This function must do the following:
298 - Install an async target if one was requested.
299 - Notify the target to resume.
302 mono_threads_suspend_begin_async_resume (MonoThreadInfo
*info
)
304 int sig
= mono_threads_suspend_get_restart_signal ();
306 if (!mono_threads_pthread_kill (info
, sig
)) {
307 mono_threads_add_to_pending_operation_set (info
);
314 mono_threads_suspend_abort_syscall (MonoThreadInfo
*info
)
316 /* We signal a thread to break it from the current syscall.
317 * This signal should not be interpreted as a suspend request. */
318 info
->syscall_break_signal
= TRUE
;
319 if (mono_threads_pthread_kill (info
, mono_threads_suspend_get_abort_signal ()) == 0) {
320 mono_threads_add_to_pending_operation_set (info
);
325 mono_threads_suspend_register (MonoThreadInfo
*info
)
327 #if defined (HOST_ANDROID)
328 info
->native_handle
= gettid ();
333 mono_threads_suspend_free (MonoThreadInfo
*info
)
338 mono_threads_suspend_init (void)
342 #endif /* defined(USE_POSIX_BACKEND) */