diff options
author | Gonzalo Paniagua Javier <gonzalo.mono@gmail.com> | 2006-02-28 04:14:37 +0300 |
---|---|---|
committer | Gonzalo Paniagua Javier <gonzalo.mono@gmail.com> | 2006-02-28 04:14:37 +0300 |
commit | c3733aa980f405b7e1f913d1e355c036ce139c5c (patch) | |
tree | f5eaf59cdebe2c927cd8356f396ccb066a8e3769 | |
parent | 53c61e76eda2cb5432cd4073679fb634403d4477 (diff) |
backport of the thread dump code by Zoltan
svn path=/branches/mono-1-1-13/mono/; revision=57364
-rw-r--r-- | mono/metadata/ChangeLog | 6 | ||||
-rw-r--r-- | mono/metadata/object-internals.h | 2 | ||||
-rw-r--r-- | mono/metadata/threads.c | 35 | ||||
-rw-r--r-- | mono/metadata/threads.h | 2 | ||||
-rw-r--r-- | mono/mini/ChangeLog | 4 | ||||
-rw-r--r-- | mono/mini/mini-exceptions.c | 72 | ||||
-rw-r--r-- | mono/mini/mini.c | 22 | ||||
-rw-r--r-- | mono/mini/mini.h | 2 |
8 files changed, 133 insertions, 12 deletions
diff --git a/mono/metadata/ChangeLog b/mono/metadata/ChangeLog index ce85a8bc07a..bc742f8d757 100644 --- a/mono/metadata/ChangeLog +++ b/mono/metadata/ChangeLog @@ -1,3 +1,9 @@ +2006-01-26 Zoltan Varga <vargaz@gmail.com> + + * object-internals.h (MonoThread): Add 'thread_dump_requested' field. + + * threads.c (mono_threads_request_thread_dump): New helper function. + 2006-02-24 Gonzalo Paniagua Javier <gonzalo@ximian.com> * threadpool.c: for asynchronous connect(), enable the same workaround diff --git a/mono/metadata/object-internals.h b/mono/metadata/object-internals.h index 8af7f8ebaa8..6e03829e443 100644 --- a/mono/metadata/object-internals.h +++ b/mono/metadata/object-internals.h @@ -253,7 +253,7 @@ struct _MonoThread { * These fields are used to avoid having to increment corlib versions * when a new field is added to the unmanaged MonoThread structure. */ - gpointer unused1; + MonoBoolean thread_dump_requested; gpointer unused2; gpointer unused3; gpointer unused4; diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index b3e15b57992..0a73e8d30d3 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -2204,6 +2204,41 @@ void mono_thread_suspend_all_other_threads (void) g_free (wait); } +/** + * mono_threads_request_thread_dump: + * + * Ask all threads except the current to print their stacktrace to stdout. + */ +void +mono_threads_request_thread_dump (void) +{ + struct wait_data *wait = g_new0 (struct wait_data, 1); + int i, waitnum; + gsize self = GetCurrentThreadId (); + gpointer *events; + guint32 eventidx = 0; + + /* + * Make a copy of the hashtable since we can't do anything with + * threads while threads_mutex is held. + */ + mono_threads_lock (); + mono_g_hash_table_foreach (threads, collect_threads, wait); + mono_threads_unlock (); + + for (i = 0; i < wait->num; ++i) { + MonoThread *thread = wait->threads [i]; + + if (!mono_gc_is_finalizer_thread (thread) && (thread != mono_thread_current ()) && !thread->thread_dump_requested) { + thread->thread_dump_requested = TRUE; + + signal_thread_state_change (thread); + } + + CloseHandle (wait->handles [i]); + } +} + /* * mono_thread_push_appdomain_ref: * diff --git a/mono/metadata/threads.h b/mono/metadata/threads.h index 0e564931fb0..afc4ff8925a 100644 --- a/mono/metadata/threads.h +++ b/mono/metadata/threads.h @@ -69,6 +69,8 @@ void mono_gc_stop_world (void); void mono_gc_start_world (void); +void mono_threads_request_thread_dump (void); + extern MonoException* mono_thread_request_interruption (gboolean running_managed); extern gboolean mono_thread_interruption_requested (void); extern void mono_thread_interruption_checkpoint (void); diff --git a/mono/mini/ChangeLog b/mono/mini/ChangeLog index 7d4b6da0518..c11d3ab51cb 100644 --- a/mono/mini/ChangeLog +++ b/mono/mini/ChangeLog @@ -1,3 +1,7 @@ +2006-01-26 Zoltan Varga <vargaz@gmail.com> + + * mini.h mini.c mini-exceptions.c: Add thread dump support. Fixes + #75145. Thu Feb 23 13:45:46 CET 2006 Paolo Molaro <lupus@ximian.com> diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index d11fffbfd55..31953481a31 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -297,7 +297,8 @@ mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start #ifndef CUSTOM_STACK_WALK void -mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) { +mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboolean do_il_offset, gpointer user_data) +{ MonoDomain *domain = mono_domain_get (); MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); MonoLMF *lmf = jit_tls->lmf; @@ -310,11 +311,15 @@ mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_da mono_arch_flush_register_windows (); + if (start_ctx) { + memcpy (&ctx, start_ctx, sizeof (MonoContext)); + } else { #ifdef MONO_INIT_CONTEXT_FROM_CURRENT MONO_INIT_CONTEXT_FROM_CURRENT (&ctx); #else MONO_INIT_CONTEXT_FROM_CALLER (&ctx); #endif + } while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) { @@ -333,6 +338,12 @@ mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_da } } +void +mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data) +{ + mono_jit_walk_stack_from_ctx (func, NULL, do_il_offset, user_data); +} + MonoBoolean ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, MonoReflectionMethod **method, @@ -951,13 +962,23 @@ mono_free_altstack (MonoJitTlsData *tls) static gboolean print_stack_frame (MonoMethod *method, gint32 native_offset, gint32 il_offset, gboolean managed, gpointer data) { + FILE *stream = (FILE*)data; + if (method) { - if (il_offset != -1) - fprintf (stderr, "in [0x%lx] %s\n", (long)il_offset, mono_method_full_name (method, TRUE)); - else - fprintf (stderr, "in <0x%lx> %s\n", (long)native_offset, mono_method_full_name (method, TRUE)); + char *fname = mono_method_full_name (method, TRUE); + + if (il_offset != -1) { + gchar *source_location = mono_debug_source_location_from_address (method, native_offset, NULL, mono_domain_get ()); + + if (source_location) + fprintf (stream, "in %s (at %s)\n", fname, source_location); + else + fprintf (stream, "in %s [IL 0x%lx]\n", fname, (long)il_offset); + } else + fprintf (stream, "in %s <0x%lx>\n", fname, (long)native_offset); + g_free (fname); } else - fprintf (stderr, "in <%lx> <unknown>\n", (long)native_offset); + fprintf (stream, "in <unknown> <%lx>\n", (long)native_offset); return FALSE; } @@ -987,7 +1008,7 @@ mono_handle_native_sigsegv (void *ctx) fprintf (stderr, "Stacktrace:\n\n"); - mono_jit_walk_stack (print_stack_frame, TRUE, NULL); + mono_jit_walk_stack (print_stack_frame, TRUE, stderr); fflush (stderr); @@ -1012,3 +1033,40 @@ mono_handle_native_sigsegv (void *ctx) abort (); } + +/* + * mono_print_thread_dump: + * + * Print information about the current thread to stdout. + */ +void +mono_print_thread_dump (void *sigctx) +{ + MonoThread *thread = mono_thread_current (); +#ifndef CUSTOM_STACK_WALK + MonoContext ctx; +#endif + char *name; + GError *error = NULL; + + if (thread->name) { + name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error); + g_assert (!error); + fprintf (stdout, "\n\"%s\"", name); + g_free (name); + } + else + fprintf (stdout, "\n\"\""); + + fprintf (stdout, " tid=0x%p this=0x%p:\n", (gpointer)(gsize)thread->tid, thread); + +#ifdef CUSTOM_STACK_WALK + printf ("\t<Stack traces in thread dumps not supported on this platform>\n"); +#else + mono_arch_sigctx_to_monoctx (sigctx, &ctx); + + mono_jit_walk_stack_from_ctx (print_stack_frame, &ctx, TRUE, stdout); +#endif + + fflush (stdout); +} diff --git a/mono/mini/mini.c b/mono/mini/mini.c index b76e9d1ed35..231f8e77024 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -9976,10 +9976,17 @@ SIG_HANDLER_SIGNATURE (sigusr1_signal_handler) { gboolean running_managed; MonoException *exc; + MonoThread *thread = mono_thread_current (); void *ji; GET_CONTEXT; + if (thread->thread_dump_requested) { + thread->thread_dump_requested = FALSE; + + mono_print_thread_dump (ctx); + } + /* * FIXME: * This is an async signal, so the code below must not call anything which @@ -10006,12 +10013,19 @@ SIG_HANDLER_SIGNATURE (sigprof_signal_handler) static void SIG_HANDLER_SIGNATURE (sigquit_signal_handler) { - MonoException *exc; GET_CONTEXT; - exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT)."); - - mono_arch_handle_exception (ctx, exc, FALSE); + printf ("Full thread dump:\n"); + + mono_threads_request_thread_dump (); + + /* + * print_thread_dump () skips the current thread, since sending a signal + * to it would invoke the signal handler below the sigquit signal handler, + * and signal handlers don't create an lmf, so the stack walk could not + * be performed. + */ + mono_print_thread_dump (ctx); } static void diff --git a/mono/mini/mini.h b/mono/mini/mini.h index c9fa9ee79d3..91798891d2a 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -954,7 +954,9 @@ gpointer mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineTy gboolean mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only); void mono_handle_native_sigsegv (void *sigctx); +void mono_print_thread_dump (void *sigctx); void mono_jit_walk_stack (MonoStackWalk func, gboolean do_il_offset, gpointer user_data); +void mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *ctx, gboolean do_il_offset, gpointer user_data); void mono_setup_altstack (MonoJitTlsData *tls); void mono_free_altstack (MonoJitTlsData *tls); |