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
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;
#define mono_refcount_init(v,destructor) do { mono_refcount_initialize (&(v)->ref, (destructor)); } while (0)
#define mono_refcount_inc(v) (mono_refcount_increment (&(v)->ref),(v))
+#define mono_refcount_tryinc(v) (mono_refcount_tryincrement (&(v)->ref))
#define mono_refcount_dec(v) do { mono_refcount_decrement (&(v)->ref); } while (0)
static inline void
refcount->destructor = destructor;
}
-static inline void
-mono_refcount_increment (MonoRefCount *refcount)
+static inline gboolean
+mono_refcount_tryincrement (MonoRefCount *refcount)
{
guint32 oldref, newref;
do {
oldref = refcount->ref;
if (oldref == 0)
- g_error ("%s: cannot increment a ref with value 0", __func__);
+ return FALSE;
newref = oldref + 1;
} while (InterlockedCompareExchange ((gint32*) &refcount->ref, newref, oldref) != oldref);
+
+ return TRUE;
+}
+
+static inline void
+mono_refcount_increment (MonoRefCount *refcount)
+{
+ if (!mono_refcount_tryincrement (refcount))
+ g_error ("%s: cannot increment a ref with value 0", __func__);
}
static inline void