gboolean mono_threads_wait_pending_operations (void) { int i; int c = pending_suspends; /* Wait threads to park */ THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-COUNT] %d\n", c); if (pending_suspends) { MonoStopwatch suspension_time; mono_stopwatch_start (&suspension_time); for (i = 0; i < pending_suspends; ++i) { THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-WAITING]\n"); InterlockedIncrement (&waits_done); if (!mono_os_sem_timedwait (&suspend_semaphore, SLEEP_DURATION_BEFORE_ABORT, MONO_SEM_FLAGS_NONE)) continue; mono_stopwatch_stop (&suspension_time); dump_threads (); MOSTLY_ASYNC_SAFE_PRINTF ("WAITING for %d threads, got %d suspended\n", (int)pending_suspends, i); g_error ("suspend_thread suspend took %d ms, which is more than the allowed %d ms", (int)mono_stopwatch_elapsed_ms (&suspension_time), SLEEP_DURATION_BEFORE_ABORT); } mono_stopwatch_stop (&suspension_time); THREADS_SUSPEND_DEBUG ("Suspending %d threads took %d ms.\n", (int)pending_suspends, (int)mono_stopwatch_elapsed_ms (&suspension_time)); } pending_suspends = 0; return c > 0; }
MONO_SIG_HANDLER_FUNC (static, sigterm_signal_handler) { MONO_SIG_HANDLER_GET_CONTEXT; // Note: this function only returns for a single thread // When it's invoked on other threads once the dump begins, // those threads perform their dumps and then sleep until we // die. The dump ends with the exit(1) below MonoContext mctx; gchar *output = NULL; mono_sigctx_to_monoctx (ctx, &mctx); if (!mono_threads_summarize (&mctx, &output, NULL)) g_assert_not_reached (); // Only the dumping-supervisor thread exits mono_thread_summarize MOSTLY_ASYNC_SAFE_PRINTF("Unhandled exception dump: \n######\n%s\n######\n", output); mono_chain_signal (MONO_SIG_HANDLER_PARAMS); exit (1); }
static void dump_threads (void) { MonoThreadInfo *info; MonoThreadInfo *cur = mono_thread_info_current (); MOSTLY_ASYNC_SAFE_PRINTF ("STATE CUE CARD: (? means a positive number, usually 1 or 2, * means any number)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x0\t- starting (GOOD, unless the thread is running managed code)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x1\t- running (BAD, unless it's the gc thread)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x2\t- detached (GOOD, unless the thread is running managed code)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?03\t- async suspended (GOOD)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?04\t- self suspended (GOOD)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?05\t- async suspend requested (BAD)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?06\t- self suspend requested (BAD)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x*07\t- blocking (GOOD)\n"); MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?08\t- blocking with pending suspend (GOOD)\n"); FOREACH_THREAD_SAFE (info) { #ifdef TARGET_MACH char thread_name [256] = { 0 }; pthread_getname_np (mono_thread_info_get_tid (info), thread_name, 255); MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] (%s) state %x %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, thread_name, info->thread_state, info == cur ? "GC INITIATOR" : "" ); #else MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] state %x %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, info->thread_state, info == cur ? "GC INITIATOR" : "" ); #endif } END_FOREACH_THREAD_SAFE }