* 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.
*/
//
MonoCoopMutex worker_creation_lock;
gint32 heuristic_completions;
- guint32 heuristic_sample_start;
- guint32 heuristic_last_dequeue; // ms
- guint32 heuristic_last_adjustment; // ms
- guint32 heuristic_adjustment_interval; // ms
+ gint64 heuristic_sample_start;
+ gint64 heuristic_last_dequeue; // ms
+ gint64 heuristic_last_adjustment; // ms
+ gint64 heuristic_adjustment_interval; // ms
ThreadPoolHillClimbing heuristic_hill_climbing;
MonoCoopMutex heuristic_lock;
thread = mono_thread_internal_current ();
g_assert (thread);
- mono_thread_set_name_internal (thread, mono_string_new (mono_domain_get (), "Threadpool worker"), FALSE);
+ mono_thread_set_name_internal (thread, mono_string_new (mono_get_root_domain (), "Threadpool worker"), FALSE, &error);
+ mono_error_assert_ok (&error);
mono_coop_mutex_lock (&threadpool->active_threads_lock);
g_ptr_array_add (threadpool->working_threads, thread);
{
ThreadPoolCounter counter;
MonoInternalThread *thread;
+ gint64 current_ticks;
gint32 now;
mono_coop_mutex_lock (&threadpool->worker_creation_lock);
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] try create worker", mono_native_thread_id_get ());
-
- if ((now = mono_100ns_ticks () / 10 / 1000 / 1000) == 0) {
+ current_ticks = mono_100ns_ticks ();
+ now = current_ticks / (10 * 1000 * 1000);
+ if (0 == current_ticks) {
g_warning ("failed to get 100ns ticks");
} else {
if (threadpool->worker_creation_current_second != now) {
counter._.active ++;
});
- if ((thread = mono_thread_create_internal (mono_get_root_domain (), worker_thread, NULL, TRUE, 0)) != NULL) {
+ MonoError error;
+ if ((thread = mono_thread_create_internal (mono_get_root_domain (), worker_thread, NULL, TRUE, 0, &error)) != NULL) {
threadpool->worker_creation_current_count += 1;
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] try create worker, created %p, now = %d count = %d", mono_native_thread_id_get (), thread->tid, now, threadpool->worker_creation_current_count);
return TRUE;
}
- mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] try create worker, failed: could not create thread", mono_native_thread_id_get ());
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_THREADPOOL, "[%p] try create worker, failed: could not create thread due to %s", mono_native_thread_id_get (), mono_error_get_message (&error));
+ mono_error_cleanup (&error);
COUNTER_ATOMIC (counter, {
counter._.working --;
static gboolean
monitor_sufficient_delay_since_last_dequeue (void)
{
- guint32 threshold;
+ gint64 threshold;
g_assert (threadpool);
mono_gc_set_skip_thread (TRUE);
do {
- guint32 ts;
+ gint64 ts;
gboolean alerted = FALSE;
if (mono_runtime_is_shutting_down ())
static void
monitor_ensure_running (void)
{
+ MonoError error;
for (;;) {
switch (monitor_status) {
case MONITOR_STATUS_REQUESTED:
if (mono_runtime_is_shutting_down ())
return;
if (InterlockedCompareExchange (&monitor_status, MONITOR_STATUS_REQUESTED, MONITOR_STATUS_NOT_RUNNING) == MONITOR_STATUS_NOT_RUNNING) {
- if (!mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK))
+ if (!mono_thread_create_internal (mono_get_root_domain (), monitor_thread, NULL, TRUE, SMALL_STACK, &error)) {
monitor_status = MONITOR_STATUS_NOT_RUNNING;
+ mono_error_cleanup (&error);
+ }
return;
}
break;
}
static gint16
-hill_climbing_update (gint16 current_thread_count, guint32 sample_duration, gint32 completions, guint32 *adjustment_interval)
+hill_climbing_update (gint16 current_thread_count, guint32 sample_duration, gint32 completions, gint64 *adjustment_interval)
{
ThreadPoolHillClimbing *hc;
ThreadPoolHeuristicStateTransition transition;
if (mono_coop_mutex_trylock (&threadpool->heuristic_lock) == 0) {
gint32 completions = InterlockedExchange (&threadpool->heuristic_completions, 0);
- guint32 sample_end = mono_msec_ticks ();
- guint32 sample_duration = sample_end - threadpool->heuristic_sample_start;
+ gint64 sample_end = mono_msec_ticks ();
+ gint64 sample_duration = sample_end - threadpool->heuristic_sample_start;
if (sample_duration >= threadpool->heuristic_adjustment_interval / 2) {
ThreadPoolCounter counter;
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);
+ message = mono_method_call_message_new (method, params, mono_get_delegate_invoke (method->klass), (params != NULL) ? (&async_callback) : NULL, (params != NULL) ? (&state) : NULL, error);
+ return_val_if_nok (error, NULL);
async_call = (MonoAsyncCall*) mono_object_new_checked (domain, async_call_klass, error);
return_val_if_nok (error, NULL);
MONO_OBJECT_SETREF (async_call, cb_target, async_callback);
}
- async_result = mono_async_result_new (domain, NULL, async_call->state, NULL, (MonoObject*) async_call);
+ async_result = mono_async_result_new (domain, NULL, async_call->state, NULL, (MonoObject*) async_call, error);
+ return_val_if_nok (error, NULL);
MONO_OBJECT_SETREF (async_result, async_delegate, target);
mono_threadpool_ms_enqueue_work_item (domain, (MonoObject*) async_result, error);
}
MonoObject *
-mono_threadpool_ms_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc)
+mono_threadpool_ms_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc, MonoError *error)
{
MonoAsyncCall *ac;
+ mono_error_init (error);
g_assert (exc);
g_assert (out_args);
mono_monitor_enter ((MonoObject*) ares);
if (ares->endinvoke_called) {
- *exc = (MonoObject*) mono_get_exception_invalid_operation (NULL);
+ mono_error_set_invalid_operation(error, "Delegate EndInvoke method called more than once");
mono_monitor_exit ((MonoObject*) ares);
return NULL;
}
} else {
wait_event = CreateEvent (NULL, TRUE, FALSE, NULL);
g_assert(wait_event);
- MONO_OBJECT_SETREF (ares, handle, (MonoObject*) mono_wait_handle_new (mono_object_domain (ares), wait_event));
+ MonoWaitHandle *wait_handle = mono_wait_handle_new (mono_object_domain (ares), wait_event, error);
+ if (!is_ok (error)) {
+ CloseHandle (wait_event);
+ return NULL;
+ }
+ MONO_OBJECT_SETREF (ares, handle, (MonoObject*) wait_handle);
}
mono_monitor_exit ((MonoObject*) ares);
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
WaitForSingleObjectEx (wait_event, INFINITE, TRUE);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
}
ac = (MonoAsyncCall*) ares->object_data;
mono_threadpool_ms_remove_domain_jobs (MonoDomain *domain, int timeout)
{
gboolean res = TRUE;
- guint32 start;
+ gint64 end;
gpointer sem;
g_assert (domain);
g_assert (mono_domain_is_unloading (domain));
if (timeout != -1)
- start = mono_msec_ticks ();
+ end = mono_msec_ticks () + timeout;
#ifndef DISABLE_SOCKETS
mono_threadpool_ms_io_remove_domain_jobs (domain);
if (timeout != -1) {
- timeout -= mono_msec_ticks () - start;
- if (timeout < 0)
+ if (mono_msec_ticks () > end)
return FALSE;
}
#endif
mono_memory_write_barrier ();
while (domain->threadpool_jobs) {
- MONO_PREPARE_BLOCKING;
- WaitForSingleObject (sem, timeout);
- MONO_FINISH_BLOCKING;
+ gint64 now;
+
if (timeout != -1) {
- timeout -= mono_msec_ticks () - start;
- if (timeout <= 0) {
+ now = mono_msec_ticks ();
+ if (now > end) {
res = FALSE;
break;
}
}
+
+ MONO_ENTER_GC_SAFE;
+ WaitForSingleObject (sem, timeout != -1 ? end - now : timeout);
+ MONO_EXIT_GC_SAFE;
}
domain->cleanup_semaphore = NULL;