Merge pull request #4540 from kumpera/android-changes-part1
[mono.git] / mono / metadata / threadpool.c
index 4b0aa6ec18d0dbcefea22663c85585c1d3c10a9f..3c0fa3d7f6db0ebda4cd140ae42d6f7a7b60e716 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * threadpool.c: Microsoft threadpool runtime support
+/**
+ * \file
+ * Microsoft threadpool runtime support
  *
  * Author:
  *     Ludovic Henry (ludovic.henry@xamarin.com)
@@ -71,10 +72,6 @@ typedef struct {
        GPtrArray *domains; // ThreadPoolDomain* []
        MonoCoopMutex domains_lock;
 
-       GPtrArray *threads; // MonoInternalThread* []
-       MonoCoopMutex threads_lock;
-       MonoCoopCond threads_exit_cond;
-
        ThreadPoolCounter counters;
 
        gint32 limit_io_min;
@@ -121,16 +118,13 @@ domains_unlock (void)
 static void
 destroy (gpointer unused)
 {
-#if 0
        g_ptr_array_free (threadpool.domains, TRUE);
        mono_coop_mutex_destroy (&threadpool.domains_lock);
-
-       g_ptr_array_free (threadpool.threads, TRUE);
-       mono_coop_mutex_destroy (&threadpool.threads_lock);
-       mono_coop_cond_destroy (&threadpool.threads_exit_cond);
-#endif
 }
 
+static void
+worker_callback (void);
+
 static void
 initialize (void)
 {
@@ -141,60 +135,15 @@ initialize (void)
        threadpool.domains = g_ptr_array_new ();
        mono_coop_mutex_init (&threadpool.domains_lock);
 
-       threadpool.threads = g_ptr_array_new ();
-       mono_coop_mutex_init (&threadpool.threads_lock);
-       mono_coop_cond_init (&threadpool.threads_exit_cond);
-
        threadpool.limit_io_min = mono_cpu_count ();
        threadpool.limit_io_max = CLAMP (threadpool.limit_io_min * 100, MIN (threadpool.limit_io_min, 200), MAX (threadpool.limit_io_min, 200));
 
-       mono_threadpool_worker_init ();
+       mono_threadpool_worker_init (worker_callback);
 }
 
 static void
 cleanup (void)
 {
-       guint i;
-       MonoInternalThread *current;
-
-       /* we make the assumption along the code that we are
-        * cleaning up only if the runtime is shutting down */
-       g_assert (mono_runtime_is_shutting_down ());
-
-       current = mono_thread_internal_current ();
-
-       mono_coop_mutex_lock (&threadpool.threads_lock);
-
-       /* stop all threadpool.threads */
-       for (i = 0; i < threadpool.threads->len; ++i) {
-               MonoInternalThread *thread = (MonoInternalThread*) g_ptr_array_index (threadpool.threads, i);
-               if (thread != current)
-                       mono_thread_internal_abort (thread);
-       }
-
-       mono_coop_mutex_unlock (&threadpool.threads_lock);
-
-#if 0
-       /* give a chance to the other threads to exit */
-       mono_thread_info_yield ();
-
-       mono_coop_mutex_lock (&threadpool.threads_lock);
-
-       for (;;) {
-               if (threadpool.threads->len == 0)
-                       break;
-
-               if (threadpool.threads->len == 1 && g_ptr_array_index (threadpool.threads, 0) == current) {
-                       /* We are waiting on ourselves */
-                       break;
-               }
-
-               mono_coop_cond_wait (&threadpool.threads_exit_cond, &threadpool.threads_lock);
-       }
-
-       mono_coop_mutex_unlock (&threadpool.threads_lock);
-#endif
-
        mono_threadpool_worker_cleanup ();
 
        mono_refcount_dec (&threadpool);
