2 * checked-build.c: Expensive asserts used when mono is built with --with-checked-build=yes
5 * Rodrigo Kumpera (kumpera@gmail.com)
12 #include <mono/utils/checked-build.h>
13 #include <mono/utils/mono-threads.h>
14 #include <mono/utils/mono-tls.h>
17 #define MAX_NATIVE_BT 6
18 #define MAX_NATIVE_BT_PROBE (MAX_NATIVE_BT + 5)
19 #define MAX_TRANSITIONS 3
22 #ifdef HAVE_BACKTRACE_SYMBOLS
25 //XXX We should collect just the IPs and lazily symbolificate them.
27 collect_backtrace (gpointer out_data[])
29 return backtrace (out_data, MAX_NATIVE_BT_PROBE);
33 translate_backtrace (gpointer native_trace[], int size)
35 char **names = backtrace_symbols (native_trace, size);
36 GString* bt = g_string_sized_new (100);
40 //Figure out the cut point of useless backtraces
41 //We'll skip up to the caller of checked_build_thread_transition
42 for (i = 0; i < size; ++i) {
43 if (strstr (names [i], "checked_build_thread_transition")) {
51 for (i = j; i < size; ++i) {
52 if (i - j <= MAX_NATIVE_BT)
53 g_string_append_printf (bt, "\tat %s\n", names [i]);
57 return g_string_free (bt, FALSE);
63 collect_backtrace (gpointer out_data[])
69 translate_backtrace (gpointer native_trace[], int size)
71 return g_strdup ("\tno backtrace available\n");
78 GPtrArray *transitions;
83 int from_state, next_state, suspend_count, suspend_count_delta, size;
84 gpointer backtrace [MAX_NATIVE_BT_PROBE];
87 static MonoNativeTlsKey thread_status;
90 checked_build_init (void)
92 mono_native_tls_alloc (&thread_status, NULL);
98 CheckState *state = mono_native_tls_get_value (thread_status);
100 state = g_new0 (CheckState, 1);
101 state->transitions = g_ptr_array_new ();
102 mono_native_tls_set_value (thread_status, state);
109 free_transition (ThreadTransition *t)
115 checked_build_thread_transition (const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta)
117 MonoThreadInfo *cur = mono_thread_info_current_unchecked ();
118 CheckState *state = get_state ();
119 /* We currently don't record external changes as those are hard to reason about. */
123 if (state->transitions->len >= MAX_TRANSITIONS)
124 free_transition (g_ptr_array_remove_index (state->transitions, 0));
126 ThreadTransition *t = g_new0 (ThreadTransition, 1);
127 t->name = transition;
128 t->from_state = from_state;
129 t->next_state = next_state;
130 t->suspend_count = suspend_count;
131 t->suspend_count_delta = suspend_count_delta;
132 t->size = collect_backtrace (t->backtrace);
133 g_ptr_array_add (state->transitions, t);
137 assertion_fail (const char *msg, ...)
140 GString* err = g_string_sized_new (100);
141 CheckState *state = get_state ();
143 g_string_append_printf (err, "Assertion failure in thread %p due to: ", mono_native_thread_id_get ());
146 va_start (args, msg);
147 g_string_append_vprintf (err, msg, args);
150 g_string_append_printf (err, "\nLast %d state transitions: (most recent first)\n", state->transitions->len);
152 for (i = state->transitions->len - 1; i >= 0; --i) {
153 ThreadTransition *t = state->transitions->pdata [i];
154 char *bt = translate_backtrace (t->backtrace, t->size);
155 g_string_append_printf (err, "[%s] %s -> %s (%d) %s%d at:\n%s",
157 mono_thread_state_name (t->from_state),
158 mono_thread_state_name (t->next_state),
160 t->suspend_count_delta > 0 ? "+" : "", //I'd like to see this sort of values: -1, 0, +1
161 t->suspend_count_delta,
167 g_string_free (err, TRUE);
171 assert_gc_safe_mode (void)
173 MonoThreadInfo *cur = mono_thread_info_current ();
177 assertion_fail ("Expected GC Safe mode but thread is not attached");
179 switch (state = mono_thread_info_current_state (cur)) {
181 case STATE_BLOCKING_AND_SUSPENDED:
184 assertion_fail ("Expected GC Safe mode but was in %s state", mono_thread_state_name (state));
189 assert_gc_unsafe_mode (void)
191 MonoThreadInfo *cur = mono_thread_info_current ();
195 assertion_fail ("Expected GC Unsafe mode but thread is not attached");
197 switch (state = mono_thread_info_current_state (cur)) {
199 case STATE_ASYNC_SUSPEND_REQUESTED:
200 case STATE_SELF_SUSPEND_REQUESTED:
203 assertion_fail ("Expected GC Unsafe mode but was in %s state", mono_thread_state_name (state));
208 assert_gc_neutral_mode (void)
210 MonoThreadInfo *cur = mono_thread_info_current ();
214 assertion_fail ("Expected GC Neutral mode but thread is not attached");
216 switch (state = mono_thread_info_current_state (cur)) {
218 case STATE_ASYNC_SUSPEND_REQUESTED:
219 case STATE_SELF_SUSPEND_REQUESTED:
221 case STATE_BLOCKING_AND_SUSPENDED:
224 assertion_fail ("Expected GC Neutral mode but was in %s state", mono_thread_state_name (state));
228 #endif /* CHECKED_BUILD */