Skip to content

Commit

Permalink
[threads] Fix async call in coop (mono#4423)
Browse files Browse the repository at this point in the history
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
 mono#5  0x0000000041e8101f in ?? ()
 mono#6  0x00002b1014abe070 in ?? ()
 mono#7  0x0000000001615860 in ?? ()
 mono#8  0x0000000001615860 in ?? ()
 mono#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
 mono#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
 mono#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
 mono#7  0x0000000000680736 in monoeg_assertion_message (format=<optimized out>) at goutput.c:135
 mono#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
 mono#9  0x00000000005bad50 in suspend_for_shutdown_critical (info=info@entry=0x2b0ff80008c0, unused=unused@entry=0x0) at threads.c:5019
 mono#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
 mono#11 0x00000000005c2e71 in mono_thread_internal_suspend_for_shutdown (thread=<optimized out>) at threads.c:5028
 mono#12 0x00000000005e9100 in mono_gc_cleanup () at gc.c:1015
 mono#13 0x00000000005e108e in mono_runtime_cleanup (domain=domain@entry=0x1615860) at appdomain.c:423
 mono#14 0x00000000004228cb in mini_cleanup (domain=0x1615860) at mini-runtime.c:4111
 mono#15 0x000000000047b99f in mono_main (argc=10, argv=<optimized out>) at driver.c:2167
 mono#16 0x00000000004200db in mono_main_with_options (argv=0x7ffc7324ef68, argc=10) at main.c:45
 mono#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.
 =================================================================
```
  • Loading branch information
luhenry committed Mar 8, 2017
1 parent 84e9738 commit 65a7fa0
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 2 deletions.
12 changes: 12 additions & 0 deletions mono/utils/mono-threads-coop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
8 changes: 6 additions & 2 deletions mono/utils/mono-threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 65a7fa0

Please sign in to comment.