Skip to content

Commit

Permalink
2009-02-19 Rodrigo Kumpera <rkumpera@novell.com>
Browse files Browse the repository at this point in the history
	* 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
kumpera committed Feb 19, 2009
1 parent bd6746f commit 34feb34
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 11 deletions.
17 changes: 17 additions & 0 deletions mono/metadata/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
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.
Expand Down
4 changes: 3 additions & 1 deletion mono/metadata/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 3 additions & 0 deletions mono/metadata/appdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);

Expand Down
13 changes: 7 additions & 6 deletions mono/metadata/domain-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions mono/metadata/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down
5 changes: 3 additions & 2 deletions mono/metadata/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
}

/**
Expand Down
120 changes: 120 additions & 0 deletions mono/metadata/lock-tracer.c
Original file line number Diff line number Diff line change
@@ -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
48 changes: 48 additions & 0 deletions mono/metadata/lock-tracer.h
Original file line number Diff line number Diff line change
@@ -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.