@@ -209,7 +158,7 @@ mono_threadpool_enqueue_work_item (MonoDomain *domain, MonoObject *work_item, Mo
        MonoBoolean f;
        gpointer args [2];
 
-       mono_error_init (error);
+       error_init (error);
        g_assert (work_item);
 
        if (!threadpool_class)
@@ -325,19 +274,22 @@ static MonoObject*
 try_invoke_perform_wait_callback (MonoObject** exc, MonoError *error)
 {
        HANDLE_FUNCTION_ENTER ();
-       mono_error_init (error);
+       error_init (error);
        MonoObject *res = mono_runtime_try_invoke (mono_defaults.threadpool_perform_wait_callback_method, NULL, NULL, exc, error);
        HANDLE_FUNCTION_RETURN_VAL (res);
 }
 
 static void
-worker_callback (gpointer unused)
+worker_callback (void)
 {
        MonoError error;
        ThreadPoolDomain *tpdomain, *previous_tpdomain;
        ThreadPoolCounter counter;
        MonoInternalThread *thread;
 
+       if (!mono_refcount_tryinc (&threadpool))
+               return;
+
        thread = mono_thread_internal_current ();
 
        COUNTER_ATOMIC (counter, {
@@ -357,10 +309,6 @@ worker_callback (gpointer unused)
                return;
        }
 
-       mono_coop_mutex_lock (&threadpool.threads_lock);
-       g_ptr_array_add (threadpool.threads, thread);
-       mono_coop_mutex_unlock (&threadpool.threads_lock);
-
        /*
         * This is needed so there is always an lmf frame in the runtime invoke call below,
         * so ThreadAbortExceptions are caught even if the thread is in native code.
@@ -447,14 +395,6 @@ worker_callback (gpointer unused)
 
        domains_unlock ();
 
-       mono_coop_mutex_lock (&threadpool.threads_lock);
-
-       g_ptr_array_remove_fast (threadpool.threads, thread);
-
-       mono_coop_cond_signal (&threadpool.threads_exit_cond);
-
-       mono_coop_mutex_unlock (&threadpool.threads_lock);
-
        COUNTER_ATOMIC (counter, {
                counter._.working --;
        });
@@ -484,9 +424,7 @@ mono_threadpool_begin_invoke (MonoDomain *domain, MonoObject *target, MonoMethod
        if (!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);
+       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, error);
        return_val_if_nok (error, NULL);
@@ -517,7 +455,7 @@ mono_threadpool_end_invoke (MonoAsyncResult *ares, MonoArray **out_args, MonoObj
 {
        MonoAsyncCall *ac;
 
-       mono_error_init (error);
+       error_init (error);
        g_assert (exc);
        g_assert (out_args);
 
@@ -671,12 +609,18 @@ ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_
        if (!worker_threads || !completion_port_threads)
                return;
 
-       mono_lazy_initialize (&status, initialize);
+       if (!mono_lazy_initialize (&status, initialize) || !mono_refcount_tryinc (&threadpool)) {
+               *worker_threads = 0;
+               *completion_port_threads = 0;
+               return;
+       }
 
        counter = COUNTER_READ ();
 
        *worker_threads = MAX (0, mono_threadpool_worker_get_max () - counter._.working);
        *completion_port_threads = threadpool.limit_io_max;
+
+       mono_refcount_dec (&threadpool);
 }
 
 void
@@ -685,10 +629,16 @@ ves_icall_System_Threading_ThreadPool_GetMinThreadsNative (gint32 *worker_thread
        if (!worker_threads || !completion_port_threads)
                return;
 
-       mono_lazy_initialize (&status, initialize);
+       if (!mono_lazy_initialize (&status, initialize) || !mono_refcount_tryinc (&threadpool)) {
+               *worker_threads = 0;
+               *completion_port_threads = 0;
+               return;
+       }
 
        *worker_threads = mono_threadpool_worker_get_min ();
        *completion_port_threads = threadpool.limit_io_min;
+
+       mono_refcount_dec (&threadpool);
 }
 
 void
@@ -697,25 +647,35 @@ ves_icall_System_Threading_ThreadPool_GetMaxThreadsNative (gint32 *worker_thread
        if (!worker_threads || !completion_port_threads)
                return;
 
-       mono_lazy_initialize (&status, initialize);
+       if (!mono_lazy_initialize (&status, initialize) || !mono_refcount_tryinc (&threadpool)) {
+               *worker_threads = 0;
+               *completion_port_threads = 0;
+               return;
+       }
 
        *worker_threads = mono_threadpool_worker_get_max ();
        *completion_port_threads = threadpool.limit_io_max;
+
+       mono_refcount_dec (&threadpool);
 }
 
 MonoBoolean
 ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads, gint32 completion_port_threads)
 {
-       mono_lazy_initialize (&status, initialize);
-
        if (completion_port_threads <= 0 || completion_port_threads > threadpool.limit_io_max)
                return FALSE;
 
-       if (!mono_threadpool_worker_set_min (worker_threads))
+       if (!mono_lazy_initialize (&status, initialize) || !mono_refcount_tryinc (&threadpool))
+               return FALSE;
+
+       if (!mono_threadpool_worker_set_min (worker_threads)) {
+               mono_refcount_dec (&threadpool);
                return FALSE;
+       }
 
        threadpool.limit_io_min = completion_port_threads;
 
+       mono_refcount_dec (&threadpool);
        return TRUE;
 }
 
@@ -724,16 +684,20 @@ ves_icall_System_Threading_ThreadPool_SetMaxThreadsNative (gint32 worker_threads
 {
        gint cpu_count = mono_cpu_count ();
 
-       mono_lazy_initialize (&status, initialize);
-
        if (completion_port_threads < threadpool.limit_io_min || completion_port_threads < cpu_count)
                return FALSE;
 
-       if (!mono_threadpool_worker_set_max (worker_threads))
+       if (!mono_lazy_initialize (&status, initialize) || !mono_refcount_tryinc (&threadpool))
+               return FALSE;
+
+       if (!mono_threadpool_worker_set_max (worker_threads)) {
+               mono_refcount_dec (&threadpool);
                return FALSE;
+       }
 
        threadpool.limit_io_max = completion_port_threads;
 
+       mono_refcount_dec (&threadpool);
        return TRUE;
 }
 
@@ -783,7 +747,7 @@ ves_icall_System_Threading_ThreadPool_RequestWorkerThread (void)
        if (mono_domain_is_unloading (domain))
                return FALSE;
 
-       if (!mono_refcount_tryinc (&threadpool)) {
+       if (!mono_lazy_initialize (&status, initialize) || !mono_refcount_tryinc (&threadpool)) {
                /* threadpool has been destroyed, we are shutting down */
                return FALSE;
        }
@@ -818,11 +782,9 @@ ves_icall_System_Threading_ThreadPool_RequestWorkerThread (void)
                counter._.starting ++;
        });
 
-       mono_threadpool_worker_enqueue (worker_callback, NULL);
-
-       /* we do not decrement the threadpool refcount,
-        * as it's going to be done in the worker_callback */
+       mono_threadpool_worker_request ();
 
+       mono_refcount_dec (&threadpool);
        return TRUE;
 }