From 98a369ffa9a543049dfd5388051ab05eb57b47b2 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 24 Feb 2017 08:19:10 -0500 Subject: [PATCH] [threads] Fix async call in coop (#4423) We would observe crashes like the following: ``` * Assertion at mono-threads.c:1009, condition `mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED' not met Debug info from gdb: [New LWP 26793] [New LWP 26792] [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 0x00002b0ff3481ee9 in waitpid () from /lib/x86_64-linux-gnu/libpthread.so.0 Id Target Id Frame 3 Thread 0x2b0ff3e6c700 (LWP 26792) "SGen worker" 0x00002b0ff347e414 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0 2 Thread 0x2b0ff633e700 (LWP 26793) "Finalizer" 0x00002b0ff347e414 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0 * 1 Thread 0x2b0ff2b67c40 (LWP 26780) "mono" 0x00002b0ff3481ee9 in waitpid () from /lib/x86_64-linux-gnu/libpthread.so.0 Thread 3 (Thread 0x2b0ff3e6c700 (LWP 26792)): #0 0x00002b0ff347e414 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0 #1 0x0000000000661bdf in mono_os_cond_wait (mutex=0x9dee40 , cond=0x9dee00 ) at ../../mono/utils/mono-os-mutex.h:146 #2 thread_func (thread_data=0x2b0ff2bcb008) at sgen-thread-pool.c:129 #3 0x00002b0ff347a182 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0 #4 0x00002b0ff39a130d in clone () from /lib/x86_64-linux-gnu/libc.so.6 Thread 2 (Thread 0x2b0ff633e700 (LWP 26793)): #0 0x00002b0ff347e414 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/x86_64-linux-gnu/libpthread.so.0 #1 0x00000000005caff3 in mono_os_cond_wait (mutex=, cond=) at ../../mono/utils/mono-os-mutex.h:146 #2 mono_coop_cond_wait (mutex=, cond=) at ../../mono/utils/mono-coop-mutex.h:87 #3 mono_threadpool_io_remove_socket (fd=134239440) at threadpool-io.c:628 #4 0x00000000005ae4f4 in ves_icall_System_Net_Sockets_Socket_Close_internal (sock=42, werror=) at w32socket.c:708 #5 0x0000000041e8101f in ?? () #6 0x00002b1014abe070 in ?? () #7 0x0000000001615860 in ?? () #8 0x0000000001615860 in ?? () #9 0x0000000000000000 in ?? () Thread 1 (Thread 0x2b0ff2b67c40 (LWP 26780)): #0 0x00002b0ff3481ee9 in waitpid () from /lib/x86_64-linux-gnu/libpthread.so.0 #1 0x00000000004ac5e6 in mono_handle_native_crash (signal=, ctx=, info=) at mini-exceptions.c:2557 #2 #3 0x00002b0ff38dcf79 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #4 0x00002b0ff38e0388 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #5 0x000000000066b459 in mono_log_write_logfile (log_domain=, level=, hdr=, message=) at mono-log-common.c:137 #6 0x00000000006805e0 in monoeg_g_logv (log_domain=log_domain@entry=0x0, log_level=log_level@entry=G_LOG_LEVEL_ERROR, format=, args=args@entry=0x7ffc7324ea78) at goutput.c:115 #7 0x0000000000680736 in monoeg_assertion_message (format=) at goutput.c:135 #8 0x00000000006759b8 in mono_thread_info_setup_async_call (info=info@entry=0x2b0ff80008c0, target_func=target_func@entry=0x5bac20 , user_data=user_data@entry=0x0) at mono-threads.c:1009 #9 0x00000000005bad50 in suspend_for_shutdown_critical (info=info@entry=0x2b0ff80008c0, unused=unused@entry=0x0) at threads.c:5019 #10 0x00000000006763ae in mono_thread_info_safe_suspend_and_run (id=47347555100416, interrupt_kernel=interrupt_kernel@entry=0, callback=callback@entry=0x5bad40 , user_data=user_data@entry=0x0) at mono-threads.c:979 #11 0x00000000005c2e71 in mono_thread_internal_suspend_for_shutdown (thread=) at threads.c:5028 #12 0x00000000005e9100 in mono_gc_cleanup () at gc.c:1015 #13 0x00000000005e108e in mono_runtime_cleanup (domain=domain@entry=0x1615860) at appdomain.c:423 #14 0x00000000004228cb in mini_cleanup (domain=0x1615860) at mini-runtime.c:4111 #15 0x000000000047b99f in mono_main (argc=10, argv=) at driver.c:2167 #16 0x00000000004200db in mono_main_with_options (argv=0x7ffc7324ef68, argc=10) at main.c:45 #17 main (argc=10, argv=0x7ffc7324ef68) at main.c:338 ================================================================= Got a SIGABRT while executing native code. This usually indicates a fatal error in the mono runtime or one of the native libraries used by your application. ================================================================= ``` --- mono/utils/mono-threads-coop.c | 12 ++++++++++++ mono/utils/mono-threads.c | 8 ++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mono/utils/mono-threads-coop.c b/mono/utils/mono-threads-coop.c index 7f274853683..ed6b1807a3a 100644 --- a/mono/utils/mono-threads-coop.c +++ b/mono/utils/mono-threads-coop.c @@ -288,6 +288,12 @@ mono_threads_exit_gc_safe_region_unbalanced (gpointer cookie, gpointer *stackdat default: g_error ("Unknown thread state"); } + + if (info->async_target) { + info->async_target (info->user_data); + info->async_target = NULL; + info->user_data = NULL; + } } void @@ -355,6 +361,12 @@ mono_threads_enter_gc_unsafe_region_unbalanced_with_info (MonoThreadInfo *info, g_error ("Unknown thread state"); } + if (info->async_target) { + info->async_target (info->user_data); + info->async_target = NULL; + info->user_data = NULL; + } + return info; } diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c index b0e98d43f28..76821d0d359 100644 --- a/mono/utils/mono-threads.c +++ b/mono/utils/mono-threads.c @@ -1005,8 +1005,12 @@ currently used only to deliver exceptions. void mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data) { - /* An async call can only be setup on an async suspended thread */ - g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED); + if (!mono_threads_is_coop_enabled ()) { + /* In non-coop mode, an async call can only be setup on an async suspended thread, but in coop mode, a thread + * may be in blocking state, and will execute the async call when leaving the safepoint, leaving a gc safe + * region or entering a gc unsafe region */ + g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED); + } /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/ g_assert (!info->async_target); info->async_target = target_func; -- 2.25.1