diff options
author | Ludovic Henry <ludovic@xamarin.com> | 2017-02-24 16:19:10 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-24 16:19:10 +0300 |
commit | 98a369ffa9a543049dfd5388051ab05eb57b47b2 (patch) | |
tree | 823a22518dd5b3b7e8405c348ab7ce79c4dd693e | |
parent | 4fb9e11be7d0ea5069e2da3ea5d66b35ba949086 (diff) |
[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 <lock>, cond=0x9dee00 <work_cond>) 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=<optimized out>, cond=<optimized out>) at ../../mono/utils/mono-os-mutex.h:146
#2 mono_coop_cond_wait (mutex=<optimized out>, cond=<optimized out>) 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=<optimized out>) 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=<optimized out>, ctx=<optimized out>, info=<optimized out>) at mini-exceptions.c:2557
#2 <signal handler called>
#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=<optimized out>, level=<optimized out>, hdr=<optimized out>, message=<optimized out>) 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=<optimized out>, args=args@entry=0x7ffc7324ea78) at goutput.c:115
#7 0x0000000000680736 in monoeg_assertion_message (format=<optimized out>) at goutput.c:135
#8 0x00000000006759b8 in mono_thread_info_setup_async_call (info=info@entry=0x2b0ff80008c0, target_func=target_func@entry=0x5bac20 <suspend_for_shutdown_async_call>, 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 <suspend_for_shutdown_critical>, user_data=user_data@entry=0x0) at mono-threads.c:979
#11 0x00000000005c2e71 in mono_thread_internal_suspend_for_shutdown (thread=<optimized out>) 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=<optimized out>) 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.
=================================================================
```
-rw-r--r-- | mono/utils/mono-threads-coop.c | 12 | ||||
-rw-r--r-- | 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; |