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
return tpdomain;
}
+static MonoObject*
+try_invoke_perform_wait_callback (MonoObject** exc, MonoError *error)
+{
+ HANDLE_FUNCTION_ENTER ();
+ mono_error_init (error);
+ MonoObject *res = mono_runtime_try_invoke (mono_defaults.threadpool_perform_wait_callback_method, NULL, NULL, exc, error);
+ HANDLE_FUNCTION_RETURN_VAL (res);
+}
+
static void
worker_callback (gpointer unused)
{
if (mono_domain_set (tpdomain->domain, FALSE)) {
MonoObject *exc = NULL, *res;
- res = mono_runtime_try_invoke (mono_defaults.threadpool_perform_wait_callback_method, NULL, NULL, &exc, &error);
+ res = try_invoke_perform_wait_callback (&exc, &error);
if (exc || !mono_error_ok(&error)) {
if (exc == NULL)
exc = (MonoObject *) mono_error_convert_to_exception (&error);
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;