mono-threads-posix.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /**
  2. * \file
  3. * Low-level threading, posix version
  4. *
  5. * Author:
  6. * Rodrigo Kumpera (kumpera@gmail.com)
  7. *
  8. * (C) 2011 Novell, Inc
  9. */
  10. #include <config.h>
  11. /* For pthread_main_np, pthread_get_stackaddr_np and pthread_get_stacksize_np */
  12. #if defined (__MACH__)
  13. #define _DARWIN_C_SOURCE 1
  14. #endif
  15. #if defined (HOST_FUCHSIA)
  16. #include <zircon/syscalls.h>
  17. #endif
  18. #if defined (__HAIKU__)
  19. #include <os/kernel/OS.h>
  20. #endif
  21. #include <mono/utils/mono-threads.h>
  22. #include <mono/utils/mono-threads-coop.h>
  23. #include <mono/utils/mono-coop-semaphore.h>
  24. #include <mono/metadata/gc-internals.h>
  25. #include <mono/utils/mono-threads-debug.h>
  26. #include <mono/utils/mono-errno.h>
  27. #include <errno.h>
  28. // Unity -- Just disable tkill wholesale for now
  29. // #if !defined(ENABLE_NETCORE) && defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
  30. // // tkill was deprecated and removed in the recent versions of Android NDK
  31. // #define USE_TKILL_ON_ANDROID 1
  32. // extern int tkill (pid_t tid, int signal);
  33. // #endif
  34. #if defined(_POSIX_VERSION) && !defined (HOST_WASM)
  35. #include <pthread.h>
  36. #include <sys/mman.h>
  37. #ifdef HAVE_SYS_RESOURCE_H
  38. #include <sys/resource.h>
  39. #endif
  40. static pthread_mutex_t memory_barrier_process_wide_mutex = PTHREAD_MUTEX_INITIALIZER;
  41. static void *memory_barrier_process_wide_helper_page;
  42. gboolean
  43. mono_thread_platform_create_thread (MonoThreadStart thread_fn, gpointer thread_data, gsize* const stack_size, MonoNativeThreadId *tid)
  44. {
  45. pthread_attr_t attr;
  46. pthread_t thread;
  47. gint res;
  48. gsize set_stack_size;
  49. res = pthread_attr_init (&attr);
  50. if (res != 0)
  51. g_error ("%s: pthread_attr_init failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
  52. if (stack_size)
  53. set_stack_size = *stack_size;
  54. else
  55. set_stack_size = 0;
  56. #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
  57. if (set_stack_size == 0) {
  58. #if HAVE_VALGRIND_MEMCHECK_H
  59. if (RUNNING_ON_VALGRIND)
  60. set_stack_size = 1 << 20;
  61. else
  62. set_stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
  63. #else
  64. set_stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
  65. #endif
  66. }
  67. #ifdef PTHREAD_STACK_MIN
  68. if (set_stack_size < PTHREAD_STACK_MIN)
  69. set_stack_size = PTHREAD_STACK_MIN;
  70. #endif
  71. res = pthread_attr_setstacksize (&attr, set_stack_size);
  72. if (res != 0)
  73. g_error ("%s: pthread_attr_setstacksize failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
  74. #endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */
  75. /* Actually start the thread */
  76. #ifdef RUNTIME_IL2CPP
  77. res = pthread_create (&thread, &attr, (gpointer (*)(gpointer)) thread_fn, thread_data);
  78. #else
  79. res = mono_gc_pthread_create (&thread, &attr, (gpointer (*)(gpointer)) thread_fn, thread_data);
  80. #endif
  81. if (res) {
  82. res = pthread_attr_destroy (&attr);
  83. if (res != 0)
  84. g_error ("%s: pthread_attr_destroy failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
  85. return FALSE;
  86. }
  87. if (tid)
  88. *tid = thread;
  89. if (stack_size) {
  90. res = pthread_attr_getstacksize (&attr, stack_size);
  91. if (res != 0)
  92. g_error ("%s: pthread_attr_getstacksize failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
  93. }
  94. res = pthread_attr_destroy (&attr);
  95. if (res != 0)
  96. g_error ("%s: pthread_attr_destroy failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
  97. return TRUE;
  98. }
  99. void
  100. mono_threads_platform_init (void)
  101. {
  102. }
  103. gboolean
  104. mono_threads_platform_in_critical_region (THREAD_INFO_TYPE *info)
  105. {
  106. return FALSE;
  107. }
  108. gboolean
  109. mono_threads_platform_yield (void)
  110. {
  111. return sched_yield () == 0;
  112. }
  113. void
  114. mono_threads_platform_exit (gsize exit_code)
  115. {
  116. pthread_exit ((gpointer) exit_code);
  117. }
  118. #if HOST_FUCHSIA
  119. int
  120. mono_thread_info_get_system_max_stack_size (void)
  121. {
  122. /* For now, we do not enforce any limits */
  123. return INT_MAX;
  124. }
  125. #else
  126. int
  127. mono_thread_info_get_system_max_stack_size (void)
  128. {
  129. struct rlimit lim;
  130. /* If getrlimit fails, we don't enforce any limits. */
  131. if (getrlimit (RLIMIT_STACK, &lim))
  132. return INT_MAX;
  133. /* rlim_t is an unsigned long long on 64bits OSX but we want an int response. */
  134. if (lim.rlim_max > (rlim_t)INT_MAX)
  135. return INT_MAX;
  136. return (int)lim.rlim_max;
  137. }
  138. #endif
  139. int
  140. mono_threads_pthread_kill (MonoThreadInfo *info, int signum)
  141. {
  142. THREADS_SUSPEND_DEBUG ("sending signal %d to %p[%p]\n", signum, info, mono_thread_info_get_tid (info));
  143. const int signal_queue_ovf_retry_count G_GNUC_UNUSED = 5;
  144. const gulong signal_queue_ovf_sleep_us G_GNUC_UNUSED = 10 * 1000; /* 10 milliseconds */
  145. int retry_count G_GNUC_UNUSED = 0;
  146. int result;
  147. #if defined (__linux__)
  148. redo:
  149. #endif
  150. #ifdef USE_TKILL_ON_ANDROID
  151. {
  152. int old_errno = errno;
  153. result = tkill (info->native_handle, signum);
  154. if (result < 0) {
  155. result = errno;
  156. mono_set_errno (old_errno);
  157. }
  158. }
  159. #elif defined (HAVE_PTHREAD_KILL)
  160. result = pthread_kill (mono_thread_info_get_tid (info), signum);
  161. #else
  162. result = -1;
  163. g_error ("pthread_kill () is not supported by this platform");
  164. #endif
  165. /*
  166. * ESRCH just means the thread is gone; this is usually not fatal.
  167. *
  168. * ENOTSUP can occur if we try to send signals (e.g. for sampling) to Grand
  169. * Central Dispatch threads on Apple platforms. This is kinda bad, but
  170. * since there's really nothing we can do about it, we just ignore it and
  171. * move on.
  172. *
  173. * All other error codes are ill-documented and usually stem from various
  174. * OS-specific idiosyncracies. We want to know about these, so fail loudly.
  175. * One example is EAGAIN on Linux, which indicates a signal queue overflow.
  176. */
  177. if (result &&
  178. result != ESRCH
  179. #if defined (__MACH__) && defined (ENOTSUP)
  180. && result != ENOTSUP
  181. #endif
  182. #if defined (__linux__)
  183. && !(result == EAGAIN && retry_count < signal_queue_ovf_retry_count)
  184. #endif
  185. )
  186. g_error ("%s: pthread_kill failed with error %d - potential kernel OOM or signal queue overflow", __func__, result);
  187. #if defined (__linux__)
  188. if (result == EAGAIN && retry_count < signal_queue_ovf_retry_count) {
  189. /* HACK: if the signal queue overflows on linux, try again a couple of times.
  190. * Tries to address https://github.com/dotnet/runtime/issues/32377
  191. */
  192. g_warning ("%s: pthread_kill failed with error %d - potential kernel OOM or signal queue overflow, sleeping for %ld microseconds", __func__, result, signal_queue_ovf_sleep_us);
  193. g_usleep (signal_queue_ovf_sleep_us);
  194. ++retry_count;
  195. goto redo;
  196. }
  197. #endif
  198. return result;
  199. }
  200. MonoNativeThreadId
  201. mono_native_thread_id_get (void)
  202. {
  203. return pthread_self ();
  204. }
  205. gboolean
  206. mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2)
  207. {
  208. return pthread_equal (id1, id2);
  209. }
  210. /*
  211. * mono_native_thread_create:
  212. *
  213. * Low level thread creation function without any GC wrappers.
  214. */
  215. gboolean
  216. mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
  217. {
  218. return pthread_create (tid, NULL, (void *(*)(void *)) func, arg) == 0;
  219. }
  220. size_t
  221. mono_native_thread_get_name (MonoNativeThreadId tid, char *name_out, size_t max_len)
  222. {
  223. #ifdef HAVE_PTHREAD_GETNAME_NP
  224. int error = pthread_getname_np(tid, name_out, max_len);
  225. if (error != 0)
  226. return 0;
  227. return strlen(name_out);
  228. #else
  229. return 0;
  230. #endif
  231. }
  232. void
  233. mono_native_thread_set_name (MonoNativeThreadId tid, const char *name)
  234. {
  235. #ifdef __MACH__
  236. /*
  237. * We can't set the thread name for other threads, but we can at least make
  238. * it work for threads that try to change their own name.
  239. */
  240. if (tid != mono_native_thread_id_get ())
  241. return;
  242. if (!name) {
  243. pthread_setname_np ("");
  244. } else {
  245. char n [63];
  246. strncpy (n, name, sizeof (n) - 1);
  247. n [sizeof (n) - 1] = '\0';
  248. pthread_setname_np (n);
  249. }
  250. #elif defined (__HAIKU__)
  251. thread_id haiku_tid;
  252. haiku_tid = get_pthread_thread_id (tid);
  253. if (!name) {
  254. rename_thread (haiku_tid, "");
  255. } else {
  256. rename_thread (haiku_tid, name);
  257. }
  258. #elif defined (__NetBSD__)
  259. if (!name) {
  260. pthread_setname_np (tid, "%s", (void*)"");
  261. } else {
  262. char n [PTHREAD_MAX_NAMELEN_NP];
  263. strncpy (n, name, sizeof (n) - 1);
  264. n [sizeof (n) - 1] = '\0';
  265. pthread_setname_np (tid, "%s", (void*)n);
  266. }
  267. #elif defined (HAVE_PTHREAD_SETNAME_NP)
  268. #if defined (__linux__)
  269. /* Ignore requests to set the main thread name because it causes the
  270. * value returned by Process.ProcessName to change.
  271. */
  272. MonoNativeThreadId main_thread_tid;
  273. if (mono_native_thread_id_main_thread_known (&main_thread_tid) &&
  274. mono_native_thread_id_equals (tid, main_thread_tid))
  275. return;
  276. #endif
  277. if (!name) {
  278. pthread_setname_np (tid, "");
  279. } else {
  280. char n [16];
  281. strncpy (n, name, sizeof (n) - 1);
  282. n [sizeof (n) - 1] = '\0';
  283. pthread_setname_np (tid, n);
  284. }
  285. #endif
  286. }
  287. gboolean
  288. mono_native_thread_join (MonoNativeThreadId tid)
  289. {
  290. void *res;
  291. return !pthread_join (tid, &res);
  292. }
  293. void
  294. mono_memory_barrier_process_wide (void)
  295. {
  296. int status;
  297. status = pthread_mutex_lock (&memory_barrier_process_wide_mutex);
  298. g_assert (status == 0);
  299. if (memory_barrier_process_wide_helper_page == NULL) {
  300. status = posix_memalign (&memory_barrier_process_wide_helper_page, mono_pagesize (), mono_pagesize ());
  301. g_assert (status == 0);
  302. }
  303. // Changing a helper memory page protection from read / write to no access
  304. // causes the OS to issue IPI to flush TLBs on all processors. This also
  305. // results in flushing the processor buffers.
  306. status = mono_mprotect (memory_barrier_process_wide_helper_page, mono_pagesize (), MONO_MMAP_READ | MONO_MMAP_WRITE);
  307. g_assert (status == 0);
  308. // Ensure that the page is dirty before we change the protection so that
  309. // we prevent the OS from skipping the global TLB flush.
  310. __sync_add_and_fetch ((size_t*)memory_barrier_process_wide_helper_page, 1);
  311. status = mono_mprotect (memory_barrier_process_wide_helper_page, mono_pagesize (), MONO_MMAP_NONE);
  312. g_assert (status == 0);
  313. status = pthread_mutex_unlock (&memory_barrier_process_wide_mutex);
  314. g_assert (status == 0);
  315. }
  316. gint32
  317. mono_native_thread_processor_id_get (void)
  318. {
  319. #ifdef HAVE_SCHED_GETCPU
  320. return sched_getcpu ();
  321. #else
  322. return -1;
  323. #endif
  324. }
  325. #endif /* defined(_POSIX_VERSION) */
  326. #if defined(USE_POSIX_BACKEND)
  327. gboolean
  328. mono_threads_suspend_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
  329. {
  330. int sig = interrupt_kernel ? mono_threads_suspend_get_abort_signal () : mono_threads_suspend_get_suspend_signal ();
  331. if (!mono_threads_pthread_kill (info, sig)) {
  332. mono_threads_add_to_pending_operation_set (info);
  333. return TRUE;
  334. }
  335. if (!mono_threads_transition_abort_async_suspend (info)) {
  336. /* We raced with self suspend and lost so suspend can continue. */
  337. g_assert (mono_threads_is_hybrid_suspension_enabled ());
  338. info->suspend_can_continue = TRUE;
  339. THREADS_SUSPEND_DEBUG ("\tlost race with self suspend %p\n", mono_thread_info_get_tid (info));
  340. return TRUE;
  341. }
  342. return FALSE;
  343. }
  344. gboolean
  345. mono_threads_suspend_check_suspend_result (MonoThreadInfo *info)
  346. {
  347. return info->suspend_can_continue;
  348. }
  349. /*
  350. This begins async resume. This function must do the following:
  351. - Install an async target if one was requested.
  352. - Notify the target to resume.
  353. */
  354. gboolean
  355. mono_threads_suspend_begin_async_resume (MonoThreadInfo *info)
  356. {
  357. int sig = mono_threads_suspend_get_restart_signal ();
  358. if (!mono_threads_pthread_kill (info, sig)) {
  359. mono_threads_add_to_pending_operation_set (info);
  360. return TRUE;
  361. }
  362. return FALSE;
  363. }
  364. void
  365. mono_threads_suspend_abort_syscall (MonoThreadInfo *info)
  366. {
  367. /* We signal a thread to break it from the current syscall.
  368. * This signal should not be interpreted as a suspend request. */
  369. info->syscall_break_signal = TRUE;
  370. if (mono_threads_pthread_kill (info, mono_threads_suspend_get_abort_signal ()) == 0) {
  371. mono_threads_add_to_pending_operation_set (info);
  372. }
  373. }
  374. void
  375. mono_threads_suspend_register (MonoThreadInfo *info)
  376. {
  377. #if defined (HOST_ANDROID)
  378. info->native_handle = gettid ();
  379. #endif
  380. }
  381. void
  382. mono_threads_suspend_free (MonoThreadInfo *info)
  383. {
  384. }
  385. void
  386. mono_threads_suspend_init (void)
  387. {
  388. }
  389. #endif /* defined(USE_POSIX_BACKEND) */