From 6335b96646e2b816058b3d28840da27fa988d93e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 14 Sep 2015 13:13:46 +0200 Subject: [PATCH] [threadpool] Prevent high CPU usage in certain conditions Threadpool uses poll(2) to watch the file descriptors for activity but it can sometimes miss that an fd went into error. When that happens the poll call is interrupted with EAGAIN since the erroneous fd's events have already been read and there's nothing left in the queue for it. That, in turn, causes mono to run the loop so quickly that it uses 100% of the CPU. It happens, for instance, with Xamarin Studio which can utilize two CPU cores to the full while idling on the opening screen. This commit makes sure to remove the descriptors with errors from the poll set and thus preventing the syscall from being interrupted and returning EAGAIN. --- mono/metadata/threadpool-ms-io.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/mono/metadata/threadpool-ms-io.c b/mono/metadata/threadpool-ms-io.c index 47bceb56464..add3be6086c 100644 --- a/mono/metadata/threadpool-ms-io.c +++ b/mono/metadata/threadpool-ms-io.c @@ -290,6 +290,7 @@ wait_callback (gint fd, gint events, gpointer user_data) MonoGHashTable *states; MonoMList *list = NULL; gpointer k; + gboolean remove_fd = FALSE; g_assert (user_data); states = user_data; @@ -311,14 +312,23 @@ wait_callback (gint fd, gint events, gpointer user_data) mono_threadpool_ms_enqueue_work_item (((MonoObject*) sockares)->vtable->domain, (MonoObject*) sockares); } - mono_g_hash_table_replace (states, GINT_TO_POINTER (fd), list); + remove_fd = (events & EVENT_ERR) == EVENT_ERR; + if (!remove_fd) { + mono_g_hash_table_replace (states, GINT_TO_POINTER (fd), list); - events = get_events (list); + events = get_events (list); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: res fd %3d, events = %2s | %2s", - fd, (events & EVENT_IN) ? "RD" : "..", (events & EVENT_OUT) ? "WR" : ".."); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: res fd %3d, events = %2s | %2s | %2s", + fd, (events & EVENT_IN) ? "RD" : "..", (events & EVENT_OUT) ? "WR" : "..", (events & EVENT_ERR) ? "ERR" : "..."); - threadpool_io->backend.register_fd (fd, events, FALSE); + threadpool_io->backend.register_fd (fd, events, FALSE); + } else { + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: err fd %d", fd); + + mono_g_hash_table_remove (states, GINT_TO_POINTER (fd)); + + threadpool_io->backend.remove_fd (fd); + } } } @@ -368,8 +378,8 @@ selector_thread (gpointer data) events = get_events (list); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: %3s fd %3d, events = %2s | %2s", - exists ? "mod" : "add", fd, (events & EVENT_IN) ? "RD" : "..", (events & EVENT_OUT) ? "WR" : ".."); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_THREADPOOL, "io threadpool: %3s fd %3d, events = %2s | %2s | %2s", + exists ? "mod" : "add", fd, (events & EVENT_IN) ? "RD" : "..", (events & EVENT_OUT) ? "WR" : "..", (events & EVENT_ERR) ? "ERR" : "..."); threadpool_io->backend.register_fd (fd, events, !exists); -- 2.25.1