Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGonzalo Paniagua Javier <gonzalo.mono@gmail.com>2006-02-28 04:14:37 +0300
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>2006-02-28 04:14:37 +0300
commitc3733aa980f405b7e1f913d1e355c036ce139c5c (patch)
treef5eaf59cdebe2c927cd8356f396ccb066a8e3769
parent53c61e76eda2cb5432cd4073679fb634403d4477 (diff)
backport of the thread dump code by Zoltan
svn path=/branches/mono-1-1-13/mono/; revision=57364
-rw-r--r--mono/metadata/ChangeLog6
-rw-r--r--mono/metadata/object-internals.h2
-rw-r--r--mono/metadata/threads.c35
-rw-r--r--mono/metadata/threads.h2
-rw-r--r--mono/mini/ChangeLog4
-rw-r--r--mono/mini/mini-exceptions.c72
-rw-r--r--mono/mini/mini.c22
-rw-r--r--mono/mini/mini.h2
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);