Patch for bug #62532 implemention of a kqueue/kevent based FileSystemWatcher.
[mono.git] / mono / metadata / threadpool.c
index 04acc64e885247a70877a43046dbe5253e3d94d9..0803f0f846299acfbcc14cc917797b6cb2dc269a 100644 (file)
 #define _WIN32_WINNT 0x0500
 #endif
 
-#include <mono/metadata/appdomain.h>
+#include <mono/metadata/domain-internals.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/threads.h>
+#include <mono/metadata/threads-types.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/file-io.h>
 #include <mono/metadata/monitor.h>
 
 /* maximum number of worker threads */
 int mono_max_worker_threads = 25; /* fixme: should be 25 per available CPU */
-int mono_min_worker_threads = 0;
+static int mono_min_worker_threads = 0;
 
 /* current number of worker threads */
 static int mono_worker_threads = 0;
 
 /* current number of busy threads */
-int busy_worker_threads = 0;
+static int busy_worker_threads = 0;
 
 /* we use this to store a reference to the AsyncResult to avoid GC */
 static MonoGHashTable *ares_htable = NULL;
@@ -81,7 +82,9 @@ mono_async_invoke (MonoAsyncResult *ares)
        }
 
        /* notify listeners */
-       mono_monitor_try_enter ((MonoObject *) ares, INFINITE);
+       if(!mono_monitor_enter ((MonoObject *) ares))
+               return;
+       
        if (ares->handle != NULL) {
                ac->wait_event = ((MonoWaitHandle *) ares->handle)->handle;
                SetEvent (ac->wait_event);
@@ -119,6 +122,7 @@ mono_thread_pool_add (MonoObject *target, MonoMethodMessage *msg, MonoDelegate *
        ares->async_delegate = target;
 
        if (!ares_htable) {
+               MONO_GC_REGISTER_ROOT (ares_htable);
                ares_htable = mono_g_hash_table_new (NULL, NULL);
                job_added = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
        }
@@ -149,7 +153,10 @@ mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject
        *out_args = NULL;
 
        /* check if already finished */
-       mono_monitor_try_enter ((MonoObject *) ares, INFINITE);
+       if (!mono_monitor_enter ((MonoObject *) ares)) {
+               return NULL;
+       }
+       
        if (ares->endinvoke_called) {
                *exc = (MonoObject *)mono_exception_from_name (mono_defaults.corlib, "System", 
                                              "InvalidOperationException");
@@ -169,7 +176,7 @@ mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject
                        ares->handle = (MonoObject *) mono_wait_handle_new (mono_object_domain (ares), ac->wait_event);
                }
                mono_monitor_exit ((MonoObject *) ares);
-               WaitForSingleObject (ac->wait_event, INFINITE);
+               WaitForSingleObjectEx (ac->wait_event, INFINITE, TRUE);
        } else {
                mono_monitor_exit ((MonoObject *) ares);
        }
@@ -246,15 +253,31 @@ async_invoke_thread (gpointer data)
 
                data = dequeue_job ();
        
-               if (!data && WaitForSingleObject (job_added, 500) != WAIT_TIMEOUT)
-                       data = dequeue_job ();
+               if (!data) {
+                       guint32 wr;
+                       int timeout = 500;
+                       guint32 start_time = GetTickCount ();
+                       
+                       do {
+                               wr = WaitForSingleObjectEx (job_added, (guint32)timeout, TRUE);
+                               mono_thread_interruption_checkpoint ();
+                       
+                               timeout -= GetTickCount () - start_time;
+                       
+                               if (wr != WAIT_TIMEOUT)
+                                       data = dequeue_job ();
+                       }
+                       while (!data && timeout > 0);
+               }
                
                if (!data) {
                        workers = (int) InterlockedCompareExchange (&mono_worker_threads, 0, -1); 
                        min = (int) InterlockedCompareExchange (&mono_min_worker_threads, 0, -1); 
        
                        while (!data && workers <= min) {
-                               WaitForSingleObject (job_added, INFINITE);
+                               WaitForSingleObjectEx (job_added, INFINITE, TRUE);
+                               mono_thread_interruption_checkpoint ();
+                       
                                data = dequeue_job ();
                                workers = (int) InterlockedCompareExchange (&mono_worker_threads, 0, -1); 
                                min = (int) InterlockedCompareExchange (&mono_min_worker_threads, 0, -1); 
@@ -305,12 +328,16 @@ ves_icall_System_Threading_ThreadPool_GetMinThreads (gint *workerThreads, gint *
        *completionPortThreads = 0;
 }
 
-void
+MonoBoolean
 ves_icall_System_Threading_ThreadPool_SetMinThreads (gint workerThreads, gint completionPortThreads)
 {
        MONO_ARCH_SAVE_REGS;
 
+       if (workerThreads < 0 || workerThreads > mono_max_worker_threads)
+               return FALSE;
        InterlockedExchange (&mono_min_worker_threads, workerThreads);
+       /* FIXME: should actually start the idle threads if needed */
+       return TRUE;
 }
 
 static void