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"
22 /* maximum number of worker threads */
23 int mono_max_worker_threads = 25; /* fixme: should be 25 per available CPU */
24 /* current number of worker threads */
25 int mono_worker_threads = 0;
27 /* current number of busy threads */
28 static int busy_worker_threads = 0;
30 /* we use this to store a reference to the AsyncResult to avoid GC */
31 static MonoGHashTable *ares_htable = NULL;
34 MonoMethodMessage *msg;
35 HANDLE wait_semaphore;
36 MonoMethod *cb_method;
37 MonoDelegate *cb_target;
43 static void async_invoke_thread (void);
45 static GList *async_call_queue = NULL;
48 mono_async_invoke (MonoAsyncResult *ares)
50 ASyncCall *ac = (ASyncCall *)ares->data;
53 ac->res = mono_message_invoke (ares->async_delegate, ac->msg,
54 &ac->msg->exc, &ac->out_args);
58 /* notify listeners */
59 ReleaseSemaphore (ac->wait_semaphore, 0x7fffffff, NULL);
61 /* call async callback if cb_method != null*/
63 MonoObject *exc = NULL;
65 mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &exc);
70 mono_g_hash_table_remove (ares_htable, ares);
74 mono_thread_pool_add (MonoObject *target, MonoMethodMessage *msg, MonoDelegate *async_callback,
77 MonoDomain *domain = mono_domain_get ();
78 MonoAsyncResult *ares;
82 ac = GC_MALLOC (sizeof (ASyncCall));
84 /* We'll leak the semaphore... */
85 ac = g_new0 (ASyncCall, 1);
87 ac->wait_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
92 ac->cb_method = mono_get_delegate_invoke (((MonoObject *)async_callback)->vtable->klass);
93 ac->cb_target = async_callback;
97 ares_htable = mono_g_hash_table_new (NULL, NULL);
99 ares = mono_async_result_new (domain, ac->wait_semaphore, ac->state, ac);
100 ares->async_delegate = target;
102 mono_g_hash_table_insert (ares_htable, ares, ares);
104 EnterCriticalSection (&mono_delegate_section);
105 async_call_queue = g_list_append (async_call_queue, ares);
106 ReleaseSemaphore (mono_delegate_semaphore, 1, NULL);
108 if (mono_worker_threads <= busy_worker_threads &&
109 mono_worker_threads < mono_max_worker_threads) {
110 mono_worker_threads++;
111 mono_thread_create (domain, async_invoke_thread, NULL);
113 LeaveCriticalSection (&mono_delegate_section);
119 mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc)
127 EnterCriticalSection (&mono_delegate_section);
128 /* check if already finished */
129 if (ares->endinvoke_called) {
130 *exc = (MonoObject *)mono_exception_from_name (mono_defaults.corlib, "System",
131 "InvalidOperationException");
132 LeaveCriticalSection (&mono_delegate_section);
136 ares->endinvoke_called = 1;
137 ac = (ASyncCall *)ares->data;
139 g_assert (ac != NULL);
141 if ((l = g_list_find (async_call_queue, ares))) {
142 async_call_queue = g_list_remove_link (async_call_queue, l);
145 LeaveCriticalSection (&mono_delegate_section);
149 mono_async_invoke (ares);
153 /* wait until we are really finished */
154 WaitForSingleObject (ac->wait_semaphore, INFINITE);
157 *out_args = ac->out_args;
164 async_invoke_thread ()
169 thread = mono_thread_current ();
170 thread->threadpool_thread = TRUE;
174 if (WaitForSingleObject (mono_delegate_semaphore, 500) == WAIT_TIMEOUT) {
175 EnterCriticalSection (&mono_delegate_section);
176 mono_worker_threads--;
177 LeaveCriticalSection (&mono_delegate_section);
182 EnterCriticalSection (&mono_delegate_section);
184 if (async_call_queue) {
187 ar = (MonoAsyncResult *)async_call_queue->data;
188 tmp = async_call_queue;
189 async_call_queue = g_list_remove_link (async_call_queue, async_call_queue);
194 LeaveCriticalSection (&mono_delegate_section);
198 busy_worker_threads++;
200 LeaveCriticalSection (&mono_delegate_section);
201 /* worker threads invokes methods in different domains,
202 * so we need to set the right domain here */
203 domain = ((MonoObject *)ar)->vtable->domain;
204 mono_domain_set (domain);
206 mono_async_invoke (ar);
208 EnterCriticalSection (&mono_delegate_section);
209 busy_worker_threads--;
210 LeaveCriticalSection (&mono_delegate_section);
214 g_assert_not_reached ();