Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mono / metadata / threadpool-ms.c
index 7d9657c2fcc61f229b54dca8a45e1af6388ad667..62fc34aef3f2b11e470b7a8912c819bbf68a6db1 100644 (file)
@@ -5,6 +5,7 @@
  *     Ludovic Henry (ludovic.henry@xamarin.com)
  *
  * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 //
@@ -46,7 +47,7 @@
 #define CPU_USAGE_LOW 80
 #define CPU_USAGE_HIGH 95
 
-#define MONITOR_INTERVAL 100 // ms
+#define MONITOR_INTERVAL 500 // ms
 #define MONITOR_MINIMAL_LIFETIME 60 * 1000 // ms
 
 #define WORKER_CREATION_MAX_PER_SEC 10
@@ -227,11 +228,11 @@ rand_create (void)
 static guint32
 rand_next (gpointer *handle, guint32 min, guint32 max)
 {
+       MonoError error;
        guint32 val;
-       if (!mono_rand_try_get_uint32 (handle, &val, min, max)) {
-               // FIXME handle error
-               g_assert_not_reached ();
-       }
+       mono_rand_try_get_uint32 (handle, &val, min, max, &error);
+       // FIXME handle error
+       mono_error_assert_ok (&error);
        return val;
 }
 
@@ -344,21 +345,20 @@ cleanup (void)
        mono_coop_mutex_unlock (&threadpool->active_threads_lock);
 }
 
-void
-mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item)
+gboolean
+mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item, MonoError *error)
 {
        static MonoClass *threadpool_class = NULL;
        static MonoMethod *unsafe_queue_custom_work_item_method = NULL;
-       MonoError error;
        MonoDomain *current_domain;
        MonoBoolean f;
        gpointer args [2];
 
+       mono_error_init (error);
        g_assert (work_item);
 
        if (!threadpool_class)
-               threadpool_class = mono_class_from_name (mono_defaults.corlib, "System.Threading", "ThreadPool");
-       g_assert (threadpool_class);
+               threadpool_class = mono_class_load_from_name (mono_defaults.corlib, "System.Threading", "ThreadPool");
 
        if (!unsafe_queue_custom_work_item_method)
                unsafe_queue_custom_work_item_method = mono_class_get_method_from_name (threadpool_class, "UnsafeQueueCustomWorkItem", 2);
@@ -371,17 +371,21 @@ mono_threadpool_ms_enqueue_work_item (MonoDomain *domain, MonoObject *work_item)
 
        current_domain = mono_domain_get ();
        if (current_domain == domain) {
-               mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, error);
+               return_val_if_nok (error, FALSE);
        } else {
                mono_thread_push_appdomain_ref (domain);
                if (mono_domain_set (domain, FALSE)) {
-                       mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       mono_runtime_invoke_checked (unsafe_queue_custom_work_item_method, NULL, args, error);
+                       if (!is_ok (error)) {
+                               mono_thread_pop_appdomain_ref ();
+                               return FALSE;
+                       }
                        mono_domain_set (current_domain, TRUE);
                }
                mono_thread_pop_appdomain_ref ();
        }
+       return TRUE;
 }
 
 /* LOCKING: threadpool->domains_lock must be held */
@@ -525,7 +529,7 @@ worker_park (void)
                if (interrupted)
                        goto done;
 
-               if (mono_coop_cond_timedwait (&threadpool->parked_threads_cond, &threadpool->active_threads_lock, rand_next ((void **)rand_handle, 5 * 1000, 60 * 1000)) != 0)
+               if (mono_coop_cond_timedwait (&threadpool->parked_threads_cond, &threadpool->active_threads_lock, rand_next (&rand_handle, 5 * 1000, 60 * 1000)) != 0)
                        timeout = TRUE;
 
                mono_thread_info_uninstall_interrupt (&interrupted);
@@ -876,8 +880,8 @@ monitor_thread (void)
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] monitor thread, started", mono_native_thread_id_get ());
 
        do {
-               MonoInternalThread *thread;
-               gboolean all_waitsleepjoin = TRUE;
+               ThreadPoolCounter counter;
+               gboolean limit_worker_max_reached;
                gint32 interval_left = MONITOR_INTERVAL;
                gint32 awake = 0; /* number of spurious awakes we tolerate before doing a round of rebalancing */
 
@@ -918,49 +922,38 @@ monitor_thread (void)
                }
                mono_coop_mutex_unlock (&threadpool->domains_lock);
 
+               threadpool->cpu_usage = mono_cpu_usage (threadpool->cpu_usage_state);
 
-               mono_coop_mutex_lock (&threadpool->active_threads_lock);
-               for (i = 0; i < threadpool->working_threads->len; ++i) {
-                       thread = (MonoInternalThread *)g_ptr_array_index (threadpool->working_threads, i);
-                       if ((thread->state & ThreadState_WaitSleepJoin) == 0) {
-                               all_waitsleepjoin = FALSE;
-                               break;
-                       }
-               }
-               mono_coop_mutex_unlock (&threadpool->active_threads_lock);
+               if (!monitor_sufficient_delay_since_last_dequeue ())
+                       continue;
 
