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_lock (&threadpool->threads_lock);
for (;;) {
- ThreadPoolCounter counter;
-
- counter = COUNTER_READ (threadpool);
- if (counter._.working == 0)
+ if (threadpool->threads->len == 0)
break;
- if (counter._.working == 1) {
- if (threadpool->threads->len == 1 && g_ptr_array_index (threadpool->threads, 0) == current) {
- /* We are waiting on ourselves */
- break;
- }
+ if (threadpool->threads->len == 1 && g_ptr_array_index (threadpool->threads, 0) == current) {
+ /* We are waiting on ourselves */
+ break;
}
mono_coop_cond_wait (&threadpool->threads_exit_cond, &threadpool->threads_lock);
}
mono_coop_mutex_unlock (&threadpool->threads_lock);
+#endif
mono_threadpool_worker_cleanup (threadpool->worker);
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);
mono_coop_mutex_lock (&threadpool->threads_lock);
- COUNTER_ATOMIC (threadpool, counter, {
- counter._.working --;
- });
-
g_ptr_array_remove_fast (threadpool->threads, thread);
mono_coop_cond_signal (&threadpool->threads_exit_cond);
mono_coop_mutex_unlock (&threadpool->threads_lock);
+ COUNTER_ATOMIC (threadpool, counter, {
+ counter._.working --;
+ });
+
mono_refcount_dec (threadpool);
}
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;
}
tpdomain->outstanding_request ++;
g_assert (tpdomain->outstanding_request >= 1);
- mono_refcount_inc (threadpool);
+ domains_unlock ();
COUNTER_ATOMIC (threadpool, counter, {
- if (!(counter._.starting < 32767 /* G_MAXINT16 */))
- g_error ("%s: counter._.starting = %d, but should be < 32767", __func__, counter._.starting);
+ if (counter._.starting == 16) {
+ mono_refcount_dec (threadpool);
+ return TRUE;
+ }
counter._.starting ++;
});
mono_threadpool_worker_enqueue (threadpool->worker, worker_callback, NULL);
- domains_unlock ();
-
return TRUE;
}