return res;
}
+ class Worker {
+ volatile bool stop = false;
+ public void Stop () {
+ stop = true;
+ }
+
+ public void Work () {
+ while (!stop) {
+ for (int i = 0; i < 100; i++) {
+ var a = new double[80000];
+ Thread.Sleep (0);
+ }
+ GC.Collect ();
+ }
+ }
+ }
+
+ public static int test_43_thread_attach_detach_contested () {
+ // Test plan: we want to create a race between the GC
+ // and native threads detaching. When a native thread
+ // calls a managed delegate, it's attached to the
+ // runtime by the wrapper. It is detached when the
+ // thread is destroyed and the TLS key destructor for
+ // MonoThreadInfo runs. That destructor wants to take
+ // the GC lock. So we create a lot of native threads
+ // while at the same time running a worker that
+ // allocates garbage and invokes the collector.
+ var w = new Worker ();
+ Thread t = new Thread(new ThreadStart (w.Work));
+ t.Start ();
+
+ for (int count = 0; count < 500; count++) {
+ int res = mono_test_marshal_thread_attach (delegate (int i) {
+ Thread.Sleep (0);
+ return i + 1;
+ });
+ }
+ Thread.Sleep (1000);
+ w.Stop ();
+ t.Join ();
+ return 43;
+
+ }
/*
* Appdomain save/restore
*/
mono_threads_transition_state_poll (MonoThreadInfo *info)
{
int raw_state, cur_state, suspend_count;
- g_assert (info == mono_thread_info_current ());
+ g_assert (mono_thread_info_is_current (info));
retry_state_change:
UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
info = (MonoThreadInfo *) arg;
g_assert (info);
+ g_assert (mono_thread_info_is_current (info));
+ g_assert (mono_thread_info_is_live (info));
small_id = info->small_id;
return FALSE;
}
+#ifndef HOST_WIN32
+static void
+thread_info_key_dtor (void *arg)
+{
+ /* Put the MonoThreadInfo back for the duration of the
+ * unregister code. In some circumstances the thread needs to
+ * take the GC lock which may block which requires a coop
+ * state transition. */
+ mono_native_tls_set_value (thread_info_key, arg);
+ unregister_thread (arg);
+ mono_native_tls_set_value (thread_info_key, NULL);
+}
+#endif
+
void
mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
{
res = mono_native_tls_alloc (&thread_info_key, NULL);
res = mono_native_tls_alloc (&thread_exited_key, NULL);
#else
- res = mono_native_tls_alloc (&thread_info_key, (void *) unregister_thread);
+ res = mono_native_tls_alloc (&thread_info_key, (void *) thread_info_key_dtor);
res = mono_native_tls_alloc (&thread_exited_key, (void *) thread_exited_dtor);
#endif
mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
{
g_assert (info);
+ g_assert (mono_thread_info_is_current (info));
+ g_assert (mono_thread_info_is_live (info));
MONO_ENTER_GC_SAFE_WITH_INFO(info);