[threadpool-io] Ensure selector thread is running before waiting on it (#4572)
authorLudovic Henry <ludovic@xamarin.com>
Thu, 23 Mar 2017 14:09:33 +0000 (10:09 -0400)
committerGitHub <noreply@github.com>
Thu, 23 Mar 2017 14:09:33 +0000 (10:09 -0400)
This could result in a unecessary wait on shutdown where the selector thread would have exited, and the finalizer thread would try to dispose a Socket, which would try to remove the socket from the IOSelector. This removal operation would wait on the selector thread to acknowledge the removal, but because the selector thread would have alreday exited, we would wait on an event that would never happen.

mono/metadata/threadpool-io.c

index 4e3b30f011541330aa48beb58265f4b6d68a9d17..5048c6ae08f76e95b3637bd8b26ec63ccc6e756f 100644 (file)
@@ -318,8 +318,6 @@ selector_thread (gpointer data)
        MonoError error;
        MonoGHashTable *states;
 
-       io_selector_running = TRUE;
-
        if (mono_runtime_is_shutting_down ()) {
                io_selector_running = FALSE;
                return 0;
@@ -445,7 +443,12 @@ selector_thread (gpointer data)
 
        mono_g_hash_table_destroy (states);
 
+       mono_coop_mutex_lock (&threadpool_io->updates_lock);
+
        io_selector_running = FALSE;
+       mono_coop_cond_broadcast (&threadpool_io->updates_cond);
+
+       mono_coop_mutex_unlock (&threadpool_io->updates_lock);
 
        return 0;
 }
@@ -555,9 +558,15 @@ initialize (void)
        if (!threadpool_io->backend.init (threadpool_io->wakeup_pipes [0]))
                g_error ("initialize: backend->init () failed");
 
+       mono_coop_mutex_lock (&threadpool_io->updates_lock);
+
+       io_selector_running = TRUE;
+
        MonoError error;
        if (!mono_thread_create_internal (mono_get_root_domain (), selector_thread, NULL, MONO_THREAD_CREATE_FLAGS_THREADPOOL | MONO_THREAD_CREATE_FLAGS_SMALL_STACK, &error))
                g_error ("initialize: mono_thread_create_internal () failed due to %s", mono_error_get_message (&error));
+
+       mono_coop_mutex_unlock (&threadpool_io->updates_lock);
 }
 
 static void
@@ -591,6 +600,11 @@ ves_icall_System_IOSelector_Add (gpointer handle, MonoIOSelectorJob *job)
 
        mono_coop_mutex_lock (&threadpool_io->updates_lock);
 
+       if (!io_selector_running) {
+               mono_coop_mutex_unlock (&threadpool_io->updates_lock);
+               return;
+       }
+
        update = update_get_new ();
        update->type = UPDATE_ADD;
        update->data.add.fd = GPOINTER_TO_INT (handle);
@@ -618,6 +632,11 @@ mono_threadpool_io_remove_socket (int fd)
 
        mono_coop_mutex_lock (&threadpool_io->updates_lock);
 
+       if (!io_selector_running) {
+               mono_coop_mutex_unlock (&threadpool_io->updates_lock);
+               return;
+       }
+
        update = update_get_new ();
        update->type = UPDATE_REMOVE_SOCKET;
        update->data.add.fd = fd;
@@ -640,6 +659,11 @@ mono_threadpool_io_remove_domain_jobs (MonoDomain *domain)
 
        mono_coop_mutex_lock (&threadpool_io->updates_lock);
 
+       if (!io_selector_running) {
+               mono_coop_mutex_unlock (&threadpool_io->updates_lock);
+               return;
+       }
+
        update = update_get_new ();
        update->type = UPDATE_REMOVE_DOMAIN;
        update->data.remove_domain.domain = domain;