2005-08-21 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / threadpool.c
index 15313bebbf319430b1bbd84d842bba4974c25947..796af597a5035ff41c0c24eae46e981dec93294c 100644 (file)
 #ifdef PLATFORM_WIN32
 #define WINVER 0x0500
 #define _WIN32_WINNT 0x0500
-#define THREADS_PER_CPU        25
-#else
-#define THREADS_PER_CPU        50
 #endif
 
+#define THREADS_PER_CPU        5 /* 20 + THREADS_PER_CPU * number of CPUs */
+
 #include <mono/metadata/domain-internals.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/threads.h>
@@ -54,9 +53,9 @@
 #undef EPOLL_DEBUG
 
 /* maximum number of worker threads */
-static int mono_max_worker_threads = THREADS_PER_CPU;
-static int mono_min_worker_threads = 0;
-static int mono_io_max_worker_threads = THREADS_PER_CPU * 2;
+static int mono_max_worker_threads;
+static int mono_min_worker_threads;
+static int mono_io_max_worker_threads;
 
 /* current number of worker threads */
 static int mono_worker_threads = 0;
@@ -219,7 +218,7 @@ async_invoke_io_thread (gpointer data)
        MonoThread *thread;
        thread = mono_thread_current ();
        thread->threadpool_thread = TRUE;
-       thread->state |= ThreadState_Background;
+       ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
 
        for (;;) {
                MonoSocketAsyncResult *state;
@@ -241,16 +240,19 @@ async_invoke_io_thread (gpointer data)
                        }
 
                        domain = ((MonoObject *)ar)->vtable->domain;
+                       mono_thread_push_appdomain_ref (domain);
                        if (mono_domain_set (domain, FALSE)) {
                                ASyncCall *ac;
 
-                               mono_thread_push_appdomain_ref (domain);
                                mono_async_invoke (ar);
                                ac = (ASyncCall *) ar->data;
+                               /*
                                if (ac->msg->exc != NULL)
                                        mono_unhandled_exception (ac->msg->exc);
-                               mono_thread_pop_appdomain_ref ();
+                               */
+                               mono_domain_set (mono_get_root_domain (), TRUE);
                        }
+                       mono_thread_pop_appdomain_ref ();
                        InterlockedDecrement (&busy_io_worker_threads);
                }
 
@@ -304,7 +306,7 @@ start_io_thread_or_queue (MonoSocketAsyncResult *ares)
                InterlockedIncrement (&busy_io_worker_threads);
                InterlockedIncrement (&io_worker_threads);
                domain = ((ares) ? ((MonoObject *) ares)->vtable->domain : mono_domain_get ());
