Wed Aug 14 17:26:27 CEST 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Author:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13
14 #if HAVE_BOEHM_GC
15 #include <gc/gc.h>
16 #endif
17
18 #include <mono/metadata/object.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/assembly.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/socket-io.h>
24
25 HANDLE mono_delegate_semaphore = NULL;
26 CRITICAL_SECTION mono_delegate_section;
27 int mono_runtime_shutdown = 0;
28
29 /*
30  * mono_runtime_init:
31  * @domain: domain returned by mono_init ()
32  *
33  * Initialize the core AppDomain: this function will run also some
34  * IL initialization code, so it needs the execution engine to be fully 
35  * operational.
36  */
37 void
38 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb)
39 {
40         MonoAppDomainSetup *setup;
41         MonoAppDomain *ad;
42         MonoClass *class;
43         
44         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
45         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
46         ves_icall_System_AppDomainSetup_InitAppDomainSetup (setup);
47
48         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
49         ad = (MonoAppDomain *) mono_object_new (domain, class);
50         ad->data = domain;
51         domain->domain = ad;
52         domain->setup = setup;
53
54         mono_delegate_semaphore = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
55         g_assert (mono_delegate_semaphore != INVALID_HANDLE_VALUE);
56         InitializeCriticalSection (&mono_delegate_section);
57         
58         mono_thread_init (domain, start_cb);
59
60         mono_network_init ();
61
62         return;
63 }
64
65 void
66 mono_runtime_cleanup (MonoDomain *domain)
67 {
68         mono_runtime_shutdown = 1;
69
70         /* signal all waiters in order to stop all workers (max. 0xffff) */
71         ReleaseSemaphore (mono_delegate_semaphore, 0xffff, NULL);
72
73         mono_thread_cleanup ();
74
75         /* Do this after the thread cleanup, because subthreads might
76          * still be doing socket calls.
77          */
78         mono_network_cleanup ();
79 }
80
81 void
82 ves_icall_System_AppDomainSetup_InitAppDomainSetup (MonoAppDomainSetup *setup)
83 {
84         /* FIXME: implement me */
85 }
86
87 /**
88  * mono_domain_transfer_object:
89  * @src: the source domain
90  * @dst: the destination domain
91  * @obj: the object to transfer
92  *
93  * This function is used to transfer objects between domains. This is done by
94  * marshalling or serialisation. 
95  */
96 static MonoObject *
97 mono_domain_transfer_object (MonoDomain *src, MonoDomain *dst, MonoObject *obj)
98 {
99         MonoClass *klass;
100         MonoObject *res;        
101
102         if (!obj)
103                 return NULL;
104
105         g_assert (obj->vtable->domain == src);
106
107         /* fixme: transfer an object from one domain into another */
108
109         klass = obj->vtable->klass;
110
111         if (MONO_CLASS_IS_ARRAY (klass)) {
112                 MonoArray *ao = (MonoArray *)obj;
113                 int esize, ecount, i;
114                 guint32 *sizes;
115                 
116                 esize = mono_array_element_size (klass);
117                 if (ao->bounds == NULL) {
118                         ecount = mono_array_length (ao);
119                         res = (MonoObject *)mono_array_new_full (dst, klass, &ecount, NULL);
120                 }
121                 else {
122                         sizes = alloca (klass->rank * sizeof(guint32) * 2);
123                         ecount = 1;
124                         for (i = 0; i < klass->rank; ++i) {
125                                 sizes [i] = ao->bounds [i].length;
126                                 ecount *= ao->bounds [i].length;
127                                 sizes [i + klass->rank] = ao->bounds [i].lower_bound;
128                         }
129                         res = (MonoObject *)mono_array_new_full (dst, klass, sizes, sizes + klass->rank);
130                 }
131                 if (klass->element_class->valuetype) {
132                         memcpy (((MonoArray *)res)->vector, ao->vector, esize * ecount);
133                 } else {
134                         g_assert (esize == sizeof (gpointer));
135                         for (i = 0; i < ecount; i++) {
136                                 gpointer *src_ea = (gpointer *)mono_array_addr_with_size (ao, esize, i);
137                                 gpointer *dst_ea = (gpointer *)mono_array_addr_with_size ((MonoArray *)res, esize, i);
138
139                                 *dst_ea = mono_domain_transfer_object (src, dst, *src_ea);
140                         }
141                 }
142         } else if (klass->valuetype) {
143                 res = mono_value_box (dst, klass, (char *)obj + sizeof (MonoObject));
144         } else if (klass == mono_defaults.string_class) {
145                 MonoString *str = (MonoString *)obj;
146                 res = (MonoObject *)mono_string_new_utf16 (dst, 
147                         (const guint16 *)mono_string_chars (str), str->length); 
148         } else {
149                 /* FIXME: we need generic marshalling code here */
150                 g_assert_not_reached ();
151         }
152         
153         return res;
154 }
155
156 MonoObject *
157 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
158 {
159         MonoDomain *add = ad->data;
160         MonoDomain *cur = mono_domain_get ();
161         MonoObject *o;
162         char *str;
163
164         g_assert (ad != NULL);
165         g_assert (name != NULL);
166
167         str = mono_string_to_utf8 (name);
168
169         mono_domain_lock (add);
170         if (!strcmp (str, "APPBASE"))
171                 o = (MonoObject *)add->setup->application_base;
172         else if (!strcmp (str, "APP_CONFIG_FILE"))
173                 o = (MonoObject *)add->setup->configuration_file;
174         else if (!strcmp (str, "DYNAMIC_BASE"))
175                 o = (MonoObject *)add->setup->dynamic_base;
176         else if (!strcmp (str, "APP_NAME"))
177                 o = (MonoObject *)add->setup->application_name;
178         else if (!strcmp (str, "CACHE_BASE"))
179                 o = (MonoObject *)add->setup->cache_path;
180         else if (!strcmp (str, "PRIVATE_BINPATH"))
181                 o = (MonoObject *)add->setup->private_bin_path;
182         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
183                 o = (MonoObject *)add->setup->private_bin_path_probe;
184         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
185                 o = (MonoObject *)add->setup->shadow_copy_directories;
186         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
187                 o = (MonoObject *)add->setup->shadow_copy_files;
188         else 
189                 o = mono_g_hash_table_lookup (add->env, name);
190
191         mono_domain_unlock (add);
192         g_free (str);
193
194         if (!o)
195                 return NULL;
196
197         return mono_domain_transfer_object (add, cur, o);
198 }
199
200 void
201 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
202 {
203         MonoDomain *add = ad->data;
204         MonoDomain *cur = mono_domain_get ();
205         MonoObject *o;
206
207         g_assert (ad != NULL);
208         g_assert (name != NULL);
209
210         o = mono_domain_transfer_object (cur, add, data);
211
212         mono_domain_lock (add);
213         g_hash_table_insert (add->env, name, o);
214
215         mono_domain_unlock (add);
216 }
217
218 MonoAppDomainSetup *
219 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
220 {
221         g_assert (ad != NULL);
222         g_assert (ad->data != NULL);
223
224         return ad->data->setup;
225 }
226
227 MonoString *
228 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
229 {
230         g_assert (ad != NULL);
231         g_assert (ad->data != NULL);
232
233         return mono_string_new (ad->data, ad->data->friendly_name);
234 }
235
236 MonoAppDomain *
237 ves_icall_System_AppDomain_getCurDomain ()
238 {
239         MonoDomain *add = mono_domain_get ();
240         return add->domain;
241 }
242
243 MonoAppDomain *
244 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
245 {
246         MonoDomain *domain = mono_domain_get (); 
247         MonoClass *adclass;
248         MonoAppDomain *ad;
249         MonoDomain *data;
250         
251         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
252         
253         /* FIXME: pin all those objects */
254         ad = (MonoAppDomain *) mono_object_new (domain, adclass);
255         ad->data = data = mono_domain_create ();
256         data->domain = ad;
257         data->setup = setup;
258         data->friendly_name = mono_string_to_utf8 (friendly_name);
259
260         /* FIXME: what to do next ? */
261
262         return ad;
263 }
264
265 typedef struct {
266         MonoArray *res;
267         MonoDomain *domain;
268         int idx;
269 } add_assembly_helper_t;
270
271 static void
272 add_assembly (gpointer key, gpointer value, gpointer user_data)
273 {
274         add_assembly_helper_t *ah = (add_assembly_helper_t *) user_data;
275
276         mono_array_set (ah->res, gpointer, ah->idx++, mono_assembly_get_object (ah->domain, value));
277 }
278
279 MonoArray *
280 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad)
281 {
282         MonoDomain *domain = ad->data; 
283         static MonoClass *System_Reflection_Assembly;
284         MonoArray *res;
285         add_assembly_helper_t ah;
286         
287         if (!System_Reflection_Assembly)
288                 System_Reflection_Assembly = mono_class_from_name (
289                         mono_defaults.corlib, "System.Reflection", "Assembly");
290
291         res = mono_array_new (domain, System_Reflection_Assembly, g_hash_table_size (domain->assemblies));
292
293         ah.domain = domain;
294         ah.res = res;
295         ah.idx = 0;
296         mono_domain_lock (domain);
297         g_hash_table_foreach (domain->assemblies, add_assembly, &ah);
298         mono_domain_unlock (domain);
299
300         return res;
301 }
302
303 MonoReflectionAssembly *
304 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname)
305 {
306         MonoDomain *domain = mono_domain_get ();
307         char *name, *filename;
308         MonoImageOpenStatus status = MONO_IMAGE_OK;
309         MonoAssembly *ass;
310
311         name = filename = mono_string_to_utf8 (fname);
312
313         /* FIXME: move uri handling to mono_assembly_open */
314         if (strncmp (filename, "file://", 7) == 0)
315                 filename += 7;
316
317         ass = mono_assembly_open (filename, &status);
318         
319         g_free (name);
320
321         if (!ass){
322                 MonoException *exc = mono_get_exception_file_not_found (fname);
323                 mono_raise_exception (exc);
324         }
325
326         return mono_assembly_get_object (domain, ass);
327 }
328
329
330 MonoReflectionAssembly *
331 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoReflectionAssemblyName *assRef, MonoObject *evidence)
332 {
333         MonoDomain *domain = ad->data; 
334         char *name;
335         MonoImageOpenStatus status = MONO_IMAGE_OK;
336         MonoAssembly *ass;
337         MonoAssemblyName aname;
338
339         memset (&aname, 0, sizeof (aname));
340
341         /* FIXME : examine evidence? */
342
343         g_assert (assRef != NULL);
344         g_assert (assRef->name != NULL);
345
346         /* FIXME : examine version, culture info */
347
348         aname.name = name = mono_string_to_utf8 (assRef->name);
349
350         ass = mono_assembly_load (&aname, NULL, &status);
351         
352         g_free (name);
353
354         if (!ass) {
355                 /* FIXME: it doesn't make much sense since we really don't have a filename ... */
356                 MonoException *exc = mono_get_exception_file_not_found (assRef->name);
357                 mono_raise_exception (exc);
358         }
359
360         return mono_assembly_get_object (domain, ass);
361 }
362
363 void
364 ves_icall_System_AppDomain_Unload (MonoAppDomain *ad)
365 {
366         mono_domain_unload (ad->data, FALSE);
367 }
368
369 gint32
370 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, MonoString *file, 
371                                             MonoObject *evidence, MonoArray *args)
372 {
373         MonoDomain *cdom = mono_domain_get ();
374         MonoAssembly *assembly;
375         MonoImage *image;
376         MonoMethod *method;
377         MonoObject *margs;
378         char *filename;
379         gint32 res;
380
381         mono_domain_set (ad->data);
382
383         filename = mono_string_to_utf8 (file);
384         assembly = mono_assembly_open (filename, NULL);
385         g_free (filename);
386
387         if (!assembly) {
388                 mono_raise_exception ((MonoException *)mono_exception_from_name (
389                         mono_defaults.corlib, "System.IO", "FileNotFoundException"));
390         }
391
392         image = assembly->image;
393         method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
394
395         if (!method)
396                 g_error ("No entry point method found in %s", image->name);
397
398         margs = mono_domain_transfer_object (cdom, ad->data, (MonoObject *)args);
399         res = mono_runtime_exec_main (method, (MonoArray *)margs, NULL);
400
401         mono_domain_set (cdom);
402
403         return res;
404 }
405