#else
static inline void
-mono_handle_check_in_critical_section (const gchar* file, const gint lineno)
+mono_handle_check_in_critical_section ()
{
- MonoThreadInfo *info = (MonoThreadInfo*) mono_thread_info_current_unchecked ();
- if (info && !info->inside_critical_region)
- g_error ("Assertion at %s:%d: mono_handle_check_in_critical_section failed", file, lineno);
+ MONO_REQ_GC_UNSAFE_MODE;
}
-#define mono_handle_obj(handle) (mono_handle_check_in_critical_section (__FILE__, __LINE__), (handle)->obj)
+#define mono_handle_obj(handle) (mono_handle_check_in_critical_section (), (handle)->obj)
-#define mono_handle_assign(handle,rawptr) do { mono_handle_check_in_critical_section (__FILE__, __LINE__); (handle)->obj = (rawptr); } while (0)
+#define mono_handle_assign(handle,rawptr) do { mono_handle_check_in_critical_section (); (handle)->obj = (rawptr); } while (0)
#endif
#define MONO_HANDLE_SETREF(handle,fieldname,value) \
do { \
MonoHandle __value = (MonoHandle) (value); \
- MONO_PREPARE_CRITICAL; \
+ MONO_PREPARE_GC_CRITICAL_REGION; \
MONO_OBJECT_SETREF (mono_handle_obj ((handle)), fieldname, mono_handle_obj (__value)); \
- MONO_FINISH_CRITICAL; \
+ MONO_FINISH_GC_CRITICAL_REGION; \
} while (0)
#define MONO_HANDLE_SET(handle,fieldname,value) \
do { \
- MONO_PREPARE_CRITICAL; \
+ MONO_PREPARE_GC_CRITICAL_REGION; \
mono_handle_obj ((handle))->fieldname = (value); \
- MONO_FINISH_CRITICAL; \
+ MONO_FINISH_GC_CRITICAL_REGION; \
} while (0)
#define MONO_HANDLE_ARRAY_SETREF(handle,index,value) \
do { \
MonoHandle __value = (MonoHandle) (value); \
- MONO_PREPARE_CRITICAL; \
+ MONO_PREPARE_GC_CRITICAL_REGION; \
mono_array_setref (mono_handle_obj ((handle)), (index), mono_handle_obj (__value)); \
- MONO_FINISH_CRITICAL; \
+ MONO_FINISH_GC_CRITICAL_REGION; \
} while (0)
#define MONO_HANDLE_ARRAY_SET(handle,type,index,value) \
do { \
- MONO_PREPARE_CRITICAL; \
+ MONO_PREPARE_GC_CRITICAL_REGION; \
mono_array_set (mono_handle_obj ((handle)), (type), (index), (value)); \
- MONO_FINISH_CRITICAL; \
+ MONO_FINISH_GC_CRITICAL_REGION; \
} while (0)
/* handle arena specific functions */
typedef struct {
GPtrArray *transitions;
+ gboolean in_gc_critical_region;
} CheckState;
typedef struct {
}
}
+void *
+critical_gc_region_begin(void)
+{
+ CheckState *state = get_state ();
+ state->in_gc_critical_region = TRUE;
+ return state;
+}
+
+
+void
+critical_gc_region_end(void* token)
+{
+ CheckState *state = get_state();
+ g_assert (state == token);
+ state->in_gc_critical_region = FALSE;
+}
+
+void
+assert_not_in_gc_critical_region(void)
+{
+ CheckState *state = get_state();
+ if (state->in_gc_critical_region) {
+ MonoThreadInfo *cur = mono_thread_info_current();
+ state = mono_thread_info_current_state(cur);
+ assertion_fail("Expected GC Unsafe mode, but was in %s state", mono_thread_state_name(state));
+ }
+}
+
// check_metadata_store et al: The goal of these functions is to verify that if there is a pointer from one mempool into
// another, that the pointed-to memory is protected by the reference count mechanism for MonoImages.
//
assert_gc_neutral_mode (); \
} while (0);
+/* In a GC critical region, the thread is not allowed to switch to GC safe mode.
+ * For example if the thread is about to call a method that will manipulate managed objects.
+ * The GC critical region must only occur in unsafe mode.
+ */
+#define MONO_PREPARE_GC_CRITICAL_REGION \
+ MON_REQ_GC_UNSAFE_MODE \
+ do { \
+ void* __critical_gc_region_cookie = critical_gc_region_begin()
+
+#define MONO_FINISH_GC_CRITICAL_REGION \
+ critical_gc_region_end(__critical_gc_region_cookie); \
+ } while(0)
+
+/* Verify that the thread is not currently in a GC critical region. */
+#define MONO_REQ_GC_NOT_CRITICAL do { \
+ assert_not_in_gc_critical_region(); \
+ } while(0)
+
// Use when writing a pointer from one image or imageset to another.
#define CHECKED_METADATA_WRITE_PTR(ptr, val) do { \
check_metadata_store (&(ptr), (val)); \
void assert_gc_unsafe_mode (void);
void assert_gc_neutral_mode (void);
+void* critical_gc_region_begin(void);
+void critical_gc_region_end(void* token);
+void assert_not_in_gc_critical_region(void);
+
void checked_build_init (void);
void checked_build_thread_transition(const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta);
#define MONO_REQ_API_ENTRYPOINT
#define MONO_REQ_RUNTIME_ENTRYPOINT
+#define MONO_PREPARE_GC_CRITICAL_REGION
+#define MONO_FINISH_GC_CRITICAL_REGION
+
+#define MONO_REQ_GC_NOT_CRITICAL
+
+
#define CHECKED_MONO_INIT()
#define CHECKED_BUILD_THREAD_TRANSITION(transition, info, from_state, suspend_count, next_state, suspend_count_delta)
#include <config.h>
#include <glib.h>
+#include "checked-build.h"
+
G_BEGIN_DECLS
/* JIT specific interface */
}
#define MONO_PREPARE_BLOCKING \
+ MONO_REQ_GC_NOT_CRITICAL; \
do { \
gpointer __dummy; \
gpointer __blocking_cookie = mono_threads_prepare_blocking (&__dummy)