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>
19 #include "threadpool.h"
22 * - worker threads need to be initialized correctly.
23 * - worker threads should be domain specific
26 /* maximum number of worker threads */
27 int mono_worker_threads = 1;
29 static int workers = 0;
32 MonoMethodMessage *msg;
33 HANDLE wait_semaphore;
34 MonoMethod *cb_method;
35 MonoDelegate *cb_target;
41 static void async_invoke_thread (void);
43 static GList *async_call_queue = NULL;
46 mono_async_invoke (MonoAsyncResult *ares)
48 ASyncCall *ac = (ASyncCall *)ares->data;
51 ac->res = mono_message_invoke (ares->async_delegate, ac->msg,
52 &ac->msg->exc, &ac->out_args);
56 /* notify listeners */
57 ReleaseSemaphore (ac->wait_semaphore, 0x7fffffff, NULL);
59 /* call async callback if cb_method != null*/
61 MonoObject *exc = NULL;
63 mono_runtime_invoke (ac->cb_method, ac->cb_target, pa, &exc);
70 mono_thread_pool_add (MonoObject *target, MonoMethodMessage *msg, MonoDelegate *async_callback,
73 MonoDomain *domain = mono_domain_get ();
74 MonoAsyncResult *ares;
77 ac = g_new0 (ASyncCall, 1);
78 ac->wait_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
83 ac->cb_method = mono_get_delegate_invoke (((MonoObject *)async_callback)->vtable->klass);
84 ac->cb_target = async_callback;
87 ares = mono_async_result_new (domain, ac->wait_semaphore, ac->state, ac);
88 ares->async_delegate = target;
90 EnterCriticalSection (&mono_delegate_section);
91 async_call_queue = g_list_append (async_call_queue, ares);
92 ReleaseSemaphore (mono_delegate_semaphore, 1, NULL);
96 mono_thread_create (domain, async_invoke_thread, NULL);
98 LeaveCriticalSection (&mono_delegate_section);
104 mono_thread_pool_finish (MonoAsyncResult *ares, MonoArray **out_args, MonoObject **exc)
112 EnterCriticalSection (&mono_delegate_section);
113 /* check if already finished */
114 if (ares->endinvoke_called) {
115 *exc = (MonoObject *)mono_exception_from_name (mono_defaults.corlib, "System",
116 "InvalidOperationException");
117 LeaveCriticalSection (&mono_delegate_section);
121 ares->endinvoke_called = 1;
122 ac = (ASyncCall *)ares->data;
124 g_assert (ac != NULL);
126 if ((l = g_list_find (async_call_queue, ares))) {
127 async_call_queue = g_list_remove_link (async_call_queue, l);
128 mono_async_invoke (ares);
130 LeaveCriticalSection (&mono_delegate_section);
132 /* wait until we are really finished */
133 WaitForSingleObject (ac->wait_semaphore, INFINITE);
136 *out_args = ac->out_args;
142 async_invoke_thread ()
148 gboolean new_worker = FALSE;
150 if (WaitForSingleObject (mono_delegate_semaphore, 500) == WAIT_TIMEOUT) {
151 EnterCriticalSection (&mono_delegate_section);
153 LeaveCriticalSection (&mono_delegate_section);
158 EnterCriticalSection (&mono_delegate_section);
160 if (async_call_queue) {
161 if ((g_list_length (async_call_queue) > 1) &&
162 (workers < mono_worker_threads)) {
167 ar = (MonoAsyncResult *)async_call_queue->data;
168 async_call_queue = g_list_remove_link (async_call_queue, async_call_queue);
172 LeaveCriticalSection (&mono_delegate_section);
177 /* worker threads invokes methods in different domains,
178 * so we need to set the right domain here */
179 domain = ((MonoObject *)ar)->vtable->domain;
180 mono_domain_set (domain);
183 mono_thread_create (domain, async_invoke_thread, NULL);
185 mono_async_invoke (ar);
188 g_assert_not_reached ();