mono_coop_mutex_destroy (&threadpool->threads_lock);
mono_coop_cond_destroy (&threadpool->threads_exit_cond);
- g_free (threadpool);
+ /* We cannot free the threadpool, because there is a race
+ * on shutdown where a managed thread may request a new
+ * threadpool thread, but we already destroyed the
+ * threadpool. So to avoid a use-after-free, we simply do
+ * not free the threadpool, as we won't be able to access
+ * the threadpool anyway because the ref count will be 0 */
+ // g_free (threadpool);
}
static void
mono_coop_mutex_unlock (&threadpool->threads_lock);
+#if 0
/* give a chance to the other threads to exit */
mono_thread_info_yield ();
}
mono_coop_mutex_unlock (&threadpool->threads_lock);
+#endif
mono_threadpool_worker_cleanup (threadpool->worker);
g_assert(wait_event);
MonoWaitHandle *wait_handle = mono_wait_handle_new (mono_object_domain (ares), wait_event, error);
if (!is_ok (error)) {
- CloseHandle (wait_event);
+ mono_w32event_close (wait_event);
return NULL;
}
MONO_OBJECT_SETREF (ares, handle, (MonoObject*) wait_handle);
if (mono_domain_is_unloading (domain))
return FALSE;
+ if (!mono_refcount_tryinc (threadpool)) {
+ /* threadpool has been destroyed, we are shutting down */
+ return FALSE;
+ }
+
domains_lock ();
/* synchronize with mono_threadpool_remove_domain_jobs */
if (mono_domain_is_unloading (domain)) {
domains_unlock ();
+ mono_refcount_dec (threadpool);
return FALSE;
}
domains_unlock ();
COUNTER_ATOMIC (threadpool, counter, {
- if (counter._.starting == 16)
+ if (counter._.starting == 16) {
+ mono_refcount_dec (threadpool);
return TRUE;
+ }
counter._.starting ++;
});
- mono_refcount_inc (threadpool);
-
mono_threadpool_worker_enqueue (threadpool->worker, worker_callback, NULL);
return TRUE;