Permalink
Browse files

2009-02-19 Rodrigo Kumpera <rkumpera@novell.com>

	* Makefile.am: Add lock-tracer.h and lock-trace.c.

	* appdomain.c: Call the tracer init function.

 	* domain-internals.h: Enable the tracer for the domain locks.

	* image.c: Enable the tracer for image locks.

	* loader.c: Enable the trace for the loader lock.

	* lock-tracer.h:
	* lock-tracer.c: Initial implementation of the lock trace utility.
	The tracer requires a compile time define to be enabled and a env var
	to be enabled at runtime.

svn path=/trunk/mono/; revision=127476
  • Loading branch information...
1 parent bd6746f commit 34feb3493b8c3b9723fb9302b7c586e1bf4c8db8 @kumpera kumpera committed Feb 19, 2009
View
@@ -1,5 +1,22 @@
2009-02-19 Rodrigo Kumpera <rkumpera@novell.com>
+ * Makefile.am: Add lock-tracer.h and lock-trace.c.
+
+ * appdomain.c: Call the tracer init function.
+
+ * domain-internals.h: Enable the tracer for the domain locks.
+
+ * image.c: Enable the tracer for image locks.
+
+ * loader.c: Enable the trace for the loader lock.
+
+ * lock-tracer.h:
+ * lock-tracer.c: Initial implementation of the lock trace utility.
+ The tracer requires a compile time define to be enabled and a env var
+ to be enabled at runtime.
+
+2009-02-19 Rodrigo Kumpera <rkumpera@novell.com>
+
* domain.c (mono_domain_code_foreach): Improve documentation.
2009-02-19 Rodrigo Kumpera <rkumpera@novell.com>
@@ -143,7 +143,9 @@ libmonoruntime_la_SOURCES = \
debug-helpers.c \
generic-sharing.c \
mempool-internals.h \
- metadata-verify.c
+ metadata-verify.c \
+ lock-tracer.c \
+ lock-tracer.h
libmonoruntime_static_la_SOURCES = $(libmonoruntime_la_SOURCES)
@@ -47,6 +47,7 @@
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/attach.h>
#include <mono/metadata/file-io.h>
+#include <mono/metadata/lock-tracer.h>
#include <mono/utils/mono-uri.h>
#include <mono/utils/mono-logger.h>
#include <mono/utils/mono-path.h>
@@ -236,6 +237,8 @@ mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
mono_attach_init ();
+ mono_locks_tracer_init ();
+
/* mscorlib is loaded before we install the load hook */
mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
@@ -5,6 +5,7 @@
#define __MONO_METADATA_DOMAIN_INTERNALS_H__
#include <mono/metadata/appdomain.h>
+#include <mono/metadata/lock-tracer.h>
#include <mono/utils/mono-codeman.h>
#include <mono/utils/mono-hash.h>
#include <mono/utils/mono-compiler.h>
@@ -249,12 +250,12 @@ typedef struct {
const AssemblyVersionSet version_sets [2];
} MonoRuntimeInfo;
-#define mono_domain_lock(domain) EnterCriticalSection(&(domain)->lock)
-#define mono_domain_unlock(domain) LeaveCriticalSection(&(domain)->lock)
-#define mono_domain_assemblies_lock(domain) EnterCriticalSection(&(domain)->assemblies_lock)
-#define mono_domain_assemblies_unlock(domain) LeaveCriticalSection(&(domain)->assemblies_lock)
-#define mono_domain_jit_code_hash_lock(domain) EnterCriticalSection(&(domain)->jit_code_hash_lock)
-#define mono_domain_jit_code_hash_unlock(domain) LeaveCriticalSection(&(domain)->jit_code_hash_lock)
+#define mono_domain_lock(domain) mono_locks_acquire(&(domain)->lock, DomainLock)
+#define mono_domain_unlock(domain) mono_locks_release(&(domain)->lock, DomainLock)
+#define mono_domain_assemblies_lock(domain) mono_locks_acquire(&(domain)->assemblies_lock, DomainAssembliesLock)
+#define mono_domain_assemblies_unlock(domain) mono_locks_release(&(domain)->assemblies_lock, DomainAssembliesLock)
+#define mono_domain_jit_code_hash_lock(domain) mono_locks_acquire(&(domain)->jit_code_hash_lock, DomainJitCodeHashLock)
+#define mono_domain_jit_code_hash_unlock(domain) mono_locks_release(&(domain)->jit_code_hash_lock, DomainJitCodeHashLock)
typedef MonoDomain* (*MonoLoadFunc) (const char *filename, const char *runtime_version);
View
@@ -2060,13 +2060,13 @@ g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
void
mono_image_lock (MonoImage *image)
{
- EnterCriticalSection (&image->lock);
+ mono_locks_acquire (&image->lock, ImageDataLock);
}
void
mono_image_unlock (MonoImage *image)
{
- LeaveCriticalSection (&image->lock);
+ mono_locks_release (&image->lock, ImageDataLock);
}
View
@@ -36,6 +36,7 @@
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/exception.h>
#include <mono/metadata/marshal.h>
+#include <mono/metadata/lock-tracer.h>
#include <mono/utils/mono-logger.h>
#include <mono/utils/mono-dl.h>
#include <mono/utils/mono-membar.h>
@@ -1948,13 +1949,13 @@ mono_method_get_last_managed (void)
void
mono_loader_lock (void)
{
- EnterCriticalSection (&loader_mutex);
+ mono_locks_acquire (&loader_mutex, LoaderLock);
}
void
mono_loader_unlock (void)
{
- LeaveCriticalSection (&loader_mutex);
+ mono_locks_release (&loader_mutex, LoaderLock);
}
/**
View
@@ -0,0 +1,120 @@
+/*
+ * lock-tracer.c: Runtime simple lock tracer
+ *
+ * Authors:
+ * Rodrigo Kumpera (rkumpera@novell.com)
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+
+#include <mono/io-layer/io-layer.h>
+
+#include "lock-tracer.h"
+
+/*
+ * This is a very simple lock trace implementation. It can be used to verify that the runtime is
+ * correctly following all locking rules.
+ *
+ * To log more kind of locks just do the following:
+ * - add an entry into the RuntimeLocks enum
+ * - change EnterCriticalSection(mutex) to mono_locks_acquire (mutex, LockName)
+ * - change LeaveCriticalSection to mono_locks_release (mutex, LockName)
+ * - change the decoder to understand the new lock kind.
+ *
+ * TODO:
+ * - Use unbuffered IO without fsync
+ * - Switch to a binary log format
+ * - Enable tracing of more runtime locks
+ * - Add lock check assertions (must_not_hold_any_lock_but, must_hold_lock, etc)
+ * This should be used to verify methods that expect that a given lock is held at entrypoint, for example.
+ *
+ * To use the trace, define LOCK_TRACER in lock-trace.h and when running mono define MONO_ENABLE_LOCK_TRACER.
+ * This will produce a locks.ZZZ where ZZZ is the pid of the mono process.
+ * Use the decoder to verify the result.
+ */
+
+#ifdef LOCK_TRACER
+
+static FILE *trace_file;
+static CRITICAL_SECTION tracer_lock;
+
+typedef enum {
+ RECORD_MUST_NOT_HOLD_ANY,
+ RECORD_MUST_NOT_HOLD_ONE,
+ RECORD_MUST_HOLD_ONE,
+ RECORD_LOCK_ACQUIRED,
+ RECORD_LOCK_RELEASED
+} RecordType;
+
+void
+mono_locks_tracer_init (void)
+{
+ char *name;
+ InitializeCriticalSection (&tracer_lock);
+ if (!getenv ("MONO_ENABLE_LOCK_TRACER"))
+ return;
+ name = g_strdup_printf ("locks.%d", getpid ());
+ trace_file = fopen (name, "w+");
+ g_free (name);
+}
+
+
+#ifdef HAVE_EXECINFO_H
+
+static int
+mono_backtrace (gpointer array[], int traces)
+{
+ return backtrace (array, traces);
+}
+
+#else
+
+static int
+mono_backtrace (gpointer array[], int traces)
+{
+ return 0;
+}
+
+#endif
+
+static void
+add_record (RecordType record_kind, RuntimeLocks kind, gpointer lock)
+{
+ gpointer frames[10];
+ char *msg;
+ if (!trace_file)
+ return;
+
+ memset (frames, 0, sizeof (gpointer));
+ mono_backtrace (frames, 6);
+
+ /*We only dump 5 frames, which should be more than enough to most analysis.*/
+ msg = g_strdup_printf ("%x,%d,%d,%p,%p,%p,%p,%p,%p\n", (guint32)GetCurrentThreadId (), record_kind, kind, lock, frames [1], frames [2], frames [3], frames [4], frames [5]);
+ fwrite (msg, strlen (msg), 1, trace_file);
+ fflush (trace_file);
+ g_free (msg);
+}
+
+void
+mono_locks_lock_acquired (RuntimeLocks kind, gpointer lock)
+{
+ add_record (RECORD_LOCK_ACQUIRED, kind, lock);
+}
+
+void
+mono_locks_lock_released (RuntimeLocks kind, gpointer lock)
+{
+ add_record (RECORD_LOCK_RELEASED, kind, lock);
+}
+
+#endif
@@ -0,0 +1,48 @@
+#ifndef __MONO_METADATA_LOCK_TRACER_H__
+#define __MONO_METADATA_LOCK_TRACER_H__
+
+/*This is a private header*/
+#include <glib.h>
+
+#include "mono/utils/mono-compiler.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ InvalidLock = 0,
+ LoaderLock,
+ ImageDataLock,
+ DomainLock,
+ DomainAssembliesLock,
+ DomainJitCodeHashLock,
+} RuntimeLocks;
+
+#ifdef LOCK_TRACER
+
+void mono_locks_tracer_init (void) MONO_INTERNAL;
+
+void mono_locks_lock_acquired (RuntimeLocks kind, gpointer lock) MONO_INTERNAL;
+void mono_locks_lock_released (RuntimeLocks kind, gpointer lock) MONO_INTERNAL;
+
+#else
+
+#define mono_locks_tracer_init() do {} while (0)
+
+#define mono_locks_lock_acquired(__UNUSED0, __UNUSED1) do {} while (0)
+#define mono_locks_lock_released(__UNUSED0, __UNUSED1) do {} while (0)
+
+#endif
+
+#define mono_locks_acquire(LOCK, NAME) do { \
+ EnterCriticalSection (LOCK); \
+ mono_locks_lock_acquired (NAME, LOCK); \
+} while (0)
+
+#define mono_locks_release(LOCK, NAME) do { \
+ mono_locks_lock_released (NAME, LOCK); \
+ LeaveCriticalSection (LOCK); \
+} while (0)
+
+G_END_DECLS
+
+#endif /* __MONO_METADATA_LOCK_TRACER_H__ */

0 comments on commit 34feb34

Please sign in to comment.