2009-12-04 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / metadata / threadpool.c
index 2a8d49bfe405a547477e0897196dd68663bdba12..4bada712599d22932d262dd2356cf68299fb4f90 100644 (file)
@@ -154,6 +154,14 @@ static MonoClass *async_call_klass;
 static MonoClass *socket_async_call_klass;
 static MonoClass *process_async_call_klass;
 
+/* Hooks */
+static MonoThreadPoolFunc tp_start_func;
+static MonoThreadPoolFunc tp_finish_func;
+static gpointer tp_hooks_user_data;
+static MonoThreadPoolItemFunc tp_item_begin_func;
+static MonoThreadPoolItemFunc tp_item_end_func;
+static gpointer tp_item_user_data;
+
 #define INIT_POLLFD(a, b, c) {(a)->fd = b; (a)->events = c; (a)->revents = 0;}
 enum {
        AIO_OP_FIRST,
@@ -180,7 +188,7 @@ socket_io_cleanup (SocketIOData *data)
 
        EnterCriticalSection (&data->io_lock);
        data->inited = 0;
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        closesocket (data->pipe [0]);
        closesocket (data->pipe [1]);
 #else
@@ -284,6 +292,8 @@ async_invoke_io_thread (gpointer data)
        idle_data.wait_handle = CreateEvent (NULL, FALSE, FALSE, NULL);
 
        thread = mono_thread_internal_current ();
+       if (tp_start_func)
+               tp_start_func (tp_hooks_user_data);
 
        version = mono_get_runtime_info ()->framework_version;
        for (;;) {
@@ -320,11 +330,15 @@ async_invoke_io_thread (gpointer data)
                                        continue;
                                }
                                if (mono_domain_set (domain, FALSE)) {
-                                       ASyncCall *ac;
+                                       /* ASyncCall *ac; */
 
+                                       if (tp_item_begin_func)
+                                               tp_item_begin_func (tp_item_user_data);
                                        mono_async_invoke (ar);
-                                       ac = (ASyncCall *) ar->object_data;
+                                       if (tp_item_end_func)
+                                               tp_item_end_func (tp_item_user_data);
                                        /*
+                                       ac = (ASyncCall *) ar->object_data;
                                        if (ac->msg->exc != NULL)
                                                mono_unhandled_exception (ac->msg->exc);
                                        */
@@ -356,6 +370,8 @@ async_invoke_io_thread (gpointer data)
                        InterlockedDecrement (&async_io_tp.nthreads);
                        CloseHandle (idle_data.wait_handle);
                        idle_data.wait_handle = NULL;
+                       if (tp_finish_func)
+                               tp_finish_func (tp_hooks_user_data);
                        return;
                }
                
@@ -499,7 +515,7 @@ socket_io_poll_main (gpointer p)
                                for (; i < allocated; i++)
                                        INIT_POLLFD (&pfds [i], -1, 0);
                        }
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
                        nread = read (data->pipe [0], one, 1);
 #else
                        nread = recv ((SOCKET) data->pipe [0], one, 1, 0);
