2 * threadpool.c: global thread pool
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2001 Ximian, Inc.
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/threads.h>
16 #include <mono/metadata/exception.h>
17 #ifndef PLATFORM_WIN32
18 #include "mono/io-layer/wapi.h"
19 #include "mono/io-layer/uglify.h"
22 #include "threadpool.h"
25 * - worker threads need to be initialized correctly.
26 * - worker threads should be domain specific
29 /* maximum number of worker threads */
30 int mono_worker_threads = 1;
32 static int workers = 0;
35 MonoMethodMessage *msg;
36 HANDLE wait_semaphore;
37 MonoMethod *cb_method;
38 MonoDelegate *cb_target;
44 static void async_invoke_thread (void);
46 static GList *async_call_queue = NULL;
49 mono_async_invoke (MonoAsyncResult *ares)
51 ASyncCall *ac = (ASyncCall *)ares->data;
54 ac->res = mono_message_invoke (ares->async_delegate, ac->msg,
55 &ac->msg->exc, &ac->out_args);
59 /* notify listeners */
60 ReleaseSemaphore (ac->wait_semaphore, 0x7fffffff, NULL);
62 /* call async callback if cb_method != null*/
64 MonoObject *exc = NULL;
66 mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &exc);
73 mono_thread_pool_add (MonoObject *target, MonoMethodMessage *msg, MonoDelegate *async_callback,
76 MonoDomain *domain = mono_domain_get ();
77 MonoAsyncResult *ares;
80 ac = g_new0 (ASyncCall, 1);
81 ac->wait_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
86 ac->cb_method = mono_get_delegate_invoke (((MonoObject *)async_callback)->vtable->klass);
87 ac->cb_target = async_callback;
90 ares = mono_async_result_new (domain, ac->wait_semaphore, ac->state, ac);
91 ares->async_delegate = target;
93 EnterCriticalSection (&mono_delegate_section);
94 async_call_queue = g_list_append (async_call_queue, ares);
95 ReleaseSemaphore (mono_delegate_semaphore, 1, NULL);
100 thread = mono_thread_create (domain, async_invoke_thread);
101 g_assert (thread != NULL);
103 LeaveCriticalSection (&mono_delegate_section);
109 mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc)
117 EnterCriticalSection (&mono_delegate_section);
118 /* check if already finished */
119 if (ares->endinvoke_called) {
120 *exc = (MonoObject *)mono_exception_from_name (mono_defaults.corlib, "System",
121 "InvalidOperationException");
122 LeaveCriticalSection (&mono_delegate_section);
126 ares->endinvoke_called = 1;
127 ac = (ASyncCall *)ares->data;
129 g_assert (ac != NULL);
131 if ((l = g_list_find (async_call_queue, ares))) {
132 async_call_queue = g_list_remove_link (async_call_queue, l);
133 mono_async_invoke (ares);
135 LeaveCriticalSection (&mono_delegate_section);
137 /* wait until we are really finished */
138 WaitForSingleObject (ac->wait_semaphore, INFINITE);
141 *out_args = ac->out_args;
147 async_invoke_thread ()
153 gboolean new_worker = FALSE;
155 if (WaitForSingleObject (mono_delegate_semaphore, 500) == WAIT_TIMEOUT) {
156 EnterCriticalSection (&mono_delegate_section);
158 LeaveCriticalSection (&mono_delegate_section);
163 EnterCriticalSection (&mono_delegate_section);
165 if (async_call_queue) {
166 if ((g_list_length (async_call_queue) > 1) &&
167 (workers < mono_worker_threads)) {
172 ar = (MonoAsyncResult *)async_call_queue->data;
173 async_call_queue = g_list_remove_link (async_call_queue, async_call_queue);
177 LeaveCriticalSection (&mono_delegate_section);
182 /* worker threads invokes methods in different domains,
183 * so we need to set the right domain here */
184 domain = ((MonoObject *)ar)->vtable->domain;
185 mono_domain_set (domain);
188 mono_thread_create (domain, async_invoke_thread);
190 mono_async_invoke (ar);
193 g_assert_not_reached ();