-               mono_thread_create (domain, async_invoke_io_thread, ares);
+               mono_thread_create (mono_get_root_domain (), async_invoke_io_thread, ares);
        } else {
                append_job (&io_queue_lock, &async_io_queue, ares);
                ReleaseSemaphore (io_job_added, 1, NULL);
@@ -378,7 +380,7 @@ socket_io_poll_main (gpointer p)
 
        thread = mono_thread_current ();
        thread->threadpool_thread = TRUE;
-       thread->state |= ThreadState_Background;
+       ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
 
        allocated = INITIAL_POLLFD_SIZE;
        pfds = g_new0 (mono_pollfd, allocated);
@@ -519,7 +521,7 @@ socket_io_epoll_main (gpointer p)
        epollfd = data->epollfd;
        thread = mono_thread_current ();
        thread->threadpool_thread = TRUE;
-       thread->state |= ThreadState_Background;
+       ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
        events = g_new0 (struct epoll_event, nevents);
 
        while (1) {
@@ -732,6 +734,9 @@ socket_io_init (SocketIOData *data)
        g_assert (data->pipe [0] != INVALID_SOCKET);
        closesocket (srv);
 #endif
+       mono_io_max_worker_threads = mono_max_worker_threads / 2;
+       if (mono_io_max_worker_threads < 10)
+               mono_io_max_worker_threads = 10;
 
        data->sock_to_state = g_hash_table_new (g_direct_hash, g_direct_equal);
 
@@ -885,6 +890,16 @@ static void
 mono_async_invoke (MonoAsyncResult *ares)
 {
        ASyncCall *ac = (ASyncCall *)ares->data;
+       MonoThread *thread = NULL;
+
+       if (ares->execution_context) {
+               /* use captured ExecutionContext (if available) */
+               thread = mono_thread_current ();
+               ares->original_context = thread->execution_context;
+               thread->execution_context = ares->execution_context;
+       } else {
+               ares->original_context = NULL;
+       }
 
        ac->msg->exc = NULL;
        ac->res = mono_message_invoke (ares->async_delegate, ac->msg, 
@@ -897,8 +912,16 @@ mono_async_invoke (MonoAsyncResult *ares)
                MonoObject *exc = NULL;
                void *pa = &ares;
                mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &exc);
-               if (!ac->msg->exc)
-                       ac->msg->exc = exc;
+               /* 'exc' will be the previous ac->msg->exc if not NULL and not
+                * catched. If catched, this will be set to NULL and the
+                * exception will not be printed. */
+               ac->msg->exc = exc;
+       }
+
+       /* restore original thread execution context if flow isn't suppressed, i.e. non null */
+       if (ares->original_context) {
+               thread->execution_context = ares->original_context;
+               ares->original_context = NULL;
        }
 
        /* notify listeners */
@@ -929,13 +952,13 @@ mono_thread_pool_init ()
        ares_htable = mono_g_hash_table_new (NULL, NULL);
        job_added = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
        GetSystemInfo (&info);
-       if (getenv ("MONO_THREADS_PER_CPU") != NULL) {
-               threads_per_cpu = atoi (getenv ("MONO_THREADS_PER_CPU"));
+       if (g_getenv ("MONO_THREADS_PER_CPU") != NULL) {
+               threads_per_cpu = atoi (g_getenv ("MONO_THREADS_PER_CPU"));
                if (threads_per_cpu <= 0)
                        threads_per_cpu = THREADS_PER_CPU;
        }
 
-       mono_max_worker_threads = threads_per_cpu * info.dwNumberOfProcessors;
+       mono_max_worker_threads = 20 + threads_per_cpu * info.dwNumberOfProcessors;
 }
 
 MonoAsyncResult *
@@ -990,7 +1013,7 @@ start_thread_or_queue (MonoAsyncResult *ares)
                InterlockedIncrement (&mono_worker_threads);
                InterlockedIncrement (&busy_worker_threads);
                domain = ((MonoObject *) ares)->vtable->domain;
-               mono_thread_create (domain, async_invoke_thread, ares);
+               mono_thread_create (mono_get_root_domain (), async_invoke_thread, ares);
        } else {
                append_job (&mono_delegate_section, &async_call_queue, ares);
                ReleaseSemaphore (job_added, 1, NULL);
@@ -1111,7 +1134,7 @@ async_invoke_thread (gpointer data)
  
        thread = mono_thread_current ();
        thread->threadpool_thread = TRUE;
-       thread->state |= ThreadState_Background;
+       ves_icall_System_Threading_Thread_SetState (thread, ThreadState_Background);
 
        for (;;) {
                MonoAsyncResult *ar;
@@ -1121,21 +1144,24 @@ async_invoke_thread (gpointer data)
                        /* worker threads invokes methods in different domains,
                         * so we need to set the right domain here */
                        domain = ((MonoObject *)ar)->vtable->domain;
+                       mono_thread_push_appdomain_ref (domain);
                        if (mono_domain_set (domain, FALSE)) {
                                ASyncCall *ac;
 
-                               mono_thread_push_appdomain_ref (domain);
                                mono_async_invoke (ar);
                                ac = (ASyncCall *) ar->data;
+                               /*
                                if (ac->msg->exc != NULL)
                                        mono_unhandled_exception (ac->msg->exc);
-                               mono_thread_pop_appdomain_ref ();
+                               */
+                               mono_domain_set (mono_get_root_domain (), TRUE);
                        }
+                       mono_thread_pop_appdomain_ref ();
                        InterlockedDecrement (&busy_worker_threads);
                }
 
                data = dequeue_job (&mono_delegate_section, &async_call_queue);
-       
+
                if (!data) {
                        guint32 wr;
                        int timeout = 10000;