@@ -693,7 +709,7 @@ mono_thread_pool_remove_socket (int sock)
        }
 }
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
 static void
 connect_hack (gpointer x)
 {
@@ -713,7 +729,7 @@ connect_hack (gpointer x)
 static void
 socket_io_init (SocketIOData *data)
 {
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        struct sockaddr_in server;
        struct sockaddr_in client;
        SOCKET srv;
@@ -746,7 +762,7 @@ socket_io_init (SocketIOData *data)
        data->epoll_disabled = TRUE;
 #endif
 
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
        if (data->epoll_disabled) {
                if (pipe (data->pipe) != 0) {
                        int err = errno;
@@ -808,7 +824,7 @@ socket_io_add_poll (MonoSocketAsyncResult *state)
        SocketIOData *data = &socket_io_data;
        int w;
 
-#if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD) || defined(PLATFORM_WIN32) || defined(PLATFORM_SOLARIS)
+#if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD) || defined(HOST_WIN32) || defined(PLATFORM_SOLARIS)
        /* select() for connect() does not work well on the Mac. Bug #75436. */
        /* Bug #77637 for the BSD 6 case */
        /* Bug #78888 for the Windows case */
@@ -835,7 +851,7 @@ socket_io_add_poll (MonoSocketAsyncResult *state)
        mono_g_hash_table_replace (data->sock_to_state, GINT_TO_POINTER (state->handle), list);
        LeaveCriticalSection (&data->io_lock);
        *msg = (char) state->operation;
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
        w = write (data->pipe [1], msg, 1);
        w = w;
 #else
@@ -1068,7 +1084,7 @@ mono_thread_pool_init ()
        cpu_count = mono_cpu_count ();
        n = 8 + 2 * cpu_count; /* 8 is minFreeThreads for ASP.NET */
        threadpool_init (&async_tp, n, n + threads_per_cpu * cpu_count, async_invoke_thread);
-#ifndef DISABLE_SOCKET
+#ifndef DISABLE_SOCKETS
        threadpool_init (&async_io_tp, 2 * cpu_count, 8 * cpu_count, async_invoke_io_thread);
 #endif
 
@@ -1289,6 +1305,7 @@ threadpool_queue_idle_thread (ThreadPool *tp, IdleThreadData *it)
        EnterCriticalSection (cs);
        if (tp->idle_threads == NULL) {
                it->die = TRUE;
+               LeaveCriticalSection (cs);
                return NULL; /* We are shutting down */
        }
        /*
@@ -1332,8 +1349,10 @@ threadpool_append_job (ThreadPool *tp, MonoObject *ar)
        cs = &tp->lock;
        threadpool_jobs_inc (ar); 
        EnterCriticalSection (cs);
-       if (tp->idle_threads == NULL)
+       if (tp->idle_threads == NULL) { 
+               LeaveCriticalSection (cs);
                return; /* We are shutting down */
+       }
        if (ar->vtable->domain->state == MONO_APPDOMAIN_UNLOADING ||
                        ar->vtable->domain->state == MONO_APPDOMAIN_UNLOADED) {
                LeaveCriticalSection (cs);
@@ -1481,6 +1500,8 @@ async_invoke_thread (gpointer data)
        idle_data.wait_handle = CreateEvent (NULL, FALSE, FALSE, NULL);
  
        thread = mono_thread_internal_current ();
+       if (tp_start_func)
+               tp_start_func (tp_hooks_user_data);
        version = mono_get_runtime_info ()->framework_version;
        for (;;) {
                MonoAsyncResult *ar;
@@ -1505,11 +1526,15 @@ async_invoke_thread (gpointer data)
                                }
 
                                if (mono_domain_set (domain, FALSE)) {
-                                       ASyncCall *ac;
+                                       /* ASyncCall *ac; */
 
+                                       if (tp_item_begin_func)
+                                               tp_item_begin_func (tp_item_user_data);
                                        mono_async_invoke (ar);
-                                       ac = (ASyncCall *) ar->object_data;
+                                       if (tp_item_end_func)
+                                               tp_item_end_func (tp_item_user_data);
                                        /*
+                                       ac = (ASyncCall *) ar->object_data;
                                        if (ac->msg->exc != NULL)
                                                mono_unhandled_exception (ac->msg->exc);
                                        */
@@ -1540,6 +1565,8 @@ async_invoke_thread (gpointer data)
                        InterlockedDecrement (&async_tp.nthreads);
                        CloseHandle (idle_data.wait_handle);
                        idle_data.wait_handle = NULL;
+                       if (tp_finish_func)
+                               tp_finish_func (tp_hooks_user_data);
                        return;
                }
                
@@ -1625,3 +1652,39 @@ ves_icall_System_Threading_ThreadPool_SetMaxThreads (gint workerThreads, gint co
        return TRUE;
 }
 
+/**
+ * mono_install_threadpool_thread_hooks
+ * @start_func: the function to be called right after a new threadpool thread is created. Can be NULL.
+ * @finish_func: the function to be called right before a thredpool thread is exiting. Can be NULL.
+ * @user_data: argument passed to @start_func and @finish_func.
+ *
+ * @start_fun will be called right after a threadpool thread is created and @finish_func right before a threadpool thread exits.
+ * The calls will be made from the thread itself.
+ */
+void
+mono_install_threadpool_thread_hooks (MonoThreadPoolFunc start_func, MonoThreadPoolFunc finish_func, gpointer user_data)
+{
+       tp_start_func = start_func;
+       tp_finish_func = finish_func;
+       tp_hooks_user_data = user_data;
+}
+
+/**
+ * mono_install_threadpool_item_hooks
+ * @begin_func: the function to be called before a threadpool work item processing starts.
+ * @end_func: the function to be called after a threadpool work item is finished.
+ * @user_data: argument passed to @begin_func and @end_func.
+ *
+ * The calls will be made from the thread itself and from the same AppDomain
+ * where the work item was executed.
+ *
+ */
+void
+mono_install_threadpool_item_hooks (MonoThreadPoolItemFunc begin_func, MonoThreadPoolItemFunc end_func, gpointer user_data)
+{
+       tp_item_begin_func = begin_func;
+       tp_item_end_func = end_func;
+       tp_item_user_data = user_data;
+}
+
+