2009-12-02 Jb Evain <jbevain@novell.com>
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Authors:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  */
12 #undef ASSEMBLY_LOAD_DEBUG
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25 #ifdef HAVE_UTIME_H
26 #include <utime.h>
27 #else
28 #ifdef HAVE_SYS_UTIME_H
29 #include <sys/utime.h>
30 #endif
31 #endif
32
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/object.h>
35 #include <mono/metadata/domain-internals.h>
36 #include "mono/metadata/metadata-internals.h"
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/socket-io.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/gc-internal.h>
43 #include <mono/metadata/mono-gc.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/monitor.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/mono-debug-debugger.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/file-io.h>
51 #include <mono/metadata/lock-tracer.h>
52 #include <mono/metadata/console-io.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/tokentype.h>
55 #include <mono/utils/mono-uri.h>
56 #include <mono/utils/mono-logger.h>
57 #include <mono/utils/mono-path.h>
58 #include <mono/utils/mono-stdlib.h>
59 #include <mono/utils/mono-io-portability.h>
60 #include <mono/utils/mono-error-internals.h>
61 #ifdef HOST_WIN32
62 #include <direct.h>
63 #endif
64
65 /*
66  * This is the version number of the corlib-runtime interface. When
67  * making changes to this interface (by changing the layout
68  * of classes the runtime knows about, changing icall signature or
69  * semantics etc), increment this variable. Also increment the
70  * pair of this variable in mscorlib in:
71  *       mcs/class/mscorlib/System/Environment.cs
72  *
73  * Changes which are already detected at runtime, like the addition
74  * of icalls, do not require an increment.
75  */
76 #define MONO_CORLIB_VERSION 87
77
78 typedef struct
79 {
80         int runtime_count;
81         int assemblybinding_count;
82         MonoDomain *domain;
83 } RuntimeConfig;
84
85 CRITICAL_SECTION mono_delegate_section;
86
87 #ifdef _EGLIB_MAJOR
88 /* Need to lock here because EGLIB has locking defined as no-ops, we can not depend on mono_strtod do the right locking */
89 /* Ideally this will be fixed in eglib */
90 CRITICAL_SECTION mono_strtod_mutex;
91 #endif
92
93
94 static gunichar2 process_guid [36];
95 static gboolean process_guid_set = FALSE;
96
97 static gboolean shutting_down = FALSE;
98
99 static gboolean no_exec = FALSE;
100
101 static MonoAssembly *
102 mono_domain_assembly_preload (MonoAssemblyName *aname,
103                               gchar **assemblies_path,
104                               gpointer user_data);
105
106 static MonoAssembly *
107 mono_domain_assembly_search (MonoAssemblyName *aname,
108                                                          gpointer user_data);
109
110 static MonoAssembly *
111 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
112                                                                           gpointer user_data);
113
114 static void
115 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
116
117 static void
118 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
119
120 static MonoAppDomain *
121 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
122
123 static char *
124 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
125
126 static MonoLoadFunc load_function = NULL;
127
128 void
129 mono_install_runtime_load (MonoLoadFunc func)
130 {
131         load_function = func;
132 }
133
134 MonoDomain*
135 mono_runtime_load (const char *filename, const char *runtime_version)
136 {
137         g_assert (load_function);
138         return load_function (filename, runtime_version);
139 }
140
141 /*
142  * mono_runtime_set_no_exec:
143  *
144  *   Instructs the runtime to operate in static mode, i.e. avoid/do not allow managed
145  * code execution. This is useful for running the AOT compiler on platforms which
146  * allow full-aot execution only.
147  * This should be called before mono_runtime_init ().
148  */
149 void
150 mono_runtime_set_no_exec (gboolean val)
151 {
152         no_exec = val;
153 }
154
155 gboolean
156 mono_runtime_get_no_exec (void)
157 {
158         return no_exec;
159 }
160
161 static void
162 create_exceptions (MonoDomain *domain)
163 {
164         MonoString *arg;
165
166         /*
167          * Create an instance early since we can't do it when there is no memory.
168          */
169         arg = mono_string_new (domain, "Out of memory");
170         domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
171         
172         /* 
173          * These two are needed because the signal handlers might be executing on
174          * an alternate stack, and Boehm GC can't handle that.
175          */
176         arg = mono_string_new (domain, "A null value was found where an object instance was required");
177         domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
178         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
179         domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
180
181         /* 
182          * This class is used during exception handling, so initialize it here, to prevent
183          * stack overflows while handling stack overflows.
184          */
185         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
186 }
187
188 /**
189  * mono_runtime_init:
190  * @domain: domain returned by mono_init ()
191  *
192  * Initialize the core AppDomain: this function will run also some
193  * IL initialization code, so it needs the execution engine to be fully 
194  * operational.
195  *
196  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
197  * we know the entry_assembly.
198  *
199  */
200 void
201 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
202                    MonoThreadAttachCB attach_cb)
203 {
204         MonoAppDomainSetup *setup;
205         MonoAppDomain *ad;
206         MonoClass *class;
207
208         mono_portability_helpers_init ();
209         
210         mono_gc_base_init ();
211         mono_monitor_init ();
212         mono_thread_pool_init ();
213         mono_marshal_init ();
214
215         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
216         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
217         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
218         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
219         mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
220         mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
221         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
222         mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
223
224         mono_thread_init (start_cb, attach_cb);
225
226         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
227         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
228
229         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
230         ad = (MonoAppDomain *) mono_object_new (domain, class);
231         ad->data = domain;
232         domain->domain = ad;
233         domain->setup = setup;
234
235         InitializeCriticalSection (&mono_delegate_section);
236
237 #ifdef _EGLIB_MAJOR
238         /* Needed until EGLIB is fixed #464316 */
239         InitializeCriticalSection (&mono_strtod_mutex);
240 #endif
241         
242         mono_thread_attach (domain);
243         mono_context_init (domain);
244         mono_context_set (domain->default_context);
245
246         mono_type_initialization_init ();
247
248         if (!mono_runtime_get_no_exec ())
249                 create_exceptions (domain);
250
251         /* GC init has to happen after thread init */
252         mono_gc_init ();
253
254 #ifndef DISABLE_SOCKETS
255         mono_network_init ();
256 #endif
257         
258         mono_console_init ();
259         mono_attach_init ();
260
261         mono_locks_tracer_init ();
262
263         /* mscorlib is loaded before we install the load hook */
264         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
265         
266         return;
267 }
268
269 static int
270 mono_get_corlib_version (void)
271 {
272         MonoClass *klass;
273         MonoClassField *field;
274         MonoObject *value;
275
276         klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
277         mono_class_init (klass);
278         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
279         if (!field)
280                 return -1;
281         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
282                 return -1;
283         value = mono_field_get_value_object (mono_domain_get (), field, NULL);
284         return *(gint32*)((gchar*)value + sizeof (MonoObject));
285 }
286
287 const char*
288 mono_check_corlib_version (void)
289 {
290         int version = mono_get_corlib_version ();
291         if (version != MONO_CORLIB_VERSION)
292                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
293         else
294                 return NULL;
295 }
296
297 void
298 mono_context_init (MonoDomain *domain)
299 {
300         MonoClass *class;
301         MonoAppContext *context;
302
303         class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
304         context = (MonoAppContext *) mono_object_new (domain, class);
305         context->domain_id = domain->domain_id;
306         context->context_id = 0;
307         domain->default_context = context;
308 }
309
310 /**
311  * mono_runtime_cleanup:
312  * @domain: unused.
313  *
314  * Internal routine.
315  *
316  * This must not be called while there are still running threads executing
317  * managed code.
318  */
319 void
320 mono_runtime_cleanup (MonoDomain *domain)
321 {
322         shutting_down = TRUE;
323
324         mono_attach_cleanup ();
325
326         /* This ends up calling any pending pending (for at most 2 seconds) */
327         mono_gc_cleanup ();
328
329         mono_thread_cleanup ();
330
331 #ifndef DISABLE_SOCKETS
332         mono_network_cleanup ();
333 #endif
334         mono_marshal_cleanup ();
335
336         mono_type_initialization_cleanup ();
337
338         mono_monitor_cleanup ();
339
340 #ifndef HOST_WIN32
341         _wapi_cleanup ();
342 #endif
343 }
344
345 static MonoDomainFunc quit_function = NULL;
346
347 void
348 mono_install_runtime_cleanup (MonoDomainFunc func)
349 {
350         quit_function = func;
351 }
352
353 void
354 mono_runtime_quit ()
355 {
356         if (quit_function != NULL)
357                 quit_function (mono_get_root_domain (), NULL);
358 }
359
360 /** 
361  * mono_runtime_set_shutting_down:
362  *
363  * Invoked by System.Environment.Exit to flag that the runtime
364  * is shutting down.
365  */
366 void
367 mono_runtime_set_shutting_down (void)
368 {
369         shutting_down = TRUE;
370 }
371
372 /**
373  * mono_runtime_is_shutting_down:
374  *
375  * Returns whether the runtime has been flagged for shutdown.
376  *
377  * This is consumed by the P:System.Environment.HasShutdownStarted
378  * property.
379  *
380  */
381 gboolean
382 mono_runtime_is_shutting_down (void)
383 {
384         return shutting_down;
385 }
386
387 /**
388  * mono_domain_create_appdomain:
389  * @friendly_name: The friendly name of the appdomain to create
390  * @configuration_file: The configuration file to initialize the appdomain with
391  * 
392  * Returns a MonoDomain initialized with the appdomain
393  */
394 MonoDomain *
395 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
396 {
397         MonoAppDomain *ad;
398         MonoAppDomainSetup *setup;
399         MonoClass *class;
400
401         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
402         setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
403         setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
404
405         ad = mono_domain_create_appdomain_internal (friendly_name, setup);
406
407         return mono_domain_from_appdomain (ad);
408 }
409
410 static MonoAppDomainSetup*
411 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
412 {
413         MonoDomain *caller_domain = mono_domain_get ();
414         MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
415         MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
416
417         mono_domain_set_internal (domain);
418
419         MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
420         MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
421         MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
422         MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
423         MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
424         MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
425         MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
426         MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
427         MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
428         MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
429         copy->publisher_policy = setup->publisher_policy;
430         copy->path_changed = setup->path_changed;
431         copy->loader_optimization = setup->loader_optimization;
432         copy->disallow_binding_redirects = setup->disallow_binding_redirects;
433         copy->disallow_code_downloads = setup->disallow_code_downloads;
434         MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
435         copy->disallow_appbase_probe = setup->disallow_appbase_probe;
436         MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
437         MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
438         MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
439
440         mono_domain_set_internal (caller_domain);
441
442         return copy;
443 }
444
445 static MonoAppDomain *
446 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
447 {
448         MonoError error;
449         MonoClass *adclass;
450         MonoAppDomain *ad;
451         MonoDomain *data;
452         char *shadow_location;
453         
454         MONO_ARCH_SAVE_REGS;
455
456         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
457
458         /* FIXME: pin all those objects */
459         data = mono_domain_create();
460
461         ad = (MonoAppDomain *) mono_object_new (data, adclass);
462         ad->data = data;
463         data->domain = ad;
464         data->friendly_name = g_strdup (friendly_name);
465
466         if (!setup->application_base) {
467                 /* Inherit from the root domain since MS.NET does this */
468                 MonoDomain *root = mono_get_root_domain ();
469                 if (root->setup->application_base)
470                         MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
471         }
472
473         mono_context_init (data);
474
475         mono_set_private_bin_path_from_config (data);
476         
477         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
478
479         data->setup = copy_app_domain_setup (data, setup);
480
481 #ifndef DISABLE_SHADOW_COPY
482         /*FIXME, guard this for when the debugger is not running */
483         shadow_location = get_shadow_assembly_location_base (data, &error);
484         if (!mono_error_ok (&error))
485                 mono_error_raise_exception (&error);
486         mono_debugger_event_create_appdomain (data, shadow_location);
487         g_free (shadow_location);
488 #endif
489
490         create_exceptions (data);
491
492         return ad;
493 }
494
495 /**
496  * mono_domain_has_type_resolve:
497  * @domain: application domains being looked up
498  *
499  * Returns true if the AppDomain.TypeResolve field has been
500  * set.
501  */
502 gboolean
503 mono_domain_has_type_resolve (MonoDomain *domain)
504 {
505         static MonoClassField *field = NULL;
506         MonoObject *o;
507
508         if (field == NULL) {
509                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
510                 g_assert (field);
511         }
512
513         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
514         return o != NULL;
515 }
516
517 /**
518  * mono_domain_try_type_resolve:
519  * @domain: application domainwhere the name where the type is going to be resolved
520  * @name: the name of the type to resolve or NULL.
521  * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
522  *
523  * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
524  * the assembly that matches name.
525  *
526  * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
527  *
528  * Returns: A MonoReflectionAssembly or NULL if not found
529  */
530 MonoReflectionAssembly *
531 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
532 {
533         MonoClass *klass;
534         void *params [1];
535         static MonoMethod *method = NULL;
536
537         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
538
539         if (method == NULL) {
540                 klass = domain->domain->mbr.obj.vtable->klass;
541                 g_assert (klass);
542
543                 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
544                 if (method == NULL) {
545                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
546                         return NULL;
547                 }
548         }
549
550         if (name)
551                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
552         else
553                 *params = tb;
554         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
555 }
556
557 /**
558  * mono_domain_owns_vtable_slot:
559  *
560  *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
561  */
562 gboolean
563 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
564 {
565         gboolean res;
566
567         mono_domain_lock (domain);
568         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
569         mono_domain_unlock (domain);
570         return res;
571 }
572
573 /**
574  * mono_domain_set:
575  * @domain: domain
576  * @force: force setting.
577  *
578  * Set the current appdomain to @domain. If @force is set, set it even
579  * if it is being unloaded.
580  *
581  * Returns:
582  *   TRUE on success;
583  *   FALSE if the domain is unloaded
584  */
585 gboolean
586 mono_domain_set (MonoDomain *domain, gboolean force)
587 {
588         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
589                 return FALSE;
590
591         mono_domain_set_internal (domain);
592
593         return TRUE;
594 }
595
596 MonoObject *
597 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
598 {
599         MonoDomain *add;
600         MonoObject *o;
601         char *str;
602
603         MONO_ARCH_SAVE_REGS;
604
605         g_assert (ad != NULL);
606         add = ad->data;
607         g_assert (add != NULL);
608
609         if (name == NULL)
610                 mono_raise_exception (mono_get_exception_argument_null ("name"));
611
612         str = mono_string_to_utf8 (name);
613
614         mono_domain_lock (add);
615
616         if (!strcmp (str, "APPBASE"))
617                 o = (MonoObject *)add->setup->application_base;
618         else if (!strcmp (str, "APP_CONFIG_FILE"))
619                 o = (MonoObject *)add->setup->configuration_file;
620         else if (!strcmp (str, "DYNAMIC_BASE"))
621                 o = (MonoObject *)add->setup->dynamic_base;
622         else if (!strcmp (str, "APP_NAME"))
623                 o = (MonoObject *)add->setup->application_name;
624         else if (!strcmp (str, "CACHE_BASE"))
625                 o = (MonoObject *)add->setup->cache_path;
626         else if (!strcmp (str, "PRIVATE_BINPATH"))
627                 o = (MonoObject *)add->setup->private_bin_path;
628         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
629                 o = (MonoObject *)add->setup->private_bin_path_probe;
630         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
631                 o = (MonoObject *)add->setup->shadow_copy_directories;
632         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
633                 o = (MonoObject *)add->setup->shadow_copy_files;
634         else 
635                 o = mono_g_hash_table_lookup (add->env, name);
636
637         mono_domain_unlock (add);
638         g_free (str);
639
640         if (!o)
641                 return NULL;
642
643         return o;
644 }
645
646 void
647 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
648 {
649         MonoDomain *add;
650
651         MONO_ARCH_SAVE_REGS;
652
653         g_assert (ad != NULL);
654         add = ad->data;
655         g_assert (add != NULL);
656
657         if (name == NULL)
658                 mono_raise_exception (mono_get_exception_argument_null ("name"));
659
660         mono_domain_lock (add);
661
662         mono_g_hash_table_insert (add->env, name, data);
663
664         mono_domain_unlock (add);
665 }
666
667 MonoAppDomainSetup *
668 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
669 {
670         MONO_ARCH_SAVE_REGS;
671
672         g_assert (ad != NULL);
673         g_assert (ad->data != NULL);
674
675         return ad->data->setup;
676 }
677
678 MonoString *
679 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
680 {
681         MONO_ARCH_SAVE_REGS;
682
683         g_assert (ad != NULL);
684         g_assert (ad->data != NULL);
685
686         return mono_string_new (ad->data, ad->data->friendly_name);
687 }
688
689 MonoAppDomain *
690 ves_icall_System_AppDomain_getCurDomain ()
691 {
692         MonoDomain *add = mono_domain_get ();
693
694         MONO_ARCH_SAVE_REGS;
695
696         return add->domain;
697 }
698
699 MonoAppDomain *
700 ves_icall_System_AppDomain_getRootDomain ()
701 {
702         MonoDomain *root = mono_get_root_domain ();
703
704         MONO_ARCH_SAVE_REGS;
705
706         return root->domain;
707 }
708
709 static char*
710 get_attribute_value (const gchar **attribute_names, 
711                      const gchar **attribute_values, 
712                      const char *att_name)
713 {
714         int n;
715         for (n = 0; attribute_names [n] != NULL; n++) {
716                 if (strcmp (attribute_names [n], att_name) == 0)
717                         return g_strdup (attribute_values [n]);
718         }
719         return NULL;
720 }
721
722 static void
723 start_element (GMarkupParseContext *context, 
724                const gchar         *element_name,
725                const gchar        **attribute_names,
726                const gchar        **attribute_values,
727                gpointer             user_data,
728                GError             **error)
729 {
730         RuntimeConfig *runtime_config = user_data;
731         
732         if (strcmp (element_name, "runtime") == 0) {
733                 runtime_config->runtime_count++;
734                 return;
735         }
736
737         if (strcmp (element_name, "assemblyBinding") == 0) {
738                 runtime_config->assemblybinding_count++;
739                 return;
740         }
741         
742         if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
743                 return;
744
745         if (strcmp (element_name, "probing") != 0)
746                 return;
747
748         g_free (runtime_config->domain->private_bin_path);
749         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
750         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
751                 g_free (runtime_config->domain->private_bin_path);
752                 runtime_config->domain->private_bin_path = NULL;
753                 return;
754         }
755 }
756
757 static void
758 end_element (GMarkupParseContext *context,
759              const gchar         *element_name,
760              gpointer             user_data,
761              GError             **error)
762 {
763         RuntimeConfig *runtime_config = user_data;
764         if (strcmp (element_name, "runtime") == 0)
765                 runtime_config->runtime_count--;
766         else if (strcmp (element_name, "assemblyBinding") == 0)
767                 runtime_config->assemblybinding_count--;
768 }
769
770 static const GMarkupParser
771 mono_parser = {
772         start_element,
773         end_element,
774         NULL,
775         NULL,
776         NULL
777 };
778
779 void
780 mono_set_private_bin_path_from_config (MonoDomain *domain)
781 {
782         MonoError error;
783         gchar *config_file, *text;
784         gsize len;
785         GMarkupParseContext *context;
786         RuntimeConfig runtime_config;
787         
788         if (!domain || !domain->setup || !domain->setup->configuration_file)
789                 return;
790
791         config_file = mono_string_to_utf8_checked (domain->setup->configuration_file, &error); 
792         if (!mono_error_ok (&error)) {
793                 mono_error_cleanup (&error);
794                 return;
795         }
796
797         if (!g_file_get_contents (config_file, &text, &len, NULL)) {
798                 g_free (config_file);
799                 return;
800         }
801         g_free (config_file);
802
803         runtime_config.runtime_count = 0;
804         runtime_config.assemblybinding_count = 0;
805         runtime_config.domain = domain;
806         
807         context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
808         if (g_markup_parse_context_parse (context, text, len, NULL))
809                 g_markup_parse_context_end_parse (context, NULL);
810         g_markup_parse_context_free (context);
811         g_free (text);
812 }
813
814 MonoAppDomain *
815 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
816 {
817         char *fname = mono_string_to_utf8 (friendly_name);
818         MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
819         
820         g_free (fname);
821
822         return ad;
823 }
824
825 MonoArray *
826 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
827 {
828         MonoDomain *domain = ad->data; 
829         MonoAssembly* ass;
830         static MonoClass *System_Reflection_Assembly;
831         MonoArray *res;
832         GSList *tmp;
833         int i;
834         GPtrArray *assemblies;
835
836         MONO_ARCH_SAVE_REGS;
837
838         if (!System_Reflection_Assembly)
839                 System_Reflection_Assembly = mono_class_from_name (
840                         mono_defaults.corlib, "System.Reflection", "Assembly");
841
842         /* 
843          * Make a copy of the list of assemblies because we can't hold the assemblies
844          * lock while creating objects etc.
845          */
846         assemblies = g_ptr_array_new ();
847         /* Need to skip internal assembly builders created by remoting */
848         mono_domain_assemblies_lock (domain);
849         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
850                 ass = tmp->data;
851                 if (refonly != ass->ref_only)
852                         continue;
853                 if (ass->corlib_internal)
854                         continue;
855                 g_ptr_array_add (assemblies, ass);
856         }
857         mono_domain_assemblies_unlock (domain);
858
859         res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
860         for (i = 0; i < assemblies->len; ++i) {
861                 ass = g_ptr_array_index (assemblies, i);
862                 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
863         }
864
865         g_ptr_array_free (assemblies, TRUE);
866
867         return res;
868 }
869
870 MonoReflectionAssembly *
871 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
872 {
873         MonoClass *klass;
874         MonoMethod *method;
875         MonoBoolean isrefonly;
876         gpointer params [2];
877
878         if (mono_runtime_get_no_exec ())
879                 return NULL;
880
881         g_assert (domain != NULL && fname != NULL);
882
883         klass = domain->domain->mbr.obj.vtable->klass;
884         g_assert (klass);
885         
886         method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
887         if (method == NULL) {
888                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
889                 return NULL;
890         }
891
892         isrefonly = refonly ? 1 : 0;
893         params [0] = fname;
894         params [1] = &isrefonly;
895         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
896 }
897
898 static MonoAssembly *
899 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
900                                                                           gpointer user_data)
901 {
902         gboolean refonly = GPOINTER_TO_UINT (user_data);
903         MonoReflectionAssembly *assembly;
904         MonoDomain *domain = mono_domain_get ();
905         char *aname_str;
906
907         aname_str = mono_stringify_assembly_name (aname);
908
909         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
910         assembly = mono_try_assembly_resolve (domain, mono_string_new (domain, aname_str), refonly);
911
912         g_free (aname_str);
913
914         if (assembly)
915                 return assembly->assembly;
916         else
917                 return NULL;
918 }
919         
920 /*
921  * LOCKING: assumes assemblies_lock in the domain is already locked.
922  */
923 static void
924 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
925 {
926         gint i;
927         GSList *tmp;
928         gboolean destroy_ht = FALSE;
929
930         if (!ass->aname.name)
931                 return;
932
933         if (!ht) {
934                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
935                 destroy_ht = TRUE;
936         }
937
938         /* FIXME: handle lazy loaded assemblies */
939         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
940                 g_hash_table_insert (ht, tmp->data, tmp->data);
941         }
942         if (!g_hash_table_lookup (ht, ass)) {
943                 mono_assembly_addref (ass);
944                 g_hash_table_insert (ht, ass, ass);
945                 domain->domain_assemblies = g_slist_prepend (domain->domain_assemblies, ass);
946                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s %p added to domain %s, ref_count=%d\n", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
947         }
948
949         if (ass->image->references) {
950                 for (i = 0; ass->image->references [i] != NULL; i++) {
951                         if (ass->image->references [i] != REFERENCE_MISSING)
952                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
953                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
954                                 }
955                 }
956         }
957         if (destroy_ht)
958                 g_hash_table_destroy (ht);
959 }
960
961 static void
962 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
963 {
964         static MonoClassField *assembly_load_field;
965         static MonoMethod *assembly_load_method;
966         MonoDomain *domain = mono_domain_get ();
967         MonoReflectionAssembly *ref_assembly;
968         MonoClass *klass;
969         gpointer load_value;
970         void *params [1];
971
972         if (!domain->domain)
973                 /* This can happen during startup */
974                 return;
975 #ifdef ASSEMBLY_LOAD_DEBUG
976         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
977 #endif
978         klass = domain->domain->mbr.obj.vtable->klass;
979
980         mono_domain_assemblies_lock (domain);
981         add_assemblies_to_domain (domain, assembly, NULL);
982         mono_domain_assemblies_unlock (domain);
983
984         if (assembly_load_field == NULL) {
985                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
986                 g_assert (assembly_load_field);
987         }
988
989         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
990         if (load_value == NULL) {
991                 /* No events waiting to be triggered */
992                 return;
993         }
994
995         ref_assembly = mono_assembly_get_object (domain, assembly);
996         g_assert (ref_assembly);
997
998         if (assembly_load_method == NULL) {
999                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1000                 g_assert (assembly_load_method);
1001         }
1002
1003         *params = ref_assembly;
1004         mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
1005 }
1006
1007 /*
1008  * LOCKING: Acquires the domain assemblies lock.
1009  */
1010 static void
1011 set_domain_search_path (MonoDomain *domain)
1012 {
1013         MonoError error;
1014         MonoAppDomainSetup *setup;
1015         gchar **tmp;
1016         gchar *search_path = NULL;
1017         gint i;
1018         gint npaths = 0;
1019         gchar **pvt_split = NULL;
1020         GError *gerror = NULL;
1021         gint appbaselen = -1;
1022
1023         /* 
1024          * We use the low-level domain assemblies lock, since this is called from
1025          * assembly loads hooks, which means this thread might hold the loader lock.
1026          */
1027         mono_domain_assemblies_lock (domain);
1028
1029         if (!domain->setup) {
1030                 mono_domain_assemblies_unlock (domain);
1031                 return;
1032         }
1033
1034         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1035                 mono_domain_assemblies_unlock (domain);
1036                 return;
1037         }
1038         setup = domain->setup;
1039         if (!setup->application_base) {
1040                 mono_domain_assemblies_unlock (domain);
1041                 return; /* Must set application base to get private path working */
1042         }
1043
1044         npaths++;
1045         
1046         if (setup->private_bin_path) {
1047                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1048                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1049                         g_warning ("Could not decode AppDomain search path since it contains invalid caracters");
1050                         mono_error_cleanup (&error);
1051                         mono_domain_assemblies_unlock (domain);
1052                         return;
1053                 }
1054         }
1055         
1056         if (domain->private_bin_path) {
1057                 if (search_path == NULL)
1058                         search_path = domain->private_bin_path;
1059                 else {
1060                         gchar *tmp2 = search_path;
1061                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1062                         g_free (tmp2);
1063                 }
1064         }
1065         
1066         if (search_path) {
1067                 /*
1068                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1069                  * directories relative to ApplicationBase separated by semicolons (see
1070                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1071                  * The loop below copes with the fact that some Unix applications may use ':' (or
1072                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1073                  * ';' for the subsequent split.
1074                  *
1075                  * The issue was reported in bug #81446
1076                  */
1077
1078 #ifndef TARGET_WIN32
1079                 gint slen;
1080
1081                 slen = strlen (search_path);
1082                 for (i = 0; i < slen; i++)
1083                         if (search_path [i] == ':')
1084                                 search_path [i] = ';';
1085 #endif
1086                 
1087                 pvt_split = g_strsplit (search_path, ";", 1000);
1088                 g_free (search_path);
1089                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1090         }
1091
1092         if (!npaths) {
1093                 if (pvt_split)
1094                         g_strfreev (pvt_split);
1095                 /*
1096                  * Don't do this because the first time is called, the domain
1097                  * setup is not finished.
1098                  *
1099                  * domain->search_path = g_malloc (sizeof (char *));
1100                  * domain->search_path [0] = NULL;
1101                 */
1102                 mono_domain_assemblies_unlock (domain);
1103                 return;
1104         }
1105
1106         if (domain->search_path)
1107                 g_strfreev (domain->search_path);
1108
1109         tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1110         tmp [npaths] = NULL;
1111
1112         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1113         if (!mono_error_ok (&error)) {
1114                 mono_error_cleanup (&error);
1115                 g_strfreev (pvt_split);
1116                 g_free (tmp);
1117
1118                 mono_domain_assemblies_unlock (domain);
1119                 return;
1120         }
1121
1122         domain->search_path = tmp;
1123
1124         /* FIXME: is this needed? */
1125         if (strncmp (*tmp, "file://", 7) == 0) {
1126                 gchar *file = *tmp;
1127                 gchar *uri = *tmp;
1128                 gchar *tmpuri;
1129
1130                 if (uri [7] != '/')
1131                         uri = g_strdup_printf ("file:///%s", uri + 7);
1132
1133                 tmpuri = uri;
1134                 uri = mono_escape_uri_string (tmpuri);
1135                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1136                 g_free (uri);
1137
1138                 if (tmpuri != file)
1139                         g_free (tmpuri);
1140
1141                 if (gerror != NULL) {
1142                         g_warning ("%s\n", gerror->message);
1143                         g_error_free (gerror);
1144                         *tmp = file;
1145                 } else {
1146                         g_free (file);
1147                 }
1148         }
1149
1150         for (i = 1; pvt_split && i < npaths; i++) {
1151                 if (g_path_is_absolute (pvt_split [i - 1])) {
1152                         tmp [i] = g_strdup (pvt_split [i - 1]);
1153                 } else {
1154                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1155                 }
1156
1157                 if (strchr (tmp [i], '.')) {
1158                         gchar *reduced;
1159                         gchar *freeme;
1160
1161                         reduced = mono_path_canonicalize (tmp [i]);
1162                         if (appbaselen == -1)
1163                                 appbaselen = strlen (tmp [0]);
1164
1165                         if (strncmp (tmp [0], reduced, appbaselen)) {
1166                                 g_free (reduced);
1167                                 g_free (tmp [i]);
1168                                 tmp [i] = g_strdup ("");
1169                                 continue;
1170                         }
1171
1172                         freeme = tmp [i];
1173                         tmp [i] = reduced;
1174                         g_free (freeme);
1175                 }
1176         }
1177         
1178         if (setup->private_bin_path_probe != NULL) {
1179                 g_free (tmp [0]);
1180                 tmp [0] = g_strdup ("");
1181         }
1182                 
1183         domain->setup->path_changed = FALSE;
1184
1185         g_strfreev (pvt_split);
1186
1187         mono_domain_assemblies_unlock (domain);
1188 }
1189
1190 #ifdef DISABLE_SHADOW_COPY
1191 gboolean
1192 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1193 {
1194         return FALSE;
1195 }
1196
1197 char *
1198 mono_make_shadow_copy (const char *filename)
1199 {
1200         return (char *) filename;
1201 }
1202 #else
1203 static gboolean
1204 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1205 {
1206         guint16 *orig, *dest;
1207         gboolean copy_result;
1208         
1209         strcpy (src + srclen - tail_len, extension);
1210         if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
1211                 return TRUE;
1212         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1213
1214         strcpy (target + targetlen - tail_len, extension);
1215         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1216         
1217         DeleteFile (dest);
1218         copy_result = CopyFile (orig, dest, FALSE);
1219         g_free (orig);
1220         g_free (dest);
1221         
1222         return copy_result;
1223 }
1224
1225 static gint32 
1226 get_cstring_hash (const char *str)
1227 {
1228         int len, i;
1229         const char *p;
1230         gint32 h = 0;
1231         
1232         if (!str || !str [0])
1233                 return 0;
1234                 
1235         len = strlen (str);
1236         p = str;
1237         for (i = 0; i < len; i++) {
1238                 h = (h << 5) - h + *p;
1239                 p++;
1240         }
1241         
1242         return h;
1243 }
1244
1245 /*
1246  * Returned memory is malloc'd. Called must free it 
1247  */
1248 static char *
1249 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1250 {
1251         MonoAppDomainSetup *setup;
1252         char *cache_path, *appname;
1253         char *userdir;
1254         char *location;
1255
1256         mono_error_init (error);
1257         
1258         setup = domain->setup;
1259         if (setup->cache_path != NULL && setup->application_name != NULL) {
1260                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1261                 if (!mono_error_ok (error))
1262                         return NULL;
1263 #ifndef TARGET_WIN32
1264                 {
1265                         gint i;
1266                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1267                                 if (cache_path [i] == '\\')
1268                                         cache_path [i] = '/';
1269                 }
1270 #endif
1271
1272                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1273                 if (!mono_error_ok (error)) {
1274                         g_free (cache_path);
1275                         return NULL;
1276                 }
1277
1278                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1279                 g_free (appname);
1280                 g_free (cache_path);
1281         } else {
1282                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1283                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1284                 g_free (userdir);
1285         }
1286         return location;
1287 }
1288
1289 static char *
1290 get_shadow_assembly_location (const char *filename, MonoError *error)
1291 {
1292         gint32 hash = 0, hash2 = 0;
1293         char name_hash [9];
1294         char path_hash [30];
1295         char *bname = g_path_get_basename (filename);
1296         char *dirname = g_path_get_dirname (filename);
1297         char *location, *tmploc;
1298         MonoDomain *domain = mono_domain_get ();
1299
1300         mono_error_init (error);
1301         
1302         hash = get_cstring_hash (bname);
1303         hash2 = get_cstring_hash (dirname);
1304         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1305         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1306         tmploc = get_shadow_assembly_location_base (domain, error);
1307         if (!mono_error_ok (error)) {
1308                 g_free (bname);
1309                 g_free (dirname);
1310                 return NULL;
1311         }
1312
1313         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1314         g_free (tmploc);
1315         g_free (bname);
1316         g_free (dirname);
1317         return location;
1318 }
1319
1320 static gboolean
1321 ensure_directory_exists (const char *filename)
1322 {
1323 #ifdef HOST_WIN32
1324         gchar *dir_utf8 = g_path_get_dirname (filename);
1325         gunichar2 *p;
1326         gunichar2 *dir_utf16 = NULL;
1327         int retval;
1328         
1329         if (!dir_utf8 || !dir_utf8 [0])
1330                 return FALSE;
1331
1332         dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1333         g_free (dir_utf8);
1334
1335         if (!dir_utf16)
1336                 return FALSE;
1337
1338         p = dir_utf16;
1339
1340         /* make life easy and only use one directory seperator */
1341         while (*p != '\0')
1342         {
1343                 if (*p == '/')
1344                         *p = '\\';
1345                 p++;
1346         }
1347
1348         p = dir_utf16;
1349
1350         /* get past C:\ )*/
1351         while (*p++ != '\\')    
1352         {
1353         }
1354
1355         while (1) {
1356                 BOOL bRet = FALSE;
1357                 p = wcschr (p, '\\');
1358                 if (p)
1359                         *p = '\0';
1360                 retval = _wmkdir (dir_utf16);
1361                 if (retval != 0 && errno != EEXIST) {
1362                         g_free (dir_utf16);
1363                         return FALSE;
1364                 }
1365                 if (!p)
1366                         break;
1367                 *p++ = '\\';
1368         }
1369         
1370         g_free (dir_utf16);
1371         return TRUE;
1372 #else
1373         char *p;
1374         gchar *dir = g_path_get_dirname (filename);
1375         int retval;
1376         struct stat sbuf;
1377         
1378         if (!dir || !dir [0]) {
1379                 g_free (dir);
1380                 return FALSE;
1381         }
1382         
1383         if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1384                 g_free (dir);
1385                 return TRUE;
1386         }
1387         
1388         p = dir;
1389         while (*p == '/')
1390                 p++;
1391
1392         while (1) {
1393                 p = strchr (p, '/');
1394                 if (p)
1395                         *p = '\0';
1396                 retval = mkdir (dir, 0777);
1397                 if (retval != 0 && errno != EEXIST) {
1398                         g_free (dir);
1399                         return FALSE;
1400                 }
1401                 if (!p)
1402                         break;
1403                 *p++ = '/';
1404         }
1405         
1406         g_free (dir);
1407         return TRUE;
1408 #endif
1409 }
1410
1411 static gboolean
1412 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1413 {
1414         struct stat sbuf_dest;
1415         
1416         if (stat (src, sbuf_src) == -1 || stat (dest, &sbuf_dest) == -1)
1417                 return TRUE;
1418
1419         if (sbuf_src->st_size == sbuf_dest.st_size &&
1420             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1421                 return FALSE;
1422
1423         return TRUE;
1424 }
1425
1426 static gboolean
1427 shadow_copy_create_ini (const char *shadow, const char *filename)
1428 {
1429         char *dir_name;
1430         char *ini_file;
1431         guint16 *u16_ini;
1432         gboolean result;
1433         guint32 n;
1434         HANDLE *handle;
1435         gchar *full_path;
1436
1437         dir_name = g_path_get_dirname (shadow);
1438         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1439         g_free (dir_name);
1440         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1441                 g_free (ini_file);
1442                 return TRUE;
1443         }
1444
1445         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1446         g_free (ini_file);
1447         if (!u16_ini) {
1448                 return FALSE;
1449         }
1450         handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1451                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1452         g_free (u16_ini);
1453         if (handle == INVALID_HANDLE_VALUE) {
1454                 return FALSE;
1455         }
1456
1457         full_path = mono_path_resolve_symlinks (filename);
1458         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1459         g_free (full_path);
1460         CloseHandle (handle);
1461         return result;
1462 }
1463
1464 gboolean
1465 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1466 {
1467         MonoError error;
1468         const char *version;
1469         MonoAppDomainSetup *setup;
1470         gchar *all_dirs;
1471         gchar **dir_ptr;
1472         gchar **directories;
1473         gchar *shadow_status_string;
1474         gchar *base_dir;
1475         gboolean shadow_enabled;
1476         gboolean found = FALSE;
1477
1478         if (domain == NULL)
1479                 return FALSE;
1480
1481         setup = domain->setup;
1482         if (setup == NULL || setup->shadow_copy_files == NULL)
1483                 return FALSE;
1484
1485         version = mono_get_runtime_info ()->framework_version;
1486
1487         /* For 1.x, not NULL is enough. In 2.0 it has to be "true" */
1488         if (*version <= '1') {
1489                 shadow_enabled = TRUE;
1490         } else {
1491                 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1492                 if (!mono_error_ok (&error)) {
1493                         mono_error_cleanup (&error);
1494                         return FALSE;
1495                 }
1496                 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1497                 g_free (shadow_status_string);
1498         }
1499                 
1500         if (!shadow_enabled)
1501                 return FALSE;
1502
1503         if (setup->shadow_copy_directories == NULL)
1504                 return TRUE;
1505
1506         /* Is dir_name a shadow_copy destination already? */
1507         base_dir = get_shadow_assembly_location_base (domain, &error);
1508         if (!mono_error_ok (&error)) {
1509                 mono_error_cleanup (&error);
1510                 return FALSE;
1511         }
1512
1513         if (strstr (dir_name, base_dir)) {
1514                 g_free (base_dir);
1515                 return TRUE;
1516         }
1517         g_free (base_dir);
1518
1519         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1520         if (!mono_error_ok (&error)) {
1521                 mono_error_cleanup (&error);
1522                 return FALSE;
1523         }
1524
1525         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1526         dir_ptr = directories;
1527         while (*dir_ptr) {
1528                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1529                         found = TRUE;
1530                         break;
1531                 }
1532                 dir_ptr++;
1533         }
1534         g_strfreev (directories);
1535         g_free (all_dirs);
1536         return found;
1537 }
1538
1539 /*
1540 This function raises exceptions so it can cause as sorts of nasty stuff if called
1541 while holding a lock.
1542 FIXME bubble up the error instead of raising it here
1543 */
1544 char *
1545 mono_make_shadow_copy (const char *filename)
1546 {
1547         MonoError error;
1548         gchar *sibling_source, *sibling_target;
1549         gint sibling_source_len, sibling_target_len;
1550         guint16 *orig, *dest;
1551         char *shadow;
1552         gboolean copy_result;
1553         MonoException *exc;
1554         struct stat src_sbuf;
1555         struct utimbuf utbuf;
1556         char *dir_name = g_path_get_dirname (filename);
1557         MonoDomain *domain = mono_domain_get ();
1558         char *shadow_dir;
1559
1560         set_domain_search_path (domain);
1561
1562         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1563                 g_free (dir_name);
1564                 return (char *) filename;
1565         }
1566
1567         /* Is dir_name a shadow_copy destination already? */
1568         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1569         if (!mono_error_ok (&error)) {
1570                 mono_error_cleanup (&error);
1571                 g_free (dir_name);
1572                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1573                 mono_raise_exception (exc);
1574         }
1575
1576         if (strstr (dir_name, shadow_dir)) {
1577                 g_free (shadow_dir);
1578                 g_free (dir_name);
1579                 return (char *) filename;
1580         }
1581         g_free (shadow_dir);
1582         g_free (dir_name);
1583
1584         shadow = get_shadow_assembly_location (filename, &error);
1585         if (!mono_error_ok (&error)) {
1586                 mono_error_cleanup (&error);
1587                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1588                 mono_raise_exception (exc);
1589         }
1590
1591         if (ensure_directory_exists (shadow) == FALSE) {
1592                 g_free (shadow);
1593                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1594                 mono_raise_exception (exc);
1595         }       
1596
1597         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1598                 return (char*) shadow;
1599
1600         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1601         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1602         DeleteFile (dest);
1603         copy_result = CopyFile (orig, dest, FALSE);
1604         g_free (dest);
1605         g_free (orig);
1606
1607         if (copy_result == FALSE) {
1608                 g_free (shadow);
1609                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1610                 mono_raise_exception (exc);
1611         }
1612
1613         /* attempt to copy .mdb, .config if they exist */
1614         sibling_source = g_strconcat (filename, ".config", NULL);
1615         sibling_source_len = strlen (sibling_source);
1616         sibling_target = g_strconcat (shadow, ".config", NULL);
1617         sibling_target_len = strlen (sibling_target);
1618         
1619         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1620         if (copy_result == TRUE)
1621                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1622         
1623         g_free (sibling_source);
1624         g_free (sibling_target);
1625         
1626         if (copy_result == FALSE)  {
1627                 g_free (shadow);
1628                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1629                 mono_raise_exception (exc);
1630         }
1631
1632         /* Create a .ini file containing the original assembly location */
1633         if (!shadow_copy_create_ini (shadow, filename)) {
1634                 g_free (shadow);
1635                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1636                 mono_raise_exception (exc);
1637         }
1638
1639         utbuf.actime = src_sbuf.st_atime;
1640         utbuf.modtime = src_sbuf.st_mtime;
1641         utime (shadow, &utbuf);
1642         
1643         return shadow;
1644 }
1645 #endif /* DISABLE_SHADOW_COPY */
1646
1647 MonoDomain *
1648 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1649 {
1650         if (appdomain == NULL)
1651                 return NULL;
1652         
1653         return appdomain->data;
1654 }
1655
1656 static gboolean
1657 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1658                                         const gchar *path3, const gchar *path4,
1659                                         gboolean refonly, gboolean is_private)
1660 {
1661         gchar *fullpath;
1662         gboolean found = FALSE;
1663         
1664         *assembly = NULL;
1665         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1666
1667         if (IS_PORTABILITY_SET) {
1668                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1669                 if (new_fullpath) {
1670                         g_free (fullpath);
1671                         fullpath = new_fullpath;
1672                         found = TRUE;
1673                 }
1674         } else
1675                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1676         
1677         if (found)
1678                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1679
1680         g_free (fullpath);
1681         return (*assembly != NULL);
1682 }
1683
1684 static MonoAssembly *
1685 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1686 {
1687         MonoAssembly *result = NULL;
1688         gchar **path;
1689         gchar *filename;
1690         const gchar *local_culture;
1691         gint len;
1692         gboolean is_private = FALSE;
1693
1694         if (!culture || *culture == '\0') {
1695                 local_culture = "";
1696         } else {
1697                 local_culture = culture;
1698         }
1699
1700         filename =  g_strconcat (name, ".dll", NULL);
1701         len = strlen (filename);
1702
1703         for (path = search_path; *path; path++) {
1704                 if (**path == '\0') {
1705                         is_private = TRUE;
1706                         continue; /* Ignore empty ApplicationBase */
1707                 }
1708
1709                 /* See test cases in bug #58992 and bug #57710 */
1710                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1711                 strcpy (filename + len - 4, ".dll");
1712                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1713                         break;
1714
1715                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1716                 strcpy (filename + len - 4, ".exe");
1717                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1718                         break;
1719
1720                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1721                 strcpy (filename + len - 4, ".dll");
1722                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1723                         break;
1724
1725                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1726                 strcpy (filename + len - 4, ".exe");
1727                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1728                         break;
1729         }
1730
1731         g_free (filename);
1732         return result;
1733 }
1734
1735 /*
1736  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1737  * and then from assemblies_path if any.
1738  * LOCKING: This is called from the assembly loading code, which means the caller
1739  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1740  */
1741 static MonoAssembly *
1742 mono_domain_assembly_preload (MonoAssemblyName *aname,
1743                               gchar **assemblies_path,
1744                               gpointer user_data)
1745 {
1746         MonoDomain *domain = mono_domain_get ();
1747         MonoAssembly *result = NULL;
1748         gboolean refonly = GPOINTER_TO_UINT (user_data);
1749
1750         set_domain_search_path (domain);
1751
1752         if (domain->search_path && domain->search_path [0] != NULL) {
1753                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1754         }
1755
1756         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1757                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1758         }
1759
1760         return result;
1761 }
1762
1763 /*
1764  * Check whenever a given assembly was already loaded in the current appdomain.
1765  */
1766 static MonoAssembly *
1767 mono_domain_assembly_search (MonoAssemblyName *aname,
1768                                                          gpointer user_data)
1769 {
1770         MonoDomain *domain = mono_domain_get ();
1771         GSList *tmp;
1772         MonoAssembly *ass;
1773         gboolean refonly = GPOINTER_TO_UINT (user_data);
1774
1775         mono_domain_assemblies_lock (domain);
1776         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1777                 ass = tmp->data;
1778                 /* Dynamic assemblies can't match here in MS.NET */
1779                 if (ass->dynamic || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1780                         continue;
1781
1782                 mono_domain_assemblies_unlock (domain);
1783                 return ass;
1784         }
1785         mono_domain_assemblies_unlock (domain);
1786
1787         return NULL;
1788 }
1789
1790 MonoReflectionAssembly *
1791 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1792 {
1793         MonoDomain *domain = mono_domain_get ();
1794         char *name, *filename;
1795         MonoImageOpenStatus status = MONO_IMAGE_OK;
1796         MonoAssembly *ass;
1797
1798         MONO_ARCH_SAVE_REGS;
1799
1800         if (fname == NULL) {
1801                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1802                 mono_raise_exception (exc);
1803         }
1804                 
1805         name = filename = mono_string_to_utf8 (fname);
1806         
1807         ass = mono_assembly_open_full (filename, &status, refOnly);
1808         
1809         if (!ass){
1810                 MonoException *exc;
1811
1812                 if (status == MONO_IMAGE_IMAGE_INVALID)
1813                         exc = mono_get_exception_bad_image_format2 (NULL, fname);
1814                 else
1815                         exc = mono_get_exception_file_not_found2 (NULL, fname);
1816                 g_free (name);
1817                 mono_raise_exception (exc);
1818         }
1819
1820         g_free (name);
1821
1822         return mono_assembly_get_object (domain, ass);
1823 }
1824
1825 MonoReflectionAssembly *
1826 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
1827                                             MonoArray *raw_assembly,
1828                                             MonoArray *raw_symbol_store, MonoObject *evidence,
1829                                             MonoBoolean refonly)
1830 {
1831         MonoAssembly *ass;
1832         MonoReflectionAssembly *refass = NULL;
1833         MonoDomain *domain = ad->data;
1834         MonoImageOpenStatus status;
1835         guint32 raw_assembly_len = mono_array_length (raw_assembly);
1836         MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1837
1838         if (!image) {
1839                 mono_raise_exception (mono_get_exception_bad_image_format (""));
1840                 return NULL;
1841         }
1842
1843         if (raw_symbol_store != NULL)
1844                 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1845
1846         ass = mono_assembly_load_from_full (image, "", &status, refonly);
1847
1848
1849         if (!ass) {
1850                 mono_image_close (image);
1851                 mono_raise_exception (mono_get_exception_bad_image_format (""));
1852                 return NULL; 
1853         }
1854
1855         refass = mono_assembly_get_object (domain, ass);
1856         MONO_OBJECT_SETREF (refass, evidence, evidence);
1857         return refass;
1858 }
1859
1860 MonoReflectionAssembly *
1861 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1862 {
1863         MonoDomain *domain = ad->data; 
1864         MonoImageOpenStatus status = MONO_IMAGE_OK;
1865         MonoAssembly *ass;
1866         MonoAssemblyName aname;
1867         MonoReflectionAssembly *refass = NULL;
1868         gchar *name;
1869         gboolean parsed;
1870
1871         MONO_ARCH_SAVE_REGS;
1872
1873         g_assert (assRef != NULL);
1874
1875         name = mono_string_to_utf8 (assRef);
1876         parsed = mono_assembly_name_parse (name, &aname);
1877         g_free (name);
1878
1879         if (!parsed) {
1880                 /* This is a parse error... */
1881                 return NULL;
1882         }
1883
1884         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1885         mono_assembly_name_free (&aname);
1886
1887         if (!ass) {
1888                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1889                 if (!refOnly)
1890                         refass = mono_try_assembly_resolve (domain, assRef, refOnly);
1891                 else
1892                         refass = NULL;
1893                 if (!refass) {
1894                         return NULL;
1895                 }
1896         }
1897
1898         if (refass == NULL)
1899                 refass = mono_assembly_get_object (domain, ass);
1900
1901         MONO_OBJECT_SETREF (refass, evidence, evidence);
1902         return refass;
1903 }
1904
1905 void
1906 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
1907 {
1908         MonoDomain * domain = mono_domain_get_by_id (domain_id);
1909
1910         MONO_ARCH_SAVE_REGS;
1911
1912         if (NULL == domain) {
1913                 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
1914                 mono_raise_exception (exc);
1915         }
1916         
1917         if (domain == mono_get_root_domain ()) {
1918                 mono_raise_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
1919                 return;
1920         }
1921
1922         /* 
1923          * Unloading seems to cause problems when running NUnit/NAnt, hence
1924          * this workaround.
1925          */
1926         if (g_getenv ("MONO_NO_UNLOAD"))
1927                 return;
1928
1929         mono_domain_unload (domain);
1930 }
1931
1932 gboolean
1933 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
1934 {
1935         MonoDomain *domain = mono_domain_get_by_id (domain_id);
1936
1937         if (!domain)
1938                 return TRUE;
1939
1940         return mono_domain_is_unloading (domain);
1941 }
1942
1943 gint32
1944 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
1945                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
1946 {
1947         MonoImage *image;
1948         MonoMethod *method;
1949
1950         MONO_ARCH_SAVE_REGS;
1951
1952         g_assert (refass);
1953         image = refass->assembly->image;
1954         g_assert (image);
1955
1956         method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
1957
1958         if (!method)
1959                 g_error ("No entry point method found in %s", image->name);
1960
1961         if (!args)
1962                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
1963
1964         return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
1965 }
1966
1967 gint32 
1968 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
1969 {
1970         MONO_ARCH_SAVE_REGS;
1971
1972         return ad->data->domain_id;
1973 }
1974
1975 MonoAppDomain * 
1976 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
1977 {
1978         MonoDomain *old_domain = mono_domain_get();
1979
1980         MONO_ARCH_SAVE_REGS;
1981
1982         if (!mono_domain_set (ad->data, FALSE))
1983                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
1984
1985         return old_domain->domain;
1986 }
1987
1988 MonoAppDomain * 
1989 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
1990 {
1991         MonoDomain *current_domain = mono_domain_get ();
1992         MonoDomain *domain = mono_domain_get_by_id (domainid);
1993
1994         MONO_ARCH_SAVE_REGS;
1995
1996         if (!domain || !mono_domain_set (domain, FALSE))        
1997                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
1998
1999         return current_domain->domain;
2000 }
2001
2002 void
2003 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2004 {
2005         MONO_ARCH_SAVE_REGS;
2006
2007         mono_thread_push_appdomain_ref (ad->data);
2008 }
2009
2010 void
2011 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2012 {
2013         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2014
2015         MONO_ARCH_SAVE_REGS;
2016
2017         if (!domain)
2018                 /* 
2019                  * Raise an exception to prevent the managed code from executing a pop
2020                  * later.
2021                  */
2022                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2023
2024         mono_thread_push_appdomain_ref (domain);
2025 }
2026
2027 void
2028 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2029 {
2030         MONO_ARCH_SAVE_REGS;
2031
2032         mono_thread_pop_appdomain_ref ();
2033 }
2034
2035 MonoAppContext * 
2036 ves_icall_System_AppDomain_InternalGetContext ()
2037 {
2038         MONO_ARCH_SAVE_REGS;
2039
2040         return mono_context_get ();
2041 }
2042
2043 MonoAppContext * 
2044 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2045 {
2046         MONO_ARCH_SAVE_REGS;
2047
2048         return mono_domain_get ()->default_context;
2049 }
2050
2051 MonoAppContext * 
2052 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2053 {
2054         MonoAppContext *old_context = mono_context_get ();
2055
2056         MONO_ARCH_SAVE_REGS;
2057
2058         mono_context_set (mc);
2059
2060         return old_context;
2061 }
2062
2063 MonoString *
2064 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2065 {
2066         MonoDomain* mono_root_domain = mono_get_root_domain ();
2067         mono_domain_lock (mono_root_domain);
2068         if (process_guid_set) {
2069                 mono_domain_unlock (mono_root_domain);
2070                 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
2071         }
2072         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2073         process_guid_set = TRUE;
2074         mono_domain_unlock (mono_root_domain);
2075         return newguid;
2076 }
2077
2078 gboolean
2079 mono_domain_is_unloading (MonoDomain *domain)
2080 {
2081         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2082                 return TRUE;
2083         else
2084                 return FALSE;
2085 }
2086
2087 static void
2088 clear_cached_vtable (gpointer key, gpointer value, gpointer user_data)
2089 {
2090         MonoClass *klass = (MonoClass*)key;
2091         MonoVTable *vtable = value;
2092         MonoDomain *domain = (MonoDomain*)user_data;
2093         MonoClassRuntimeInfo *runtime_info;
2094
2095         runtime_info = klass->runtime_info;
2096         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2097                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2098         if (vtable->data && klass->has_static_refs)
2099                 mono_gc_free_fixed (vtable->data);
2100 }
2101
2102 static void
2103 zero_static_data (gpointer key, gpointer value, gpointer user_data)
2104 {
2105         MonoClass *klass = (MonoClass*)key;
2106         MonoVTable *vtable = value;
2107
2108         if (vtable->data && klass->has_static_refs)
2109                 memset (vtable->data, 0, mono_class_data_size (klass));
2110 }
2111
2112 typedef struct unload_data {
2113         MonoDomain *domain;
2114         char *failure_reason;
2115 } unload_data;
2116
2117 #ifdef HAVE_SGEN_GC
2118 static void
2119 deregister_reflection_info_roots_nspace_table (gpointer key, gpointer value, gpointer image)
2120 {
2121         guint32 index = GPOINTER_TO_UINT (value);
2122         MonoClass *class = mono_class_get (image, MONO_TOKEN_TYPE_DEF | index);
2123
2124         g_assert (class);
2125
2126         if (class->reflection_info)
2127                 mono_gc_deregister_root ((char*) &class->reflection_info);
2128 }
2129
2130 static void
2131 deregister_reflection_info_roots_name_space (gpointer key, gpointer value, gpointer user_data)
2132 {
2133         g_hash_table_foreach (value, deregister_reflection_info_roots_nspace_table, user_data);
2134 }
2135
2136 static void
2137 deregister_reflection_info_roots_from_list (MonoImage *image)
2138 {
2139         GSList *list = image->reflection_info_unregister_classes;
2140
2141         while (list) {
2142                 MonoClass *class = list->data;
2143
2144                 g_assert (class->reflection_info);
2145                 mono_gc_deregister_root ((char*) &class->reflection_info);
2146
2147                 list = list->next;
2148         }
2149
2150         g_slist_free (image->reflection_info_unregister_classes);
2151         image->reflection_info_unregister_classes = NULL;
2152 }
2153
2154 static void
2155 deregister_reflection_info_roots (MonoDomain *domain)
2156 {
2157         GSList *list;
2158
2159         mono_loader_lock ();
2160         mono_domain_assemblies_lock (domain);
2161         for (list = domain->domain_assemblies; list; list = list->next) {
2162                 MonoAssembly *assembly = list->data;
2163                 MonoImage *image = assembly->image;
2164                 int i;
2165                 /*No need to take the image lock here since dynamic images are appdomain bound and at this point the mutator is gone.*/
2166                 if (image->dynamic && image->name_cache)
2167                         g_hash_table_foreach (image->name_cache, deregister_reflection_info_roots_name_space, image);
2168                 deregister_reflection_info_roots_from_list (image);
2169                 for (i = 0; i < image->module_count; ++i) {
2170                         MonoImage *module = image->modules [i];
2171                         if (module) {
2172                                 if (module->dynamic && module->name_cache) {
2173                                         g_hash_table_foreach (module->name_cache,
2174                                                         deregister_reflection_info_roots_name_space, module);
2175                                 }
2176                                 deregister_reflection_info_roots_from_list (module);
2177                         }
2178                 }
2179         }
2180         mono_domain_assemblies_unlock (domain);
2181         mono_loader_unlock ();
2182 }
2183 #endif
2184
2185 static guint32 WINAPI
2186 unload_thread_main (void *arg)
2187 {
2188         unload_data *data = (unload_data*)arg;
2189         MonoDomain *domain = data->domain;
2190
2191         /* Have to attach to the runtime so shutdown can wait for this thread */
2192         mono_thread_attach (mono_get_root_domain ());
2193
2194         /* 
2195          * FIXME: Abort our parent thread last, so we can return a failure 
2196          * indication if aborting times out.
2197          */
2198         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2199                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2200                 return 1;
2201         }
2202
2203         if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2204                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2205                 return 1;
2206         }
2207
2208         /* Finalize all finalizable objects in the doomed appdomain */
2209         if (!mono_domain_finalize (domain, -1)) {
2210                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2211                 return 1;
2212         }
2213
2214         /* Clear references to our vtables in class->runtime_info.
2215          * We also hold the loader lock because we're going to change
2216          * class->runtime_info.
2217          */
2218
2219         mono_loader_lock ();
2220         mono_domain_lock (domain);
2221 #ifdef HAVE_SGEN_GC
2222         /*
2223          * We need to make sure that we don't have any remsets
2224          * pointing into static data of the to-be-freed domain because
2225          * at the next collections they would be invalid.  So what we
2226          * do is we first zero all static data and then do a minor
2227          * collection.  Because all references in the static data will
2228          * now be null we won't do any unnecessary copies and after
2229          * the collection there won't be any more remsets.
2230          */
2231         g_hash_table_foreach (domain->class_vtable_hash, zero_static_data, domain);
2232         mono_gc_collect (0);
2233 #endif
2234         g_hash_table_foreach (domain->class_vtable_hash, clear_cached_vtable, domain);
2235 #ifdef HAVE_SGEN_GC
2236         deregister_reflection_info_roots (domain);
2237 #endif
2238         mono_domain_unlock (domain);
2239         mono_loader_unlock ();
2240
2241         mono_threads_clear_cached_culture (domain);
2242
2243         domain->state = MONO_APPDOMAIN_UNLOADED;
2244
2245         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2246
2247         /* remove from the handle table the items related to this domain */
2248         mono_gchandle_free_domain (domain);
2249
2250         mono_domain_free (domain, FALSE);
2251
2252         mono_gc_collect (mono_gc_max_generation ());
2253
2254         return 0;
2255 }
2256
2257 /*
2258  * mono_domain_unload:
2259  * @domain: The domain to unload
2260  *
2261  *  Unloads an appdomain. Follows the process outlined in the comment
2262  *  for mono_domain_try_unload.
2263  */
2264 void
2265 mono_domain_unload (MonoDomain *domain)
2266 {
2267         MonoObject *exc = NULL;
2268         mono_domain_try_unload (domain, &exc);
2269         if (exc)
2270                 mono_raise_exception ((MonoException*)exc);
2271 }
2272
2273 /*
2274  * mono_domain_unload:
2275  * @domain: The domain to unload
2276  * @exc: Exception information
2277  *
2278  *  Unloads an appdomain. Follows the process outlined in:
2279  *  http://blogs.gotdotnet.com/cbrumme
2280  *
2281  *  If doing things the 'right' way is too hard or complex, we do it the 
2282  *  'simple' way, which means do everything needed to avoid crashes and
2283  *  memory leaks, but not much else.
2284  *
2285  *  It is required to pass a valid reference to the exc argument, upon return
2286  *  from this function *exc will be set to the exception thrown, if any.
2287  *
2288  *  If this method is not called from an icall (embedded scenario for instance),
2289  *  it must not be called with any managed frames on the stack, since the unload
2290  *  process could end up trying to abort the current thread.
2291  */
2292 void
2293 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2294 {
2295         HANDLE thread_handle;
2296         gsize tid;
2297         guint32 res;
2298         MonoAppDomainState prev_state;
2299         MonoMethod *method;
2300         unload_data thread_data;
2301         MonoDomain *caller_domain = mono_domain_get ();
2302
2303         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2304
2305         /* Atomically change our state to UNLOADING */
2306         prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2307                                                                                          MONO_APPDOMAIN_UNLOADING_START,
2308                                                                                          MONO_APPDOMAIN_CREATED);
2309         if (prev_state != MONO_APPDOMAIN_CREATED) {
2310                 switch (prev_state) {
2311                 case MONO_APPDOMAIN_UNLOADING_START:
2312                 case MONO_APPDOMAIN_UNLOADING:
2313                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2314                         return;
2315                 case MONO_APPDOMAIN_UNLOADED:
2316                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2317                         return;
2318                 default:
2319                         g_warning ("Incalid appdomain state %d", prev_state);
2320                         g_assert_not_reached ();
2321                 }
2322         }
2323
2324         mono_debugger_event_unload_appdomain (domain);
2325
2326         mono_domain_set (domain, FALSE);
2327         /* Notify OnDomainUnload listeners */
2328         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2329         g_assert (method);
2330
2331         mono_runtime_invoke (method, domain->domain, NULL, exc);
2332         if (*exc) {
2333                 /* Roll back the state change */
2334                 domain->state = MONO_APPDOMAIN_CREATED;
2335                 mono_domain_set (caller_domain, FALSE);
2336                 return;
2337         }
2338         mono_domain_set (caller_domain, FALSE);
2339
2340         thread_data.domain = domain;
2341         thread_data.failure_reason = NULL;
2342
2343         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2344         domain->state = MONO_APPDOMAIN_UNLOADING;
2345         /* 
2346          * First we create a separate thread for unloading, since
2347          * we might have to abort some threads, including the current one.
2348          */
2349         /*
2350          * If we create a non-suspended thread, the runtime will hang.
2351          * See:
2352          * http://bugzilla.ximian.com/show_bug.cgi?id=27663
2353          */ 
2354 #if 0
2355         thread_handle = mono_create_thread (NULL, 0, unload_thread_main, &thread_data, 0, &tid);
2356 #else
2357         thread_handle = mono_create_thread (NULL, 0, (LPTHREAD_START_ROUTINE)unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
2358         if (thread_handle == NULL) {
2359                 return;
2360         }
2361         ResumeThread (thread_handle);
2362 #endif
2363
2364         /* Wait for the thread */       
2365         while ((res = WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION)) {
2366                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2367                         /* The unload thread tries to abort us */
2368                         /* The icall wrapper will execute the abort */
2369                         CloseHandle (thread_handle);
2370                         return;
2371                 }
2372         }
2373         CloseHandle (thread_handle);
2374
2375         if (thread_data.failure_reason) {
2376                 /* Roll back the state change */
2377                 domain->state = MONO_APPDOMAIN_CREATED;
2378
2379                 g_warning ("%s", thread_data.failure_reason);
2380
2381                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data.failure_reason);
2382
2383                 g_free (thread_data.failure_reason);
2384                 thread_data.failure_reason = NULL;
2385         }
2386 }