[Mono.Runtime.Tests] Exclude simd tests
[mono-project.git] / mono / metadata / lock-tracer.c
blob302c29f2c9aa8a787f6b847eb6c26b697644e598
1 /**
2 * \file
3 * Runtime simple lock tracer
5 * Authors:
6 * Rodrigo Kumpera (rkumpera@novell.com)
7 *
8 */
10 #include <config.h>
11 #include <stdio.h>
12 #include <string.h>
14 #include <sys/types.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
20 #ifdef HAVE_EXECINFO_H
21 #include <execinfo.h>
22 #endif
24 #include <mono/utils/mono-compiler.h>
25 #include <mono/utils/mono-threads.h>
27 #include "lock-tracer.h"
30 * This is a very simple lock trace implementation. It can be used to verify that the runtime is
31 * correctly following all locking rules.
33 * To log more kind of locks just do the following:
34 * - add an entry into the RuntimeLocks enum
35 * - change mono_os_mutex_lock(mutex) to mono_locks_os_acquire (mutex, LockName)
36 * - change mono_os_mutex_unlock(mutex) to mono_locks_os_release (mutex, LockName)
37 * - change mono_coop_mutex_lock(mutex) to mono_locks_coop_acquire (mutex, LockName)
38 * - change mono_coop_mutex_unlock(mutex) to mono_locks_coop_release (mutex, LockName)
39 * - change the decoder to understand the new lock kind.
41 * TODO:
42 * - Use unbuffered IO without fsync
43 * - Switch to a binary log format
44 * - Enable tracing of more runtime locks
45 * - Add lock check assertions (must_not_hold_any_lock_but, must_hold_lock, etc)
46 * This should be used to verify methods that expect that a given lock is held at entrypoint, for example.
48 * To use the trace, define LOCK_TRACER in lock-trace.h and when running mono define MONO_ENABLE_LOCK_TRACER.
49 * This will produce a locks.ZZZ where ZZZ is the pid of the mono process.
50 * Use the decoder to verify the result.
53 #ifdef LOCK_TRACER
55 #ifdef TARGET_OSX
56 #include <dlfcn.h>
57 #endif
59 static FILE *trace_file;
60 static mono_mutex_t tracer_lock;
61 static size_t base_address;
63 typedef enum {
64 RECORD_MUST_NOT_HOLD_ANY,
65 RECORD_MUST_NOT_HOLD_ONE,
66 RECORD_MUST_HOLD_ONE,
67 RECORD_LOCK_ACQUIRED,
68 RECORD_LOCK_RELEASED
69 } RecordType;
71 void
72 mono_locks_tracer_init (void)
74 Dl_info info;
75 int res;
76 char *name;
77 mono_os_mutex_init_recursive (&tracer_lock);
79 if (!g_hasenv ("MONO_ENABLE_LOCK_TRACER"))
80 return;
82 name = g_strdup_printf ("locks.%d", getpid ());
83 trace_file = fopen (name, "w+");
84 g_free (name);
86 #ifdef TARGET_OSX
87 res = dladdr ((void*)&mono_locks_tracer_init, &info);
88 /* The 0x1000 offset was found by empirically trying it. */
89 if (res)
90 base_address = (size_t)info.dli_fbase - 0x1000;
91 #endif
95 #ifdef HAVE_EXECINFO_H
97 static int
98 mono_backtrace (gpointer array[], int traces)
100 return backtrace (array, traces);
103 #else
105 static int
106 mono_backtrace (gpointer array[], int traces)
108 return 0;
111 #endif
113 static void
114 add_record (RecordType record_kind, RuntimeLocks kind, gpointer lock)
116 int i = 0;
117 const int no_frames = 6;
118 gpointer frames[no_frames];
120 char *msg;
121 if (!trace_file)
122 return;
124 memset (frames, 0, sizeof (gpointer) * no_frames);
125 mono_backtrace (frames, no_frames);
126 for (i = 0; i < no_frames; ++i)
127 frames [i] = (gpointer)((size_t)frames[i] - base_address);
129 /*We only dump 5 frames, which should be more than enough to most analysis.*/
130 msg = g_strdup_printf ("%x,%d,%d,%p,%p,%p,%p,%p,%p\n", (guint32)mono_native_thread_id_get (), record_kind, kind, lock, frames [1], frames [2], frames [3], frames [4], frames [5]);
131 fwrite (msg, strlen (msg), 1, trace_file);
132 fflush (trace_file);
133 g_free (msg);
136 void
137 mono_locks_lock_acquired (RuntimeLocks kind, gpointer lock)
139 add_record (RECORD_LOCK_ACQUIRED, kind, lock);
142 void
143 mono_locks_lock_released (RuntimeLocks kind, gpointer lock)
145 add_record (RECORD_LOCK_RELEASED, kind, lock);
147 #else
149 MONO_EMPTY_SOURCE_FILE (lock_tracer);
150 #endif /* LOCK_TRACER */