user ();
type_load ();
regress ();
+ gc_suspend ();
if (args.Length > 0 && args [0] == "domain-test")
/* This takes a lot of time, so execute it conditionally */
domains ();
ref_emit ();
if (args.Length > 0 && args [0] == "frames-in-native")
frames_in_native ();
- if (args.Length >0 && args [0] == "invoke-single-threaded")
+ if (args.Length > 0 && args [0] == "invoke-single-threaded")
new Tests ().invoke_single_threaded ();
return 3;
}
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void regress_2755_3 (int sum) {
}
+
+ static object gc_suspend_field;
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ static unsafe void set_gc_suspend_field () {
+ set_gc_suspend_field_2 ();
+ // Clear stack
+ int* buffer = stackalloc int [4096];
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ static void set_gc_suspend_field_2 () {
+ gc_suspend_field = new object ();
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ static void gc_suspend_1 () {
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static void gc_suspend_invoke () {
+ gc_suspend_field = null;
+ GC.Collect ();
+ GC.WaitForPendingFinalizers ();
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static void gc_suspend () {
+ set_gc_suspend_field ();
+ gc_suspend_1 ();
+ }
}
class TypeLoadClass {
vm = null;
}
#endif
+
+ [Test]
+ public void GCWhileSuspended () {
+ // Check that objects are kept alive during suspensions
+ Event e = run_until ("gc_suspend_1");
+
+ MethodMirror m = entry_point.DeclaringType.GetMethod ("gc_suspend_invoke");
+
+ var o = entry_point.DeclaringType.GetValue (entry_point.DeclaringType.GetField ("gc_suspend_field")) as ObjectMirror;
+ //Console.WriteLine (o);
+
+ StackFrame frame = e.Thread.GetFrames () [0];
+ TypeMirror t = frame.Method.DeclaringType;
+ for (int i = 0; i < 10; ++i)
+ t.InvokeMethod (e.Thread, m, new Value [] { });
+
+ // This throws an exception if the object is collected
+ long addr = o.Address;
+
+ var o2 = entry_point.DeclaringType.GetValue (entry_point.DeclaringType.GetField ("gc_suspend_field")) as ObjectMirror;
+ Assert.IsNull (o2);
+ }
}
-}
\ No newline at end of file
+}
/* A hash table containing all active domains */
static GHashTable *domains;
+/* The number of times the runtime is suspended */
+static gint32 suspend_count;
+
static void transport_init (void);
static void transport_connect (const char *address);
static gboolean transport_handshake (void);
}
static GHashTable *obj_to_objref;
+static MonoGHashTable *suspended_objs;
/*
* Return an ObjRef for OBJ.
mono_loader_lock ();
- if (!obj_to_objref)
+ if (!obj_to_objref) {
obj_to_objref = g_hash_table_new (NULL, NULL);
+ suspended_objs = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_GC);
+ MONO_GC_REGISTER_ROOT_FIXED (suspended_objs);
+ }
+
+ if (suspend_count) {
+ /*
+ * Have to keep object refs created during suspensions alive for the duration of the suspension, so GCs during invokes don't collect them.
+ */
+ mono_g_hash_table_insert (suspended_objs, obj, NULL);
+ }
/* FIXME: The tables can grow indefinitely */
return ref;
}
+static gboolean
+true_pred (gpointer key, gpointer value, gpointer user_data)
+{
+ return TRUE;
+}
+
+static void
+clear_suspended_objs (void)
+{
+ mono_loader_lock ();
+ mono_g_hash_table_foreach_remove (suspended_objs, true_pred, NULL);
+ mono_loader_unlock ();
+}
+
static inline int
get_objid (MonoObject *obj)
{
mono_thread_state_init_from_current (&tls->context);
}
-/* The number of times the runtime is suspended */
-static gint32 suspend_count;
-
/* Number of threads suspended */
/*
* If this is equal to the size of thread_to_tls, the runtime is considered
if (suspend_count == 0)
return ERR_NOT_SUSPENDED;
resume_vm ();
+ clear_suspended_objs ();
break;
case CMD_VM_DISPOSE:
/* Clear all event requests */