2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/appdomain-icalls.h>
39 #include <mono/metadata/domain-internals.h>
40 #include "mono/metadata/metadata-internals.h"
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/exception-internals.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/threadpool.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/io-layer/io-layer.h>
79 * This is the version number of the corlib-runtime interface. When
80 * making changes to this interface (by changing the layout
81 * of classes the runtime knows about, changing icall signature or
82 * semantics etc), increment this variable. Also increment the
83 * pair of this variable in mscorlib in:
84 * mcs/class/corlib/System/Environment.cs
86 * Changes which are already detected at runtime, like the addition
87 * of icalls, do not require an increment.
89 #define MONO_CORLIB_VERSION 164
94 int assemblybinding_count;
99 static gunichar2 process_guid [36];
100 static gboolean process_guid_set = FALSE;
102 static gboolean no_exec = FALSE;
104 static MonoAssembly *
105 mono_domain_assembly_preload (MonoAssemblyName *aname,
106 gchar **assemblies_path,
109 static MonoAssembly *
110 mono_domain_assembly_search (MonoAssemblyName *aname,
114 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
117 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
119 static MonoAppDomain *
120 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
123 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
125 static MonoLoadFunc load_function = NULL;
127 /* Lazy class loading functions */
128 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly);
130 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, System, AppDomain);
133 mono_install_runtime_load (MonoLoadFunc func)
135 load_function = func;
139 mono_runtime_load (const char *filename, const char *runtime_version)
141 g_assert (load_function);
142 return load_function (filename, runtime_version);
146 * mono_runtime_set_no_exec:
148 * Instructs the runtime to operate in static mode, i.e. avoid/do not
149 * allow managed code execution. This is useful for running the AOT
150 * compiler on platforms which allow full-aot execution only. This
151 * should be called before mono_runtime_init ().
154 mono_runtime_set_no_exec (gboolean val)
160 * mono_runtime_get_no_exec:
162 * If true, then the runtime will not allow managed code execution.
165 mono_runtime_get_no_exec (void)
171 create_domain_objects (MonoDomain *domain)
174 MonoDomain *old_domain = mono_domain_get ();
176 MonoVTable *string_vt;
177 MonoClassField *string_empty_fld;
179 if (domain != old_domain) {
180 mono_thread_push_appdomain_ref (domain);
181 mono_domain_set_internal_with_options (domain, FALSE);
185 * Initialize String.Empty. This enables the removal of
186 * the static cctor of the String class.
188 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
189 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
190 g_assert (string_empty_fld);
191 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
192 mono_error_assert_ok (&error);
193 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
194 domain->empty_string = empty_str;
197 * Create an instance early since we can't do it when there is no memory.
199 arg = mono_string_new (domain, "Out of memory");
200 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
201 mono_error_assert_ok (&error);
204 * These two are needed because the signal handlers might be executing on
205 * an alternate stack, and Boehm GC can't handle that.
207 arg = mono_string_new (domain, "A null value was found where an object instance was required");
208 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
209 mono_error_assert_ok (&error);
210 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
211 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
212 mono_error_assert_ok (&error);
214 /*The ephemeron tombstone i*/
215 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
216 mono_error_assert_ok (&error);
218 if (domain != old_domain) {
219 mono_thread_pop_appdomain_ref ();
220 mono_domain_set_internal_with_options (old_domain, FALSE);
224 * This class is used during exception handling, so initialize it here, to prevent
225 * stack overflows while handling stack overflows.
227 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
232 * @domain: domain returned by mono_init ()
234 * Initialize the core AppDomain: this function will run also some
235 * IL initialization code, so it needs the execution engine to be fully
238 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
239 * we know the entry_assembly.
243 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
246 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
247 mono_error_cleanup (&error);
251 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
253 MonoAppDomainSetup *setup;
257 mono_error_init (error);
259 mono_portability_helpers_init ();
261 mono_gc_base_init ();
262 mono_monitor_init ();
263 mono_marshal_init ();
265 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
266 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
267 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
268 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
269 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
270 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
271 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
273 mono_thread_init (start_cb, attach_cb);
275 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
276 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
277 return_if_nok (error);
279 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
281 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
282 return_if_nok (error);
286 domain->setup = setup;
288 mono_thread_attach (domain);
290 mono_type_initialization_init ();
292 if (!mono_runtime_get_no_exec ())
293 create_domain_objects (domain);
295 /* GC init has to happen after thread init */
298 /* contexts use GC handles, so they must be initialized after the GC */
299 mono_context_init_checked (domain, error);
300 return_if_nok (error);
301 mono_context_set (domain->default_context);
303 #ifndef DISABLE_SOCKETS
304 mono_network_init ();
307 mono_console_init ();
310 mono_locks_tracer_init ();
312 /* mscorlib is loaded before we install the load hook */
313 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
319 mono_get_corlib_version (void)
323 MonoClassField *field;
326 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
327 mono_class_init (klass);
328 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
331 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
333 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
334 mono_error_assert_ok (&error);
335 return *(gint32*)((gchar*)value + sizeof (MonoObject));
339 * mono_check_corlib_version
341 * Checks that the corlib that is loaded matches the version of this runtime.
343 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
344 * allocated string with the error otherwise.
347 mono_check_corlib_version (void)
349 int version = mono_get_corlib_version ();
350 if (version != MONO_CORLIB_VERSION)
351 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
353 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
354 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
355 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
356 if (native_offset != managed_offset)
357 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
364 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
366 * Initializes the @domain's default System.Runtime.Remoting's Context.
369 mono_context_init (MonoDomain *domain)
372 mono_context_init_checked (domain, &error);
373 mono_error_cleanup (&error);
377 mono_context_init_checked (MonoDomain *domain, MonoError *error)
380 MonoAppContext *context;
382 mono_error_init (error);
384 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
385 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
386 return_if_nok (error);
388 context->domain_id = domain->domain_id;
389 context->context_id = 0;
390 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
391 domain->default_context = context;
395 * mono_runtime_cleanup:
400 * This must not be called while there are still running threads executing
404 mono_runtime_cleanup (MonoDomain *domain)
406 mono_attach_cleanup ();
408 /* This ends up calling any pending pending (for at most 2 seconds) */
411 mono_thread_cleanup ();
413 #ifndef DISABLE_SOCKETS
414 mono_network_cleanup ();
416 mono_marshal_cleanup ();
418 mono_type_initialization_cleanup ();
420 mono_monitor_cleanup ();
423 static MonoDomainFunc quit_function = NULL;
426 mono_install_runtime_cleanup (MonoDomainFunc func)
428 quit_function = func;
434 if (quit_function != NULL)
435 quit_function (mono_get_root_domain (), NULL);
439 * mono_domain_create_appdomain:
440 * @friendly_name: The friendly name of the appdomain to create
441 * @configuration_file: The configuration file to initialize the appdomain with
443 * Returns a MonoDomain initialized with the appdomain
446 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
450 MonoAppDomainSetup *setup;
453 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
454 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
457 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
459 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
463 return mono_domain_from_appdomain (ad);
465 mono_error_cleanup (&error);
470 * mono_domain_set_config:
471 * @domain: MonoDomain initialized with the appdomain we want to change
472 * @base_dir: new base directory for the appdomain
473 * @config_file_name: path to the new configuration for the app domain
475 * Used to set the system configuration for an appdomain
477 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
478 * Error Initializing the configuration system. ---> System.ArgumentException:
479 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
482 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
484 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
485 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
488 static MonoAppDomainSetup*
489 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
491 MonoDomain *caller_domain;
492 MonoClass *ads_class;
493 MonoAppDomainSetup *copy;
495 mono_error_init (error);
497 caller_domain = mono_domain_get ();
498 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
500 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
501 return_val_if_nok (error, NULL);
503 mono_domain_set_internal (domain);
505 #define XCOPY_FIELD(dst,field,src,error) \
507 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
508 return_val_if_nok (error, NULL); \
509 MONO_OBJECT_SETREF ((dst),field,copied_val); \
512 XCOPY_FIELD (copy, application_base, setup->application_base, error);
513 XCOPY_FIELD (copy, application_name, setup->application_name, error);
514 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
515 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
516 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
517 XCOPY_FIELD (copy, license_file, setup->license_file, error);
518 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
519 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
520 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
521 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
522 copy->publisher_policy = setup->publisher_policy;
523 copy->path_changed = setup->path_changed;
524 copy->loader_optimization = setup->loader_optimization;
525 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
526 copy->disallow_code_downloads = setup->disallow_code_downloads;
527 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
528 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
529 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
530 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
531 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
535 mono_domain_set_internal (caller_domain);
540 static MonoAppDomain *
541 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
546 char *shadow_location;
548 mono_error_init (error);
550 adclass = mono_class_get_appdomain_class ();
552 /* FIXME: pin all those objects */
553 data = mono_domain_create();
555 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
556 return_val_if_nok (error, NULL);
559 data->friendly_name = g_strdup (friendly_name);
561 mono_profiler_appdomain_name (data, data->friendly_name);
563 if (!setup->application_base) {
564 /* Inherit from the root domain since MS.NET does this */
565 MonoDomain *root = mono_get_root_domain ();
566 if (root->setup->application_base) {
567 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
568 mono_error_assert_ok (error); /* FIXME don't swallow the error */
569 MONO_OBJECT_SETREF (setup, application_base, s);
573 mono_context_init_checked (data, error);
574 return_val_if_nok (error, NULL);
576 data->setup = copy_app_domain_setup (data, setup, error);
577 if (!mono_error_ok (error)) {
578 g_free (data->friendly_name);
582 mono_domain_set_options_from_config (data);
583 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
585 #ifndef DISABLE_SHADOW_COPY
586 /*FIXME, guard this for when the debugger is not running */
587 shadow_location = get_shadow_assembly_location_base (data, error);
588 if (!mono_error_ok (error)) {
589 g_free (data->friendly_name);
593 g_free (shadow_location);
596 create_domain_objects (data);
602 * mono_domain_has_type_resolve:
603 * @domain: application domains being looked up
605 * Returns: TRUE if the AppDomain.TypeResolve field has been
609 mono_domain_has_type_resolve (MonoDomain *domain)
611 static MonoClassField *field = NULL;
615 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
619 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
623 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
628 * mono_domain_try_type_resolve:
629 * @domain: application domainwhere the name where the type is going to be resolved
630 * @name: the name of the type to resolve or NULL.
631 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
633 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
634 * the assembly that matches name.
636 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
638 * Returns: A MonoReflectionAssembly or NULL if not found
640 MonoReflectionAssembly *
641 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
644 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
645 mono_error_cleanup (&error);
650 MonoReflectionAssembly *
651 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
653 static MonoMethod *method = NULL;
654 MonoReflectionAssembly *ret;
657 mono_error_init (error);
659 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
661 if (method == NULL) {
662 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
663 if (method == NULL) {
664 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
670 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
674 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
675 return_val_if_nok (error, NULL);
681 * mono_domain_owns_vtable_slot:
683 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
686 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
690 mono_domain_lock (domain);
691 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
692 mono_domain_unlock (domain);
699 * @force: force setting.
701 * Set the current appdomain to @domain. If @force is set, set it even
702 * if it is being unloaded.
706 * FALSE if the domain is unloaded
709 mono_domain_set (MonoDomain *domain, gboolean force)
711 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
714 mono_domain_set_internal (domain);
720 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
727 MONO_CHECK_ARG_NULL (name, NULL);
733 str = mono_string_to_utf8_checked (name, &error);
734 if (mono_error_set_pending_exception (&error))
737 mono_domain_lock (add);
739 if (!strcmp (str, "APPBASE"))
740 o = (MonoObject *)add->setup->application_base;
741 else if (!strcmp (str, "APP_CONFIG_FILE"))
742 o = (MonoObject *)add->setup->configuration_file;
743 else if (!strcmp (str, "DYNAMIC_BASE"))
744 o = (MonoObject *)add->setup->dynamic_base;
745 else if (!strcmp (str, "APP_NAME"))
746 o = (MonoObject *)add->setup->application_name;
747 else if (!strcmp (str, "CACHE_BASE"))
748 o = (MonoObject *)add->setup->cache_path;
749 else if (!strcmp (str, "PRIVATE_BINPATH"))
750 o = (MonoObject *)add->setup->private_bin_path;
751 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
752 o = (MonoObject *)add->setup->private_bin_path_probe;
753 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
754 o = (MonoObject *)add->setup->shadow_copy_directories;
755 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
756 o = (MonoObject *)add->setup->shadow_copy_files;
758 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
760 mono_domain_unlock (add);
770 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
774 MONO_CHECK_ARG_NULL (name,);
780 mono_domain_lock (add);
782 mono_g_hash_table_insert (add->env, name, data);
784 mono_domain_unlock (add);
788 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
793 return ad->data->setup;
797 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
802 return mono_string_new (ad->data, ad->data->friendly_name);
806 ves_icall_System_AppDomain_getCurDomain ()
808 MonoDomain *add = mono_domain_get ();
814 ves_icall_System_AppDomain_getRootDomain ()
816 MonoDomain *root = mono_get_root_domain ();
822 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
824 MonoDomain *domain = mono_domain_get ();
826 return domain->throw_unobserved_task_exceptions;
830 get_attribute_value (const gchar **attribute_names,
831 const gchar **attribute_values,
832 const char *att_name)
835 for (n = 0; attribute_names [n] != NULL; n++) {
836 if (strcmp (attribute_names [n], att_name) == 0)
837 return g_strdup (attribute_values [n]);
843 start_element (GMarkupParseContext *context,
844 const gchar *element_name,
845 const gchar **attribute_names,
846 const gchar **attribute_values,
850 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
852 if (strcmp (element_name, "runtime") == 0) {
853 runtime_config->runtime_count++;
857 if (strcmp (element_name, "assemblyBinding") == 0) {
858 runtime_config->assemblybinding_count++;
862 if (runtime_config->runtime_count != 1)
865 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
866 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
868 if (value && g_ascii_strcasecmp (value, "true") == 0)
869 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
872 if (runtime_config->assemblybinding_count != 1)
875 if (strcmp (element_name, "probing") != 0)
878 g_free (runtime_config->domain->private_bin_path);
879 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
880 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
881 g_free (runtime_config->domain->private_bin_path);
882 runtime_config->domain->private_bin_path = NULL;
888 end_element (GMarkupParseContext *context,
889 const gchar *element_name,
893 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
894 if (strcmp (element_name, "runtime") == 0)
895 runtime_config->runtime_count--;
896 else if (strcmp (element_name, "assemblyBinding") == 0)
897 runtime_config->assemblybinding_count--;
901 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
903 RuntimeConfig *state = (RuntimeConfig *)user_data;
905 const gchar *filename;
907 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
908 msg = error && error->message ? error->message : "";
909 g_warning ("Error parsing %s: %s", filename, msg);
912 static const GMarkupParser
922 mono_domain_set_options_from_config (MonoDomain *domain)
925 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
927 GMarkupParseContext *context;
928 RuntimeConfig runtime_config;
931 if (!domain || !domain->setup || !domain->setup->configuration_file)
934 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
935 if (!mono_error_ok (&error)) {
936 mono_error_cleanup (&error);
940 config_file_path = mono_portability_find_file (config_file_name, TRUE);
941 if (!config_file_path)
942 config_file_path = config_file_name;
944 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
947 runtime_config.runtime_count = 0;
948 runtime_config.assemblybinding_count = 0;
949 runtime_config.domain = domain;
950 runtime_config.filename = config_file_path;
953 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
954 offset = 3; /* Skip UTF-8 BOM */
956 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
957 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
958 g_markup_parse_context_end_parse (context, NULL);
959 g_markup_parse_context_free (context);
963 if (config_file_name != config_file_path)
964 g_free (config_file_name);
965 g_free (config_file_path);
969 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
972 MonoAppDomain *ad = NULL;
974 #ifdef DISABLE_APPDOMAINS
975 mono_error_init (&error);
976 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
980 fname = mono_string_to_utf8_checked (friendly_name, &error);
981 if (mono_error_set_pending_exception (&error))
983 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
987 mono_error_set_pending_exception (&error);
992 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
994 HANDLE_FUNCTION_ENTER ();
995 mono_error_init (error);
996 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
999 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1001 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1005 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1007 mono_error_init (error);
1008 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1012 GPtrArray *assemblies;
1015 * Make a copy of the list of assemblies because we can't hold the assemblies
1016 * lock while creating objects etc.
1018 assemblies = g_ptr_array_new ();
1019 /* Need to skip internal assembly builders created by remoting */
1020 mono_domain_assemblies_lock (domain);
1021 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1022 ass = (MonoAssembly *)tmp->data;
1023 if (refonly != ass->ref_only)
1025 if (ass->corlib_internal)
1027 g_ptr_array_add (assemblies, ass);
1029 mono_domain_assemblies_unlock (domain);
1031 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1034 for (i = 0; i < assemblies->len; ++i) {
1035 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1040 g_ptr_array_free (assemblies, TRUE);
1045 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1047 HANDLE_FUNCTION_ENTER ();
1048 mono_error_init (error);
1049 MonoAssembly *result = NULL;
1050 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1053 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1055 HANDLE_FUNCTION_RETURN_VAL (result);
1059 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1061 MonoAssembly *ret = NULL;
1063 MonoBoolean isrefonly;
1064 gpointer params [3];
1066 mono_error_init (error);
1068 if (mono_runtime_get_no_exec ())
1071 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1073 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1074 g_assert (method != NULL);
1076 isrefonly = refonly ? 1 : 0;
1077 MonoReflectionAssemblyHandle requesting_handle;
1079 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1080 return_val_if_nok (error, ret);
1082 params [0] = MONO_HANDLE_RAW (fname);
1083 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1084 params [2] = &isrefonly;
1085 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1086 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1091 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1095 MonoAssembly *assembly;
1096 MonoDomain *domain = mono_domain_get ();
1099 aname_str = mono_stringify_assembly_name (aname);
1101 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1103 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1105 mono_error_cleanup (&error);
1111 * LOCKING: assumes assemblies_lock in the domain is already locked.
1114 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1118 gboolean destroy_ht = FALSE;
1120 if (!ass->aname.name)
1124 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1128 /* FIXME: handle lazy loaded assemblies */
1129 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1130 g_hash_table_insert (ht, tmp->data, tmp->data);
1132 if (!g_hash_table_lookup (ht, ass)) {
1133 mono_assembly_addref (ass);
1134 g_hash_table_insert (ht, ass, ass);
1135 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1136 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1139 if (ass->image->references) {
1140 for (i = 0; ass->image->references [i] != NULL; i++) {
1141 if (ass->image->references [i] != REFERENCE_MISSING)
1142 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1143 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1148 g_hash_table_destroy (ht);
1152 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1154 static MonoClassField *assembly_load_field;
1155 static MonoMethod *assembly_load_method;
1157 MonoDomain *domain = mono_domain_get ();
1159 gpointer load_value;
1162 if (!domain->domain)
1163 /* This can happen during startup */
1165 #ifdef ASSEMBLY_LOAD_DEBUG
1166 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1168 klass = domain->domain->mbr.obj.vtable->klass;
1170 mono_domain_assemblies_lock (domain);
1171 add_assemblies_to_domain (domain, assembly, NULL);
1172 mono_domain_assemblies_unlock (domain);
1174 if (assembly_load_field == NULL) {
1175 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1176 g_assert (assembly_load_field);
1179 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1180 if (load_value == NULL) {
1181 /* No events waiting to be triggered */
1185 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1186 mono_error_assert_ok (&error);
1188 if (assembly_load_method == NULL) {
1189 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1190 g_assert (assembly_load_method);
1193 *params = MONO_HANDLE_RAW(ref_assembly);
1195 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1196 mono_error_cleanup (&error);
1200 * LOCKING: Acquires the domain assemblies lock.
1203 set_domain_search_path (MonoDomain *domain)
1206 MonoAppDomainSetup *setup;
1208 gchar *search_path = NULL;
1211 gchar **pvt_split = NULL;
1212 GError *gerror = NULL;
1213 gint appbaselen = -1;
1216 * We use the low-level domain assemblies lock, since this is called from
1217 * assembly loads hooks, which means this thread might hold the loader lock.
1219 mono_domain_assemblies_lock (domain);
1221 if (!domain->setup) {
1222 mono_domain_assemblies_unlock (domain);
1226 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1227 mono_domain_assemblies_unlock (domain);
1230 setup = domain->setup;
1231 if (!setup->application_base) {
1232 mono_domain_assemblies_unlock (domain);
1233 return; /* Must set application base to get private path working */
1238 if (setup->private_bin_path) {
1239 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1240 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1241 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1242 mono_error_cleanup (&error);
1243 mono_domain_assemblies_unlock (domain);
1248 if (domain->private_bin_path) {
1249 if (search_path == NULL)
1250 search_path = domain->private_bin_path;
1252 gchar *tmp2 = search_path;
1253 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1260 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1261 * directories relative to ApplicationBase separated by semicolons (see
1262 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1263 * The loop below copes with the fact that some Unix applications may use ':' (or
1264 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1265 * ';' for the subsequent split.
1267 * The issue was reported in bug #81446
1270 #ifndef TARGET_WIN32
1273 slen = strlen (search_path);
1274 for (i = 0; i < slen; i++)
1275 if (search_path [i] == ':')
1276 search_path [i] = ';';
1279 pvt_split = g_strsplit (search_path, ";", 1000);
1280 g_free (search_path);
1281 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1286 g_strfreev (pvt_split);
1288 * Don't do this because the first time is called, the domain
1289 * setup is not finished.
1291 * domain->search_path = g_malloc (sizeof (char *));
1292 * domain->search_path [0] = NULL;
1294 mono_domain_assemblies_unlock (domain);
1298 if (domain->search_path)
1299 g_strfreev (domain->search_path);
1301 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1302 tmp [npaths] = NULL;
1304 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1305 if (!mono_error_ok (&error)) {
1306 mono_error_cleanup (&error);
1307 g_strfreev (pvt_split);
1310 mono_domain_assemblies_unlock (domain);
1314 domain->search_path = tmp;
1316 /* FIXME: is this needed? */
1317 if (strncmp (*tmp, "file://", 7) == 0) {
1323 uri = g_strdup_printf ("file:///%s", uri + 7);
1326 uri = mono_escape_uri_string (tmpuri);
1327 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1333 if (gerror != NULL) {
1334 g_warning ("%s\n", gerror->message);
1335 g_error_free (gerror);
1342 for (i = 1; pvt_split && i < npaths; i++) {
1343 if (g_path_is_absolute (pvt_split [i - 1])) {
1344 tmp [i] = g_strdup (pvt_split [i - 1]);
1346 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1349 if (strchr (tmp [i], '.')) {
1353 reduced = mono_path_canonicalize (tmp [i]);
1354 if (appbaselen == -1)
1355 appbaselen = strlen (tmp [0]);
1357 if (strncmp (tmp [0], reduced, appbaselen)) {
1360 tmp [i] = g_strdup ("");
1370 if (setup->private_bin_path_probe != NULL) {
1372 tmp [0] = g_strdup ("");
1375 domain->setup->path_changed = FALSE;
1377 g_strfreev (pvt_split);
1379 mono_domain_assemblies_unlock (domain);
1382 #ifdef DISABLE_SHADOW_COPY
1384 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1390 mono_make_shadow_copy (const char *filename, MonoError *error)
1392 mono_error_init (error);
1393 return (char *) filename;
1397 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1399 guint16 *orig, *dest;
1400 gboolean copy_result;
1403 strcpy (src + srclen - tail_len, extension);
1405 if (IS_PORTABILITY_CASE) {
1406 gchar *file = mono_portability_find_file (src, TRUE);
1412 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1416 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1418 strcpy (target + targetlen - tail_len, extension);
1419 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1421 mono_w32file_delete (dest);
1423 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1425 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1426 * overwritten when updated in their original locations. */
1428 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1437 get_cstring_hash (const char *str)
1443 if (!str || !str [0])
1448 for (i = 0; i < len; i++) {
1449 h = (h << 5) - h + *p;
1457 * Returned memory is malloc'd. Called must free it
1460 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1462 MonoAppDomainSetup *setup;
1463 char *cache_path, *appname;
1467 mono_error_init (error);
1469 setup = domain->setup;
1470 if (setup->cache_path != NULL && setup->application_name != NULL) {
1471 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1472 return_val_if_nok (error, NULL);
1474 #ifndef TARGET_WIN32
1477 for (i = strlen (cache_path) - 1; i >= 0; i--)
1478 if (cache_path [i] == '\\')
1479 cache_path [i] = '/';
1483 appname = mono_string_to_utf8_checked (setup->application_name, error);
1484 if (!mono_error_ok (error)) {
1485 g_free (cache_path);
1489 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1491 g_free (cache_path);
1493 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1494 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1501 get_shadow_assembly_location (const char *filename, MonoError *error)
1503 gint32 hash = 0, hash2 = 0;
1505 char path_hash [30];
1506 char *bname = g_path_get_basename (filename);
1507 char *dirname = g_path_get_dirname (filename);
1508 char *location, *tmploc;
1509 MonoDomain *domain = mono_domain_get ();
1511 mono_error_init (error);
1513 hash = get_cstring_hash (bname);
1514 hash2 = get_cstring_hash (dirname);
1515 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1516 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1517 tmploc = get_shadow_assembly_location_base (domain, error);
1518 if (!mono_error_ok (error)) {
1524 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1532 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1534 struct stat sbuf_dest;
1536 gchar *real_src = mono_portability_find_file (src, TRUE);
1539 stat_src = (gchar*)src;
1541 stat_src = real_src;
1543 if (stat (stat_src, sbuf_src) == -1) {
1544 time_t tnow = time (NULL);
1549 memset (sbuf_src, 0, sizeof (*sbuf_src));
1550 sbuf_src->st_mtime = tnow;
1551 sbuf_src->st_atime = tnow;
1558 if (stat (dest, &sbuf_dest) == -1)
1561 if (sbuf_src->st_size == sbuf_dest.st_size &&
1562 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1569 shadow_copy_create_ini (const char *shadow, const char *filename)
1579 dir_name = g_path_get_dirname (shadow);
1580 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1582 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1587 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1592 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1594 if (handle == INVALID_HANDLE_VALUE) {
1598 full_path = mono_path_resolve_symlinks (filename);
1599 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1601 CloseHandle (handle);
1606 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1609 MonoAppDomainSetup *setup;
1612 gchar **directories;
1613 gchar *shadow_status_string;
1615 gboolean shadow_enabled;
1616 gboolean found = FALSE;
1621 setup = domain->setup;
1622 if (setup == NULL || setup->shadow_copy_files == NULL)
1625 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1626 if (!mono_error_ok (&error)) {
1627 mono_error_cleanup (&error);
1630 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1631 g_free (shadow_status_string);
1633 if (!shadow_enabled)
1636 if (setup->shadow_copy_directories == NULL)
1639 /* Is dir_name a shadow_copy destination already? */
1640 base_dir = get_shadow_assembly_location_base (domain, &error);
1641 if (!mono_error_ok (&error)) {
1642 mono_error_cleanup (&error);
1646 if (strstr (dir_name, base_dir)) {
1652 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1653 if (!mono_error_ok (&error)) {
1654 mono_error_cleanup (&error);
1658 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1659 dir_ptr = directories;
1661 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1667 g_strfreev (directories);
1673 This function raises exceptions so it can cause as sorts of nasty stuff if called
1674 while holding a lock.
1675 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1676 or NULL if source file not found.
1677 FIXME bubble up the error instead of raising it here
1680 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1683 gchar *sibling_source, *sibling_target;
1684 gint sibling_source_len, sibling_target_len;
1685 guint16 *orig, *dest;
1688 gboolean copy_result;
1689 struct stat src_sbuf;
1690 struct utimbuf utbuf;
1691 char *dir_name = g_path_get_dirname (filename);
1692 MonoDomain *domain = mono_domain_get ();
1696 mono_error_init (oerror);
1698 set_domain_search_path (domain);
1700 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1702 return (char *) filename;
1705 /* Is dir_name a shadow_copy destination already? */
1706 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1707 if (!mono_error_ok (&error)) {
1708 mono_error_cleanup (&error);
1710 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1714 if (strstr (dir_name, shadow_dir)) {
1715 g_free (shadow_dir);
1717 return (char *) filename;
1719 g_free (shadow_dir);
1722 shadow = get_shadow_assembly_location (filename, &error);
1723 if (!mono_error_ok (&error)) {
1724 mono_error_cleanup (&error);
1725 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1729 if (g_ensure_directory_exists (shadow) == FALSE) {
1731 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1735 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1736 return (char*) shadow;
1738 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1739 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1740 mono_w32file_delete (dest);
1742 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1743 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1744 * and not have it runtime error" */
1745 attrs = mono_w32file_get_attributes (orig);
1746 if (attrs == INVALID_FILE_ATTRIBUTES) {
1748 return (char *)filename;
1751 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1753 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1754 * overwritten when updated in their original locations. */
1756 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1761 if (copy_result == FALSE) {
1764 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1765 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1766 return NULL; /* file not found, shadow copy failed */
1768 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1772 /* attempt to copy .mdb, .config if they exist */
1773 sibling_source = g_strconcat (filename, ".config", NULL);
1774 sibling_source_len = strlen (sibling_source);
1775 sibling_target = g_strconcat (shadow, ".config", NULL);
1776 sibling_target_len = strlen (sibling_target);
1778 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1780 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1782 g_free (sibling_source);
1783 g_free (sibling_target);
1787 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1791 /* Create a .ini file containing the original assembly location */
1792 if (!shadow_copy_create_ini (shadow, filename)) {
1794 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1798 utbuf.actime = src_sbuf.st_atime;
1799 utbuf.modtime = src_sbuf.st_mtime;
1800 utime (shadow, &utbuf);
1804 #endif /* DISABLE_SHADOW_COPY */
1807 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1809 if (appdomain == NULL)
1812 if (mono_object_is_transparent_proxy (&appdomain->mbr.obj)) {
1813 MonoTransparentProxy *tp = (MonoTransparentProxy*)appdomain;
1814 return mono_domain_get_by_id (tp->rp->target_domain_id);
1817 return appdomain->data;
1821 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1822 const gchar *path3, const gchar *path4,
1823 gboolean refonly, gboolean is_private)
1826 gboolean found = FALSE;
1829 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1831 if (IS_PORTABILITY_SET) {
1832 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1835 fullpath = new_fullpath;
1839 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1842 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1845 return (*assembly != NULL);
1848 static MonoAssembly *
1849 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1851 MonoAssembly *result = NULL;
1854 const gchar *local_culture;
1856 gboolean is_private = FALSE;
1858 if (!culture || *culture == '\0') {
1861 local_culture = culture;
1864 filename = g_strconcat (name, ".dll", NULL);
1865 len = strlen (filename);
1867 for (path = search_path; *path; path++) {
1868 if (**path == '\0') {
1870 continue; /* Ignore empty ApplicationBase */
1873 /* See test cases in bug #58992 and bug #57710 */
1874 /* 1st try: [culture]/[name].dll (culture may be empty) */
1875 strcpy (filename + len - 4, ".dll");
1876 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1879 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1880 strcpy (filename + len - 4, ".exe");
1881 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1884 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1885 strcpy (filename + len - 4, ".dll");
1886 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1889 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1890 strcpy (filename + len - 4, ".exe");
1891 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1900 * Try loading the assembly from ApplicationBase and PrivateBinPath
1901 * and then from assemblies_path if any.
1902 * LOCKING: This is called from the assembly loading code, which means the caller
1903 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1905 static MonoAssembly *
1906 mono_domain_assembly_preload (MonoAssemblyName *aname,
1907 gchar **assemblies_path,
1910 MonoDomain *domain = mono_domain_get ();
1911 MonoAssembly *result = NULL;
1912 gboolean refonly = GPOINTER_TO_UINT (user_data);
1914 set_domain_search_path (domain);
1916 if (domain->search_path && domain->search_path [0] != NULL) {
1917 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1920 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1921 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1928 * Check whenever a given assembly was already loaded in the current appdomain.
1930 static MonoAssembly *
1931 mono_domain_assembly_search (MonoAssemblyName *aname,
1934 MonoDomain *domain = mono_domain_get ();
1937 gboolean refonly = GPOINTER_TO_UINT (user_data);
1939 mono_domain_assemblies_lock (domain);
1940 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1941 ass = (MonoAssembly *)tmp->data;
1942 /* Dynamic assemblies can't match here in MS.NET */
1943 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1946 mono_domain_assemblies_unlock (domain);
1949 mono_domain_assemblies_unlock (domain);
1954 MonoReflectionAssemblyHandle
1955 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
1957 mono_error_init (error);
1958 MonoDomain *domain = mono_domain_get ();
1959 char *name, *filename;
1960 MonoImageOpenStatus status = MONO_IMAGE_OK;
1961 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
1966 if (fname == NULL) {
1967 mono_error_set_argument_null (error, "assemblyFile", "");
1971 name = filename = mono_string_handle_to_utf8 (fname, error);
1975 MonoAssembly *ass = mono_assembly_open_full (filename, &status, refOnly);
1978 if (status == MONO_IMAGE_IMAGE_INVALID)
1979 mono_error_set_bad_image_name (error, g_strdup (name), "");
1981 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
1985 result = mono_assembly_get_object_handle (domain, ass, error);
1992 MonoReflectionAssemblyHandle
1993 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
1994 MonoArrayHandle raw_assembly,
1995 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
1996 MonoBoolean refonly,
1999 mono_error_init (error);
2001 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2002 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2003 MonoImageOpenStatus status;
2004 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2006 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2007 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2008 if (!assembly_data) {
2009 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2013 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2014 memcpy (assembly_data, raw_data, raw_assembly_len);
2015 mono_gchandle_free (gchandle); /* unpin */
2016 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2018 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2021 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2025 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2026 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2027 uint32_t symbol_gchandle;
2028 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2029 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2030 mono_gchandle_free (symbol_gchandle);
2033 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2037 mono_image_close (image);
2038 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2042 refass = mono_assembly_get_object_handle (domain, ass, error);
2043 if (!MONO_HANDLE_IS_NULL(refass))
2044 MONO_HANDLE_SET (refass, evidence, evidence);
2048 MonoReflectionAssemblyHandle
2049 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2051 mono_error_init (error);
2052 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2053 MonoImageOpenStatus status = MONO_IMAGE_OK;
2055 MonoAssemblyName aname;
2061 name = mono_string_handle_to_utf8 (assRef, error);
2064 parsed = mono_assembly_name_parse (name, &aname);
2068 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2069 /* This is a parse error... */
2071 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2075 refass = mono_assembly_get_object_handle (domain, assm, error);
2083 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2084 mono_assembly_name_free (&aname);
2087 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2089 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2098 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2102 MONO_HANDLE_SET (refass, evidence, evidence);
2106 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2110 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2112 MonoException *exc = NULL;
2113 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2115 if (NULL == domain) {
2116 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2117 mono_set_pending_exception (exc);
2121 if (domain == mono_get_root_domain ()) {
2122 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2127 * Unloading seems to cause problems when running NUnit/NAnt, hence
2130 if (g_getenv ("MONO_NO_UNLOAD"))
2132 #ifdef __native_client__
2136 mono_domain_try_unload (domain, (MonoObject**)&exc);
2138 mono_set_pending_exception (exc);
2142 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2144 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2149 return mono_domain_is_unloading (domain);
2153 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2155 mono_unhandled_exception ((MonoObject*) exc);
2159 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2160 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2163 mono_error_init (error);
2167 g_assert (!MONO_HANDLE_IS_NULL (refass));
2168 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2169 image = assembly->image;
2172 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2175 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2177 if (MONO_HANDLE_IS_NULL (args)) {
2178 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2179 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2180 mono_error_assert_ok (error);
2183 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2188 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2190 return ad->data->domain_id;
2194 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2196 MonoDomain *old_domain = mono_domain_get();
2198 if (!mono_domain_set (ad->data, FALSE)) {
2199 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2203 return old_domain->domain;
2207 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2209 MonoDomain *current_domain = mono_domain_get ();
2210 MonoDomain *domain = mono_domain_get_by_id (domainid);
2212 if (!domain || !mono_domain_set (domain, FALSE)) {
2213 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2217 return current_domain->domain;
2221 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2223 mono_thread_push_appdomain_ref (ad->data);
2227 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2229 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2233 * Raise an exception to prevent the managed code from executing a pop
2236 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2240 mono_thread_push_appdomain_ref (domain);
2244 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2246 mono_thread_pop_appdomain_ref ();
2250 ves_icall_System_AppDomain_InternalGetContext ()
2252 return mono_context_get ();
2256 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2258 return mono_domain_get ()->default_context;
2262 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2264 MonoAppContext *old_context = mono_context_get ();
2266 mono_context_set (mc);
2272 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2274 MonoDomain* mono_root_domain = mono_get_root_domain ();
2275 mono_domain_lock (mono_root_domain);
2276 if (process_guid_set) {
2277 mono_domain_unlock (mono_root_domain);
2279 MonoString *res = NULL;
2280 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2281 mono_error_set_pending_exception (&error);
2284 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2285 process_guid_set = TRUE;
2286 mono_domain_unlock (mono_root_domain);
2291 mono_domain_is_unloading (MonoDomain *domain)
2293 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2300 clear_cached_vtable (MonoVTable *vtable)
2302 MonoClass *klass = vtable->klass;
2303 MonoDomain *domain = vtable->domain;
2304 MonoClassRuntimeInfo *runtime_info;
2307 runtime_info = klass->runtime_info;
2308 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2309 runtime_info->domain_vtables [domain->domain_id] = NULL;
2310 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2311 mono_gc_free_fixed (data);
2314 static G_GNUC_UNUSED void
2315 zero_static_data (MonoVTable *vtable)
2317 MonoClass *klass = vtable->klass;
2320 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2321 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2324 typedef struct unload_data {
2327 char *failure_reason;
2332 unload_data_unref (unload_data *data)
2336 mono_atomic_load_acquire (count, gint32, &data->refcount);
2337 g_assert (count >= 1 && count <= 2);
2342 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2346 deregister_reflection_info_roots_from_list (MonoImage *image)
2348 GSList *list = image->reflection_info_unregister_classes;
2351 MonoClass *klass = (MonoClass *)list->data;
2353 mono_class_free_ref_info (klass);
2358 image->reflection_info_unregister_classes = NULL;
2362 deregister_reflection_info_roots (MonoDomain *domain)
2366 mono_domain_assemblies_lock (domain);
2367 for (list = domain->domain_assemblies; list; list = list->next) {
2368 MonoAssembly *assembly = (MonoAssembly *)list->data;
2369 MonoImage *image = assembly->image;
2373 * No need to take the image lock here since dynamic images are appdomain bound and
2374 * at this point the mutator is gone. Taking the image lock here would mean
2375 * promoting it from a simple lock to a complex lock, which we better avoid if
2378 if (image_is_dynamic (image))
2379 deregister_reflection_info_roots_from_list (image);
2381 for (i = 0; i < image->module_count; ++i) {
2382 MonoImage *module = image->modules [i];
2383 if (module && image_is_dynamic (module))
2384 deregister_reflection_info_roots_from_list (module);
2387 mono_domain_assemblies_unlock (domain);
2391 unload_thread_main (void *arg)
2394 unload_data *data = (unload_data*)arg;
2395 MonoDomain *domain = data->domain;
2399 /* Have to attach to the runtime so shutdown can wait for this thread */
2400 /* Force it to be attached to avoid racing during shutdown. */
2401 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2403 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2404 if (!is_ok (&error)) {
2405 data->failure_reason = g_strdup (mono_error_get_message (&error));
2406 mono_error_cleanup (&error);
2411 * FIXME: Abort our parent thread last, so we can return a failure
2412 * indication if aborting times out.
2414 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2415 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2419 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2420 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2424 /* Finalize all finalizable objects in the doomed appdomain */
2425 if (!mono_domain_finalize (domain, -1)) {
2426 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2430 /* Clear references to our vtables in class->runtime_info.
2431 * We also hold the loader lock because we're going to change
2432 * class->runtime_info.
2435 mono_loader_lock (); //FIXME why do we need the loader lock here?
2436 mono_domain_lock (domain);
2439 * We need to make sure that we don't have any remsets
2440 * pointing into static data of the to-be-freed domain because
2441 * at the next collections they would be invalid. So what we
2442 * do is we first zero all static data and then do a minor
2443 * collection. Because all references in the static data will
2444 * now be null we won't do any unnecessary copies and after
2445 * the collection there won't be any more remsets.
2447 for (i = 0; i < domain->class_vtable_array->len; ++i)
2448 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2449 mono_gc_collect (0);
2451 for (i = 0; i < domain->class_vtable_array->len; ++i)
2452 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2453 deregister_reflection_info_roots (domain);
2455 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2457 mono_domain_unlock (domain);
2458 mono_loader_unlock ();
2460 mono_threads_clear_cached_culture (domain);
2462 domain->state = MONO_APPDOMAIN_UNLOADED;
2464 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2466 /* remove from the handle table the items related to this domain */
2467 mono_gchandle_free_domain (domain);
2469 mono_domain_free (domain, FALSE);
2471 mono_gc_collect (mono_gc_max_generation ());
2473 mono_atomic_store_release (&data->done, TRUE);
2474 unload_data_unref (data);
2475 mono_thread_detach (thread);
2479 mono_atomic_store_release (&data->done, TRUE);
2480 unload_data_unref (data);
2481 mono_thread_detach (thread);
2486 * mono_domain_unload:
2487 * @domain: The domain to unload
2489 * Unloads an appdomain. Follows the process outlined in the comment
2490 * for mono_domain_try_unload.
2493 mono_domain_unload (MonoDomain *domain)
2495 MonoObject *exc = NULL;
2496 mono_domain_try_unload (domain, &exc);
2499 static MonoThreadInfoWaitRet
2500 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2502 MonoThreadInfoWaitRet result;
2505 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2512 * mono_domain_unload:
2513 * @domain: The domain to unload
2514 * @exc: Exception information
2516 * Unloads an appdomain. Follows the process outlined in:
2517 * http://blogs.gotdotnet.com/cbrumme
2519 * If doing things the 'right' way is too hard or complex, we do it the
2520 * 'simple' way, which means do everything needed to avoid crashes and
2521 * memory leaks, but not much else.
2523 * It is required to pass a valid reference to the exc argument, upon return
2524 * from this function *exc will be set to the exception thrown, if any.
2526 * If this method is not called from an icall (embedded scenario for instance),
2527 * it must not be called with any managed frames on the stack, since the unload
2528 * process could end up trying to abort the current thread.
2531 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2534 MonoThreadHandle *thread_handle;
2535 MonoAppDomainState prev_state;
2537 unload_data *thread_data;
2538 MonoNativeThreadId tid;
2539 MonoDomain *caller_domain = mono_domain_get ();
2541 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2543 /* Atomically change our state to UNLOADING */
2544 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2545 MONO_APPDOMAIN_UNLOADING_START,
2546 MONO_APPDOMAIN_CREATED);
2547 if (prev_state != MONO_APPDOMAIN_CREATED) {
2548 switch (prev_state) {
2549 case MONO_APPDOMAIN_UNLOADING_START:
2550 case MONO_APPDOMAIN_UNLOADING:
2551 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2553 case MONO_APPDOMAIN_UNLOADED:
2554 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2557 g_warning ("Invalid appdomain state %d", prev_state);
2558 g_assert_not_reached ();
2562 mono_domain_set (domain, FALSE);
2563 /* Notify OnDomainUnload listeners */
2564 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2567 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2569 if (!mono_error_ok (&error)) {
2571 mono_error_cleanup (&error);
2573 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2577 /* Roll back the state change */
2578 domain->state = MONO_APPDOMAIN_CREATED;
2579 mono_domain_set (caller_domain, FALSE);
2582 mono_domain_set (caller_domain, FALSE);
2584 thread_data = g_new0 (unload_data, 1);
2585 thread_data->domain = domain;
2586 thread_data->failure_reason = NULL;
2587 thread_data->done = FALSE;
2588 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2590 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2591 domain->state = MONO_APPDOMAIN_UNLOADING;
2593 * First we create a separate thread for unloading, since
2594 * we might have to abort some threads, including the current one.
2596 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2597 if (thread_handle == NULL)
2600 /* Wait for the thread */
2601 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2602 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2603 /* The unload thread tries to abort us */
2604 /* The icall wrapper will execute the abort */
2605 mono_threads_close_thread_handle (thread_handle);
2606 unload_data_unref (thread_data);
2611 mono_threads_close_thread_handle (thread_handle);
2613 if (thread_data->failure_reason) {
2614 /* Roll back the state change */
2615 domain->state = MONO_APPDOMAIN_CREATED;
2617 g_warning ("%s", thread_data->failure_reason);
2619 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2621 g_free (thread_data->failure_reason);
2622 thread_data->failure_reason = NULL;
2625 unload_data_unref (thread_data);