-               if (all_waitsleepjoin) {
-                       ThreadPoolCounter counter;
-                       gboolean limit_worker_max_reached = FALSE;
+               limit_worker_max_reached = FALSE;
 
-                       COUNTER_ATOMIC (counter, {
-                               if (counter._.max_working >= threadpool->limit_worker_max) {
-                                       limit_worker_max_reached = TRUE;
-                                       break;
-                               }
-                               counter._.max_working ++;
-                       });
+               COUNTER_ATOMIC (counter, {
+                       if (counter._.max_working >= threadpool->limit_worker_max) {
+                               limit_worker_max_reached = TRUE;
+                               break;
+                       }
+                       counter._.max_working ++;
+               });
 
-                       if (!limit_worker_max_reached)
-                               hill_climbing_force_change (counter._.max_working, TRANSITION_STARVATION);
-               }
+               if (limit_worker_max_reached)
+                       continue;
 
-               threadpool->cpu_usage = mono_cpu_usage (threadpool->cpu_usage_state);
+               hill_climbing_force_change (counter._.max_working, TRANSITION_STARVATION);
 
-               if (monitor_sufficient_delay_since_last_dequeue ()) {
-                       for (i = 0; i < 5; ++i) {
-                               if (mono_runtime_is_shutting_down ())
-                                       break;
+               for (i = 0; i < 5; ++i) {
+                       if (mono_runtime_is_shutting_down ())
+                               break;
 
-                               if (worker_try_unpark ()) {
-                                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] monitor thread, unparked", mono_native_thread_id_get ());
-                                       break;
-                               }
+                       if (worker_try_unpark ()) {
+                               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] monitor thread, unparked", mono_native_thread_id_get ());
+                               break;
+                       }
 
-                               if (worker_try_create ()) {
-                                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] monitor thread, created", mono_native_thread_id_get ());
-                                       break;
-                               }
+                       if (worker_try_create ()) {
+                               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] monitor thread, created", mono_native_thread_id_get ());
+                               break;
                        }
                }
        } while (monitor_should_keep_running ());
@@ -1326,10 +1319,9 @@ mono_threadpool_ms_cleanup (void)
 }
 
 MonoAsyncResult *
-mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod *method, gpointer *params)
+mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod *method, gpointer *params, MonoError *error)
 {
        static MonoClass *async_call_klass = NULL;
-       MonoError error;
        MonoMethodMessage *message;
        MonoAsyncResult *async_result;
        MonoAsyncCall *async_call;
@@ -1337,15 +1329,16 @@ mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMet
        MonoObject *state = NULL;
 
        if (!async_call_klass)
-               async_call_klass = mono_class_from_name (mono_defaults.corlib, "System", "MonoAsyncCall");
-       g_assert (async_call_klass);
+               async_call_klass = mono_class_load_from_name (mono_defaults.corlib, "System", "MonoAsyncCall");
 
        mono_lazy_initialize (&status, initialize);
 
+       mono_error_init (error);
+
        message = mono_method_call_message_new (method, params, mono_get_delegate_invoke (method->klass), (params != NULL) ? (&async_callback) : NULL, (params != NULL) ? (&state) : NULL);
 
-       async_call = (MonoAsyncCall*) mono_object_new_checked (domain, async_call_klass, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       async_call = (MonoAsyncCall*) mono_object_new_checked (domain, async_call_klass, error);
+       return_val_if_nok (error, NULL);
 
        MONO_OBJECT_SETREF (async_call, msg, message);
        MONO_OBJECT_SETREF (async_call, state, state);
@@ -1358,7 +1351,8 @@ mono_threadpool_ms_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMet
        async_result = mono_async_result_new (domain, NULL, async_call->state, NULL, (MonoObject*) async_call);
        MONO_OBJECT_SETREF (async_result, async_delegate, target);
 
-       mono_threadpool_ms_enqueue_work_item (domain, (MonoObject*) async_result);
+       mono_threadpool_ms_enqueue_work_item (domain, (MonoObject*) async_result, error);
+       return_val_if_nok (error, NULL);
 
        return async_result;
 }
@@ -1596,7 +1590,9 @@ void
 ves_icall_System_Threading_ThreadPool_ReportThreadStatus (MonoBoolean is_working)
 {
        // TODO
-       mono_raise_exception (mono_get_exception_not_implemented (NULL));
+       MonoError error;
+       mono_error_set_not_implemented (&error, "");
+       mono_error_set_pending_exception (&error);
 }
 
 MonoBoolean
@@ -1609,7 +1605,9 @@ MonoBoolean G_GNUC_UNUSED
 ves_icall_System_Threading_ThreadPool_PostQueuedCompletionStatus (MonoNativeOverlapped *native_overlapped)
 {
        /* This copy the behavior of the current Mono implementation */
-       mono_raise_exception (mono_get_exception_not_implemented (NULL));
+       MonoError error;
+       mono_error_set_not_implemented (&error, "");
+       mono_error_set_pending_exception (&error);
        return FALSE;
 }