* 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.
*/
//
#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
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;
}
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;
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);
current_domain = mono_domain_get ();
if (current_domain == domain) {
- mono_runtime_invoke (unsafe_queue_custom_work_item_method, NULL, args, NULL);
+ 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 (unsafe_queue_custom_work_item_method, NULL, args, NULL);
+ 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 */
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);
static void
worker_thread (gpointer data)
{
+ MonoError error;
MonoInternalThread *thread;
ThreadPoolDomain *tpdomain, *previous_tpdomain;
ThreadPoolCounter counter;
mono_thread_push_appdomain_ref (tpdomain->domain);
if (mono_domain_set (tpdomain->domain, FALSE)) {
- MonoObject *exc = NULL;
- MonoObject *res = mono_runtime_invoke (mono_defaults.threadpool_perform_wait_callback_method, NULL, NULL, &exc);
- if (exc)
+ MonoObject *exc = NULL, *res;
+
+ res = mono_runtime_try_invoke (mono_defaults.threadpool_perform_wait_callback_method, NULL, NULL, &exc, &error);
+ if (exc || !mono_error_ok(&error)) {
+ if (exc == NULL)
+ exc = (MonoObject *) mono_error_convert_to_exception (&error);
+ else
+ mono_error_cleanup (&error);
mono_thread_internal_unhandled_exception (exc);
- else if (res && *(MonoBoolean*) mono_object_unbox (res) == FALSE)
+ } else if (res && *(MonoBoolean*) mono_object_unbox (res) == FALSE)
retire = TRUE;
mono_thread_clr_state (thread, (MonoThreadState)~ThreadState_Background);
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 */
}
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 ());
}
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;
MonoMethodMessage *message;
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 (domain, async_call_klass);
+ 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);
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;
}
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
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;
}