Merge pull request #725 from knocte/threadpool_init
[mono.git] / mono / metadata / threadpool.c
index fa4cd1a4e7b30cd45eb00b06a6b3905277600e4d..8710dafd661e8d26ac41f99ec451bd617400a474 100644 (file)
@@ -90,7 +90,7 @@ typedef struct {
 
        gint event_system;
        gpointer event_data;
-       void (*modify) (gpointer event_data, int fd, int operation, int events, gboolean is_new);
+       void (*modify) (gpointer p, int fd, int operation, int events, gboolean is_new);
        void (*wait) (gpointer sock_data);
        void (*shutdown) (gpointer event_data);
 } SocketIOData;
@@ -153,6 +153,7 @@ static void socket_io_cleanup (SocketIOData *data);
 static MonoObject *get_io_event (MonoMList **list, gint event);
 static int get_events_from_list (MonoMList *list);
 static int get_event_from_state (MonoSocketAsyncResult *state);
+static void check_for_interruption_critical (void);
 
 static MonoClass *async_call_klass;
 static MonoClass *socket_async_call_klass;
@@ -558,8 +559,8 @@ socket_io_add (MonoAsyncResult *ares, MonoSocketAsyncResult *state)
 
        mono_g_hash_table_replace (data->sock_to_state, state->handle, list);
        ievt = get_events_from_list (list);
-       LeaveCriticalSection (&data->io_lock);
-       data->modify (data->event_data, fd, state->operation, ievt, is_new);
+       /* The modify function leaves the io_lock critical section. */
+       data->modify (data, fd, state->operation, ievt, is_new);
 }
 
 #ifndef DISABLE_SOCKETS
@@ -771,6 +772,7 @@ monitor_thread (gpointer unused)
        ves_icall_System_Threading_Thread_SetName_internal (thread, mono_string_new (mono_domain_get (), "Threadpool monitor"));
        while (1) {
                ms = 500;
+               i = 10; //number of spurious awakes we tolerate before doing a round of rebalancing.
                do {
                        guint32 ts;
                        ts = mono_msec_ticks ();
@@ -781,7 +783,7 @@ monitor_thread (gpointer unused)
                                break;
                        if (THREAD_WANTS_A_BREAK (thread))
                                mono_thread_interruption_checkpoint ();
-               } while (ms > 0);
+               } while (ms > 0 && i--);
 
                if (mono_runtime_is_shutting_down ())
                        break;
@@ -814,7 +816,13 @@ monitor_thread (gpointer unused)
 }
 
 void
-mono_thread_pool_init ()
+mono_thread_pool_init_tls (void)
+{
+       mono_wsq_init ();
+}
+
+void
+mono_thread_pool_init (void)
 {
        gint threads_per_cpu = 1;
        gint thread_count;
@@ -851,7 +859,6 @@ mono_thread_pool_init ()
 
        InitializeCriticalSection (&wsqs_lock);
        wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count));
-       mono_wsq_init ();
 
 #ifndef DISABLE_PERFCOUNTERS
        async_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "Work Items Added");
@@ -1097,10 +1104,13 @@ static void
 threadpool_clear_queue (ThreadPool *tp, MonoDomain *domain)
 {
        MonoObject *obj;
-       MonoMList *other;
+       MonoMList *other = NULL;
+       MonoCQ *queue = tp->queue;
+
+       if (!queue)
+               return;
 
-       other = NULL;
-       while (mono_cq_dequeue (tp->queue, &obj)) {
+       while (mono_cq_dequeue (queue, &obj)) {
                if (obj == NULL)
                        continue;
                if (obj->vtable->domain != domain)
@@ -1108,6 +1118,9 @@ threadpool_clear_queue (ThreadPool *tp, MonoDomain *domain)
                threadpool_jobs_dec (obj);
        }
 
+       if (mono_runtime_is_shutting_down ())
+               return;
+
        while (other) {
                threadpool_append_job (tp, (MonoObject *) mono_mlist_get_data (other));
                other = mono_mlist_next (other);
@@ -1382,26 +1395,63 @@ should_i_die (ThreadPool *tp)
        return result;
 }
 
+static void
+set_tp_thread_info (ThreadPool *tp)
+{
+       const gchar *name;
+       MonoInternalThread *thread = mono_thread_internal_current ();
+
+       mono_profiler_thread_start (thread->tid);
+       name = (tp->is_io) ? "IO Threadpool worker" : "Threadpool worker";
+       mono_thread_set_name_internal (thread, mono_string_new (mono_domain_get (), name), FALSE);
+}
+
+static void
+clear_thread_state (void)
+{
+       MonoInternalThread *thread = mono_thread_internal_current ();
+       /* If the callee changes the background status, set it back to TRUE */
+       mono_thread_clr_state (thread , ~ThreadState_Background);
+       if (!mono_thread_test_state (thread , ThreadState_Background))
+               ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
+}
+
+static void
+check_for_interruption_critical (void)
+{
+       MonoInternalThread *thread;
+       /*RULE NUMBER ONE OF SKIP_THREAD: NEVER POKE MANAGED STATE.*/
+       mono_gc_set_skip_thread (FALSE);
+
+       thread = mono_thread_internal_current ();
+       if (THREAD_WANTS_A_BREAK (thread))
+               mono_thread_interruption_checkpoint ();
+
+       /*RULE NUMBER TWO OF SKIP_THREAD: READ RULE NUMBER ONE.*/
+       mono_gc_set_skip_thread (TRUE);
+}
+
+static void
+fire_profiler_thread_end (void)
+{
+       MonoInternalThread *thread = mono_thread_internal_current ();
+       mono_profiler_thread_end (thread->tid);
+}
+
 static void
 async_invoke_thread (gpointer data)
 {
        MonoDomain *domain;
-       MonoInternalThread *thread;
        MonoWSQ *wsq;
        ThreadPool *tp;
        gboolean must_die;
-       const gchar *name;
   
        tp = data;
        wsq = NULL;
        if (!tp->is_io)
                wsq = add_wsq ();
 
-       thread = mono_thread_internal_current ();
-
-       mono_profiler_thread_start (thread->tid);
-       name = (tp->is_io) ? "IO Threadpool worker" : "Threadpool worker";
-       mono_thread_set_name_internal (thread, mono_string_new (mono_domain_get (), name), FALSE);
+       set_tp_thread_info (tp);
 
        if (tp_start_func)
                tp_start_func (tp_hooks_user_data);
@@ -1483,10 +1533,7 @@ async_invoke_thread (gpointer data)
                                }
                                mono_thread_pop_appdomain_ref ();
                                InterlockedDecrement (&tp->busy_threads);
-                               /* If the callee changes the background status, set it back to TRUE */
-                               mono_thread_clr_state (thread , ~ThreadState_Background);
-                               if (!mono_thread_test_state (thread , ThreadState_Background))
-                                       ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
+                               clear_thread_state ();
                        }
                }
 
@@ -1519,8 +1566,7 @@ async_invoke_thread (gpointer data)
 #endif
                                if (mono_runtime_is_shutting_down ())
                                        break;
-                               if (THREAD_WANTS_A_BREAK (thread))
-                                       mono_thread_interruption_checkpoint ();
+                               check_for_interruption_critical ();
                        }
                        InterlockedDecrement (&tp->waiting);
 
@@ -1557,7 +1603,7 @@ async_invoke_thread (gpointer data)
                                                remove_wsq (wsq);
                                        }
 
-                                       mono_profiler_thread_end (thread->tid);
+                                       fire_profiler_thread_end ();
 
                                        if (tp_finish_func)
                                                tp_finish_func (tp_hooks_user_data);