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 #include <mono/io-layer/io-layer.h>
18 #include <mono/os/gc_wrapper.h>
20 #include "threadpool.h"
23 * - worker threads need to be initialized correctly.
24 * - worker threads should be domain specific
27 /* maximum number of worker threads */
28 int mono_worker_threads = 1;
30 static int workers = 0;
33 MonoMethodMessage *msg;
34 HANDLE wait_semaphore;
35 MonoMethod *cb_method;
36 MonoDelegate *cb_target;
42 static void async_invoke_thread (void);
44 static GList *async_call_queue = NULL;
47 mono_async_invoke (MonoAsyncResult *ares)
49 ASyncCall *ac = (ASyncCall *)ares->data;
52 ac->res = mono_message_invoke (ares->async_delegate, ac->msg,
53 &ac->msg->exc, &ac->out_args);
57 /* notify listeners */
58 ReleaseSemaphore (ac->wait_semaphore, 0x7fffffff, NULL);
60 /* call async callback if cb_method != null*/
62 MonoObject *exc = NULL;
64 mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &exc);
72 async_call_finalizer (void *o, void *data)
76 CloseHandle (ac->wait_semaphore);
81 mono_thread_pool_add (MonoObject *target, MonoMethodMessage *msg, MonoDelegate *async_callback,
84 MonoDomain *domain = mono_domain_get ();
85 MonoAsyncResult *ares;
89 ac = GC_MALLOC (sizeof (ASyncCall));
90 GC_REGISTER_FINALIZER_NO_ORDER (ac, async_call_finalizer, NULL, NULL, NULL);
92 /* We'll leak the semaphore... */
93 ac = g_new0 (ASyncCall, 1);
95 ac->wait_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
100 ac->cb_method = mono_get_delegate_invoke (((MonoObject *)async_callback)->vtable->klass);
101 ac->cb_target = async_callback;
104 ares = mono_async_result_new (domain, ac->wait_semaphore, ac->state, ac);
105 ares->async_delegate = target;
107 EnterCriticalSection (&mono_delegate_section);
108 async_call_queue = g_list_append (async_call_queue, ares);
109 ReleaseSemaphore (mono_delegate_semaphore, 1, NULL);
113 mono_thread_create (domain, async_invoke_thread, NULL);
115 LeaveCriticalSection (&mono_delegate_section);
121 mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc)
129 EnterCriticalSection (&mono_delegate_section);
130 /* check if already finished */
131 if (ares->endinvoke_called) {
132 *exc = (MonoObject *)mono_exception_from_name (mono_defaults.corlib, "System",
133 "InvalidOperationException");
134 LeaveCriticalSection (&mono_delegate_section);
138 ares->endinvoke_called = 1;
139 ac = (ASyncCall *)ares->data;
141 g_assert (ac != NULL);
143 if ((l = g_list_find (async_call_queue, ares))) {
144 async_call_queue = g_list_remove_link (async_call_queue, l);
145 mono_async_invoke (ares);
147 LeaveCriticalSection (&mono_delegate_section);
149 /* wait until we are really finished */
150 WaitForSingleObject (ac->wait_semaphore, INFINITE);
153 *out_args = ac->out_args;
159 async_invoke_thread ()
165 gboolean new_worker = FALSE;
167 if (WaitForSingleObject (mono_delegate_semaphore, 500) == WAIT_TIMEOUT) {
168 EnterCriticalSection (&mono_delegate_section);
170 LeaveCriticalSection (&mono_delegate_section);
175 EnterCriticalSection (&mono_delegate_section);
177 if (async_call_queue) {
178 if ((g_list_length (async_call_queue) > 1) &&
179 (workers < mono_worker_threads)) {
184 ar = (MonoAsyncResult *)async_call_queue->data;
185 async_call_queue = g_list_remove_link (async_call_queue, async_call_queue);
189 LeaveCriticalSection (&mono_delegate_section);
194 /* worker threads invokes methods in different domains,
195 * so we need to set the right domain here */
196 domain = ((MonoObject *)ar)->vtable->domain;
197 mono_domain_set (domain);
200 mono_thread_create (domain, async_invoke_thread, NULL);
202 mono_async_invoke (ar);
205 g_assert_not_reached ();