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/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
80 * This is the version number of the corlib-runtime interface. When
81 * making changes to this interface (by changing the layout
82 * of classes the runtime knows about, changing icall signature or
83 * semantics etc), increment this variable. Also increment the
84 * pair of this variable in mscorlib in:
85 * mcs/class/corlib/System/Environment.cs
87 * Changes which are already detected at runtime, like the addition
88 * of icalls, do not require an increment.
90 #define MONO_CORLIB_VERSION 164
95 int assemblybinding_count;
100 static gunichar2 process_guid [36];
101 static gboolean process_guid_set = FALSE;
103 static gboolean no_exec = FALSE;
105 static MonoAssembly *
106 mono_domain_assembly_preload (MonoAssemblyName *aname,
107 gchar **assemblies_path,
110 static MonoAssembly *
111 mono_domain_assembly_search (MonoAssemblyName *aname,
115 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
118 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
120 static MonoAppDomain *
121 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
124 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
126 static MonoLoadFunc load_function = NULL;
128 /* Lazy class loading functions */
129 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly);
131 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, System, AppDomain);
134 mono_install_runtime_load (MonoLoadFunc func)
136 load_function = func;
140 mono_runtime_load (const char *filename, const char *runtime_version)
142 g_assert (load_function);
143 return load_function (filename, runtime_version);
147 * mono_runtime_set_no_exec:
149 * Instructs the runtime to operate in static mode, i.e. avoid/do not
150 * allow managed code execution. This is useful for running the AOT
151 * compiler on platforms which allow full-aot execution only. This
152 * should be called before mono_runtime_init ().
155 mono_runtime_set_no_exec (gboolean val)
161 * mono_runtime_get_no_exec:
163 * If true, then the runtime will not allow managed code execution.
166 mono_runtime_get_no_exec (void)
172 create_domain_objects (MonoDomain *domain)
175 MonoDomain *old_domain = mono_domain_get ();
177 MonoVTable *string_vt;
178 MonoClassField *string_empty_fld;
180 if (domain != old_domain) {
181 mono_thread_push_appdomain_ref (domain);
182 mono_domain_set_internal_with_options (domain, FALSE);
186 * Initialize String.Empty. This enables the removal of
187 * the static cctor of the String class.
189 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
190 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
191 g_assert (string_empty_fld);
192 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
193 mono_error_assert_ok (&error);
194 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
195 domain->empty_string = empty_str;
198 * Create an instance early since we can't do it when there is no memory.
200 arg = mono_string_new (domain, "Out of memory");
201 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
202 mono_error_assert_ok (&error);
205 * These two are needed because the signal handlers might be executing on
206 * an alternate stack, and Boehm GC can't handle that.
208 arg = mono_string_new (domain, "A null value was found where an object instance was required");
209 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
210 mono_error_assert_ok (&error);
211 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
212 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
213 mono_error_assert_ok (&error);
215 /*The ephemeron tombstone i*/
216 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
217 mono_error_assert_ok (&error);
219 if (domain != old_domain) {
220 mono_thread_pop_appdomain_ref ();
221 mono_domain_set_internal_with_options (old_domain, FALSE);
225 * This class is used during exception handling, so initialize it here, to prevent
226 * stack overflows while handling stack overflows.
228 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
233 * @domain: domain returned by mono_init ()
235 * Initialize the core AppDomain: this function will run also some
236 * IL initialization code, so it needs the execution engine to be fully
239 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
240 * we know the entry_assembly.
244 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
247 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
248 mono_error_cleanup (&error);
252 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
254 MonoAppDomainSetup *setup;
258 mono_error_init (error);
260 mono_portability_helpers_init ();
262 mono_gc_base_init ();
263 mono_monitor_init ();
264 mono_marshal_init ();
266 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
267 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
268 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
269 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
270 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
271 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
272 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
274 mono_thread_init (start_cb, attach_cb);
276 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
277 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
278 return_if_nok (error);
280 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
282 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
283 return_if_nok (error);
287 domain->setup = setup;
289 mono_thread_attach (domain);
291 mono_type_initialization_init ();
293 if (!mono_runtime_get_no_exec ())
294 create_domain_objects (domain);
296 /* GC init has to happen after thread init */
299 /* contexts use GC handles, so they must be initialized after the GC */
300 mono_context_init_checked (domain, error);
301 return_if_nok (error);
302 mono_context_set (domain->default_context);
304 #ifndef DISABLE_SOCKETS
305 mono_network_init ();
308 mono_console_init ();
311 mono_locks_tracer_init ();
313 /* mscorlib is loaded before we install the load hook */
314 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
320 mono_get_corlib_version (void)
324 MonoClassField *field;
327 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
328 mono_class_init (klass);
329 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
332 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
334 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
335 mono_error_assert_ok (&error);
336 return *(gint32*)((gchar*)value + sizeof (MonoObject));
340 * mono_check_corlib_version
342 * Checks that the corlib that is loaded matches the version of this runtime.
344 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
345 * allocated string with the error otherwise.
348 mono_check_corlib_version (void)
350 int version = mono_get_corlib_version ();
351 if (version != MONO_CORLIB_VERSION)
352 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
354 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
355 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
356 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
357 if (native_offset != managed_offset)
358 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
365 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
367 * Initializes the @domain's default System.Runtime.Remoting's Context.
370 mono_context_init (MonoDomain *domain)
373 mono_context_init_checked (domain, &error);
374 mono_error_cleanup (&error);
378 mono_context_init_checked (MonoDomain *domain, MonoError *error)
381 MonoAppContext *context;
383 mono_error_init (error);
385 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
386 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
387 return_if_nok (error);
389 context->domain_id = domain->domain_id;
390 context->context_id = 0;
391 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
392 domain->default_context = context;
396 * mono_runtime_cleanup:
401 * This must not be called while there are still running threads executing
405 mono_runtime_cleanup (MonoDomain *domain)
407 mono_attach_cleanup ();
409 /* This ends up calling any pending pending (for at most 2 seconds) */
412 mono_thread_cleanup ();
414 #ifndef DISABLE_SOCKETS
415 mono_network_cleanup ();
417 mono_marshal_cleanup ();
419 mono_type_initialization_cleanup ();
421 mono_monitor_cleanup ();
424 static MonoDomainFunc quit_function = NULL;
427 mono_install_runtime_cleanup (MonoDomainFunc func)
429 quit_function = func;
435 if (quit_function != NULL)
436 quit_function (mono_get_root_domain (), NULL);
440 * mono_domain_create_appdomain:
441 * @friendly_name: The friendly name of the appdomain to create
442 * @configuration_file: The configuration file to initialize the appdomain with
444 * Returns a MonoDomain initialized with the appdomain
447 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
451 MonoAppDomainSetup *setup;
454 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
455 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
458 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
460 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
464 return mono_domain_from_appdomain (ad);
466 mono_error_cleanup (&error);
471 * mono_domain_set_config:
472 * @domain: MonoDomain initialized with the appdomain we want to change
473 * @base_dir: new base directory for the appdomain
474 * @config_file_name: path to the new configuration for the app domain
476 * Used to set the system configuration for an appdomain
478 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
479 * Error Initializing the configuration system. ---> System.ArgumentException:
480 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
483 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
485 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
486 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
489 static MonoAppDomainSetup*
490 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
492 MonoDomain *caller_domain;
493 MonoClass *ads_class;
494 MonoAppDomainSetup *copy;
496 mono_error_init (error);
498 caller_domain = mono_domain_get ();
499 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
501 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
502 return_val_if_nok (error, NULL);
504 mono_domain_set_internal (domain);
506 #define XCOPY_FIELD(dst,field,src,error) \
508 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
509 return_val_if_nok (error, NULL); \
510 MONO_OBJECT_SETREF ((dst),field,copied_val); \
513 XCOPY_FIELD (copy, application_base, setup->application_base, error);
514 XCOPY_FIELD (copy, application_name, setup->application_name, error);
515 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
516 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
517 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
518 XCOPY_FIELD (copy, license_file, setup->license_file, error);
519 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
520 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
521 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
522 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
523 copy->publisher_policy = setup->publisher_policy;
524 copy->path_changed = setup->path_changed;
525 copy->loader_optimization = setup->loader_optimization;
526 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
527 copy->disallow_code_downloads = setup->disallow_code_downloads;
528 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
529 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
530 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
531 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
532 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
536 mono_domain_set_internal (caller_domain);
541 static MonoAppDomain *
542 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
547 char *shadow_location;
549 mono_error_init (error);
551 adclass = mono_class_get_appdomain_class ();
553 /* FIXME: pin all those objects */
554 data = mono_domain_create();
556 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
557 return_val_if_nok (error, NULL);
560 data->friendly_name = g_strdup (friendly_name);
562 mono_profiler_appdomain_name (data, data->friendly_name);
564 if (!setup->application_base) {
565 /* Inherit from the root domain since MS.NET does this */
566 MonoDomain *root = mono_get_root_domain ();
567 if (root->setup->application_base) {
568 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
569 mono_error_assert_ok (error); /* FIXME don't swallow the error */
570 MONO_OBJECT_SETREF (setup, application_base, s);
574 mono_context_init_checked (data, error);
575 return_val_if_nok (error, NULL);
577 data->setup = copy_app_domain_setup (data, setup, error);
578 if (!mono_error_ok (error)) {
579 g_free (data->friendly_name);
583 mono_domain_set_options_from_config (data);
584 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
586 #ifndef DISABLE_SHADOW_COPY
587 /*FIXME, guard this for when the debugger is not running */
588 shadow_location = get_shadow_assembly_location_base (data, error);
589 if (!mono_error_ok (error)) {
590 g_free (data->friendly_name);
594 g_free (shadow_location);
597 create_domain_objects (data);
603 * mono_domain_has_type_resolve:
604 * @domain: application domains being looked up
606 * Returns: TRUE if the AppDomain.TypeResolve field has been
610 mono_domain_has_type_resolve (MonoDomain *domain)
612 static MonoClassField *field = NULL;
616 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
620 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
624 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
629 * mono_domain_try_type_resolve:
630 * @domain: application domainwhere the name where the type is going to be resolved
631 * @name: the name of the type to resolve or NULL.
632 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
634 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
635 * the assembly that matches name.
637 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
639 * Returns: A MonoReflectionAssembly or NULL if not found
641 MonoReflectionAssembly *
642 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
645 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
646 mono_error_cleanup (&error);
651 MonoReflectionAssembly *
652 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
654 static MonoMethod *method = NULL;
655 MonoReflectionAssembly *ret;
658 mono_error_init (error);
660 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
662 if (method == NULL) {
663 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
664 if (method == NULL) {
665 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
671 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
675 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
676 return_val_if_nok (error, NULL);
682 * mono_domain_owns_vtable_slot:
684 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
687 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
691 mono_domain_lock (domain);
692 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
693 mono_domain_unlock (domain);
700 * @force: force setting.
702 * Set the current appdomain to @domain. If @force is set, set it even
703 * if it is being unloaded.
707 * FALSE if the domain is unloaded
710 mono_domain_set (MonoDomain *domain, gboolean force)
712 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
715 mono_domain_set_internal (domain);
721 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
728 MONO_CHECK_ARG_NULL (name, NULL);
734 str = mono_string_to_utf8_checked (name, &error);
735 if (mono_error_set_pending_exception (&error))
738 mono_domain_lock (add);
740 if (!strcmp (str, "APPBASE"))
741 o = (MonoObject *)add->setup->application_base;
742 else if (!strcmp (str, "APP_CONFIG_FILE"))
743 o = (MonoObject *)add->setup->configuration_file;
744 else if (!strcmp (str, "DYNAMIC_BASE"))
745 o = (MonoObject *)add->setup->dynamic_base;
746 else if (!strcmp (str, "APP_NAME"))
747 o = (MonoObject *)add->setup->application_name;
748 else if (!strcmp (str, "CACHE_BASE"))
749 o = (MonoObject *)add->setup->cache_path;
750 else if (!strcmp (str, "PRIVATE_BINPATH"))
751 o = (MonoObject *)add->setup->private_bin_path;
752 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
753 o = (MonoObject *)add->setup->private_bin_path_probe;
754 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
755 o = (MonoObject *)add->setup->shadow_copy_directories;
756 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
757 o = (MonoObject *)add->setup->shadow_copy_files;
759 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
761 mono_domain_unlock (add);
771 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
775 MONO_CHECK_ARG_NULL (name,);
781 mono_domain_lock (add);
783 mono_g_hash_table_insert (add->env, name, data);
785 mono_domain_unlock (add);
789 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
794 return ad->data->setup;
798 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
803 return mono_string_new (ad->data, ad->data->friendly_name);
807 ves_icall_System_AppDomain_getCurDomain ()
809 MonoDomain *add = mono_domain_get ();
815 ves_icall_System_AppDomain_getRootDomain ()
817 MonoDomain *root = mono_get_root_domain ();
823 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
825 MonoDomain *domain = mono_domain_get ();
827 return domain->throw_unobserved_task_exceptions;
831 get_attribute_value (const gchar **attribute_names,
832 const gchar **attribute_values,
833 const char *att_name)
836 for (n = 0; attribute_names [n] != NULL; n++) {
837 if (strcmp (attribute_names [n], att_name) == 0)
838 return g_strdup (attribute_values [n]);
844 start_element (GMarkupParseContext *context,
845 const gchar *element_name,
846 const gchar **attribute_names,
847 const gchar **attribute_values,
851 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
853 if (strcmp (element_name, "runtime") == 0) {
854 runtime_config->runtime_count++;
858 if (strcmp (element_name, "assemblyBinding") == 0) {
859 runtime_config->assemblybinding_count++;
863 if (runtime_config->runtime_count != 1)
866 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
867 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
869 if (value && g_ascii_strcasecmp (value, "true") == 0)
870 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
873 if (runtime_config->assemblybinding_count != 1)
876 if (strcmp (element_name, "probing") != 0)
879 g_free (runtime_config->domain->private_bin_path);
880 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
881 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
882 g_free (runtime_config->domain->private_bin_path);
883 runtime_config->domain->private_bin_path = NULL;
889 end_element (GMarkupParseContext *context,
890 const gchar *element_name,
894 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
895 if (strcmp (element_name, "runtime") == 0)
896 runtime_config->runtime_count--;
897 else if (strcmp (element_name, "assemblyBinding") == 0)
898 runtime_config->assemblybinding_count--;
902 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
904 RuntimeConfig *state = (RuntimeConfig *)user_data;
906 const gchar *filename;
908 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
909 msg = error && error->message ? error->message : "";
910 g_warning ("Error parsing %s: %s", filename, msg);
913 static const GMarkupParser
923 mono_domain_set_options_from_config (MonoDomain *domain)
926 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
928 GMarkupParseContext *context;
929 RuntimeConfig runtime_config;
932 if (!domain || !domain->setup || !domain->setup->configuration_file)
935 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
936 if (!mono_error_ok (&error)) {
937 mono_error_cleanup (&error);
941 config_file_path = mono_portability_find_file (config_file_name, TRUE);
942 if (!config_file_path)
943 config_file_path = config_file_name;
945 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
948 runtime_config.runtime_count = 0;
949 runtime_config.assemblybinding_count = 0;
950 runtime_config.domain = domain;
951 runtime_config.filename = config_file_path;
954 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
955 offset = 3; /* Skip UTF-8 BOM */
957 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
958 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
959 g_markup_parse_context_end_parse (context, NULL);
960 g_markup_parse_context_free (context);
964 if (config_file_name != config_file_path)
965 g_free (config_file_name);
966 g_free (config_file_path);
970 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
973 MonoAppDomain *ad = NULL;
975 #ifdef DISABLE_APPDOMAINS
976 mono_error_init (&error);
977 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
981 fname = mono_string_to_utf8_checked (friendly_name, &error);
982 if (mono_error_set_pending_exception (&error))
984 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
988 mono_error_set_pending_exception (&error);
993 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
995 HANDLE_FUNCTION_ENTER ();
996 mono_error_init (error);
997 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1000 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1002 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1006 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1008 mono_error_init (error);
1009 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1013 GPtrArray *assemblies;
1016 * Make a copy of the list of assemblies because we can't hold the assemblies
1017 * lock while creating objects etc.
1019 assemblies = g_ptr_array_new ();
1020 /* Need to skip internal assembly builders created by remoting */
1021 mono_domain_assemblies_lock (domain);
1022 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1023 ass = (MonoAssembly *)tmp->data;
1024 if (refonly != ass->ref_only)
1026 if (ass->corlib_internal)
1028 g_ptr_array_add (assemblies, ass);
1030 mono_domain_assemblies_unlock (domain);
1032 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1035 for (i = 0; i < assemblies->len; ++i) {
1036 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1041 g_ptr_array_free (assemblies, TRUE);
1046 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1048 HANDLE_FUNCTION_ENTER ();
1049 mono_error_init (error);
1050 MonoAssembly *result = NULL;
1051 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1054 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1056 HANDLE_FUNCTION_RETURN_VAL (result);
1060 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1062 MonoAssembly *ret = NULL;
1064 MonoBoolean isrefonly;
1065 gpointer params [3];
1067 mono_error_init (error);
1069 if (mono_runtime_get_no_exec ())
1072 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1074 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1075 g_assert (method != NULL);
1077 isrefonly = refonly ? 1 : 0;
1078 MonoReflectionAssemblyHandle requesting_handle;
1080 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1081 return_val_if_nok (error, ret);
1083 params [0] = MONO_HANDLE_RAW (fname);
1084 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1085 params [2] = &isrefonly;
1086 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1087 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1092 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1096 MonoAssembly *assembly;
1097 MonoDomain *domain = mono_domain_get ();
1100 aname_str = mono_stringify_assembly_name (aname);
1102 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1104 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1106 mono_error_cleanup (&error);
1112 * LOCKING: assumes assemblies_lock in the domain is already locked.
1115 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1119 gboolean destroy_ht = FALSE;
1121 if (!ass->aname.name)
1125 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1129 /* FIXME: handle lazy loaded assemblies */
1130 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1131 g_hash_table_insert (ht, tmp->data, tmp->data);
1133 if (!g_hash_table_lookup (ht, ass)) {
1134 mono_assembly_addref (ass);
1135 g_hash_table_insert (ht, ass, ass);
1136 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1137 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);
1140 if (ass->image->references) {
1141 for (i = 0; ass->image->references [i] != NULL; i++) {
1142 if (ass->image->references [i] != REFERENCE_MISSING)
1143 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1144 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1149 g_hash_table_destroy (ht);
1153 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1155 static MonoClassField *assembly_load_field;
1156 static MonoMethod *assembly_load_method;
1158 MonoDomain *domain = mono_domain_get ();
1160 gpointer load_value;
1163 if (!domain->domain)
1164 /* This can happen during startup */
1166 #ifdef ASSEMBLY_LOAD_DEBUG
1167 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1169 klass = domain->domain->mbr.obj.vtable->klass;
1171 mono_domain_assemblies_lock (domain);
1172 add_assemblies_to_domain (domain, assembly, NULL);
1173 mono_domain_assemblies_unlock (domain);
1175 if (assembly_load_field == NULL) {
1176 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1177 g_assert (assembly_load_field);
1180 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1181 if (load_value == NULL) {
1182 /* No events waiting to be triggered */
1186 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1187 mono_error_assert_ok (&error);
1189 if (assembly_load_method == NULL) {
1190 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1191 g_assert (assembly_load_method);
1194 *params = MONO_HANDLE_RAW(ref_assembly);
1196 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1197 mono_error_cleanup (&error);
1201 * LOCKING: Acquires the domain assemblies lock.
1204 set_domain_search_path (MonoDomain *domain)
1207 MonoAppDomainSetup *setup;
1209 gchar *search_path = NULL;
1212 gchar **pvt_split = NULL;
1213 GError *gerror = NULL;
1214 gint appbaselen = -1;
1217 * We use the low-level domain assemblies lock, since this is called from
1218 * assembly loads hooks, which means this thread might hold the loader lock.
1220 mono_domain_assemblies_lock (domain);
1222 if (!domain->setup) {
1223 mono_domain_assemblies_unlock (domain);
1227 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1228 mono_domain_assemblies_unlock (domain);
1231 setup = domain->setup;
1232 if (!setup->application_base) {
1233 mono_domain_assemblies_unlock (domain);
1234 return; /* Must set application base to get private path working */
1239 if (setup->private_bin_path) {
1240 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1241 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1242 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1243 mono_error_cleanup (&error);
1244 mono_domain_assemblies_unlock (domain);
1249 if (domain->private_bin_path) {
1250 if (search_path == NULL)
1251 search_path = domain->private_bin_path;
1253 gchar *tmp2 = search_path;
1254 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1261 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1262 * directories relative to ApplicationBase separated by semicolons (see
1263 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1264 * The loop below copes with the fact that some Unix applications may use ':' (or
1265 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1266 * ';' for the subsequent split.
1268 * The issue was reported in bug #81446
1271 #ifndef TARGET_WIN32
1274 slen = strlen (search_path);
1275 for (i = 0; i < slen; i++)
1276 if (search_path [i] == ':')
1277 search_path [i] = ';';
1280 pvt_split = g_strsplit (search_path, ";", 1000);
1281 g_free (search_path);
1282 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1287 g_strfreev (pvt_split);
1289 * Don't do this because the first time is called, the domain
1290 * setup is not finished.
1292 * domain->search_path = g_malloc (sizeof (char *));
1293 * domain->search_path [0] = NULL;
1295 mono_domain_assemblies_unlock (domain);
1299 if (domain->search_path)
1300 g_strfreev (domain->search_path);
1302 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1303 tmp [npaths] = NULL;
1305 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1306 if (!mono_error_ok (&error)) {
1307 mono_error_cleanup (&error);
1308 g_strfreev (pvt_split);
1311 mono_domain_assemblies_unlock (domain);
1315 domain->search_path = tmp;
1317 /* FIXME: is this needed? */
1318 if (strncmp (*tmp, "file://", 7) == 0) {
1324 uri = g_strdup_printf ("file:///%s", uri + 7);
1327 uri = mono_escape_uri_string (tmpuri);
1328 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1334 if (gerror != NULL) {
1335 g_warning ("%s\n", gerror->message);
1336 g_error_free (gerror);
1343 for (i = 1; pvt_split && i < npaths; i++) {
1344 if (g_path_is_absolute (pvt_split [i - 1])) {
1345 tmp [i] = g_strdup (pvt_split [i - 1]);
1347 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1350 if (strchr (tmp [i], '.')) {
1354 reduced = mono_path_canonicalize (tmp [i]);
1355 if (appbaselen == -1)
1356 appbaselen = strlen (tmp [0]);
1358 if (strncmp (tmp [0], reduced, appbaselen)) {
1361 tmp [i] = g_strdup ("");
1371 if (setup->private_bin_path_probe != NULL) {
1373 tmp [0] = g_strdup ("");
1376 domain->setup->path_changed = FALSE;
1378 g_strfreev (pvt_split);
1380 mono_domain_assemblies_unlock (domain);
1383 #ifdef DISABLE_SHADOW_COPY
1385 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1391 mono_make_shadow_copy (const char *filename, MonoError *error)
1393 mono_error_init (error);
1394 return (char *) filename;
1398 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1400 guint16 *orig, *dest;
1401 gboolean copy_result;
1404 strcpy (src + srclen - tail_len, extension);
1406 if (IS_PORTABILITY_CASE) {
1407 gchar *file = mono_portability_find_file (src, TRUE);
1413 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1417 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1419 strcpy (target + targetlen - tail_len, extension);
1420 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1422 mono_w32file_delete (dest);
1424 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1426 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1427 * overwritten when updated in their original locations. */
1429 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1438 get_cstring_hash (const char *str)
1444 if (!str || !str [0])
1449 for (i = 0; i < len; i++) {
1450 h = (h << 5) - h + *p;
1458 * Returned memory is malloc'd. Called must free it
1461 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1463 MonoAppDomainSetup *setup;
1464 char *cache_path, *appname;
1468 mono_error_init (error);
1470 setup = domain->setup;
1471 if (setup->cache_path != NULL && setup->application_name != NULL) {
1472 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1473 return_val_if_nok (error, NULL);
1475 #ifndef TARGET_WIN32
1478 for (i = strlen (cache_path) - 1; i >= 0; i--)
1479 if (cache_path [i] == '\\')
1480 cache_path [i] = '/';
1484 appname = mono_string_to_utf8_checked (setup->application_name, error);
1485 if (!mono_error_ok (error)) {
1486 g_free (cache_path);
1490 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1492 g_free (cache_path);
1494 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1495 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1502 get_shadow_assembly_location (const char *filename, MonoError *error)
1504 gint32 hash = 0, hash2 = 0;
1506 char path_hash [30];
1507 char *bname = g_path_get_basename (filename);
1508 char *dirname = g_path_get_dirname (filename);
1509 char *location, *tmploc;
1510 MonoDomain *domain = mono_domain_get ();
1512 mono_error_init (error);
1514 hash = get_cstring_hash (bname);
1515 hash2 = get_cstring_hash (dirname);
1516 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1517 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1518 tmploc = get_shadow_assembly_location_base (domain, error);
1519 if (!mono_error_ok (error)) {
1525 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1533 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1535 struct stat sbuf_dest;
1537 gchar *real_src = mono_portability_find_file (src, TRUE);
1540 stat_src = (gchar*)src;
1542 stat_src = real_src;
1544 if (stat (stat_src, sbuf_src) == -1) {
1545 time_t tnow = time (NULL);
1550 memset (sbuf_src, 0, sizeof (*sbuf_src));
1551 sbuf_src->st_mtime = tnow;
1552 sbuf_src->st_atime = tnow;
1559 if (stat (dest, &sbuf_dest) == -1)
1562 if (sbuf_src->st_size == sbuf_dest.st_size &&
1563 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1570 shadow_copy_create_ini (const char *shadow, const char *filename)
1580 dir_name = g_path_get_dirname (shadow);
1581 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1583 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1588 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1593 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1595 if (handle == INVALID_HANDLE_VALUE) {
1599 full_path = mono_path_resolve_symlinks (filename);
1600 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1602 mono_w32file_close (handle);
1607 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1610 MonoAppDomainSetup *setup;
1613 gchar **directories;
1614 gchar *shadow_status_string;
1616 gboolean shadow_enabled;
1617 gboolean found = FALSE;
1622 setup = domain->setup;
1623 if (setup == NULL || setup->shadow_copy_files == NULL)
1626 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1627 if (!mono_error_ok (&error)) {
1628 mono_error_cleanup (&error);
1631 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1632 g_free (shadow_status_string);
1634 if (!shadow_enabled)
1637 if (setup->shadow_copy_directories == NULL)
1640 /* Is dir_name a shadow_copy destination already? */
1641 base_dir = get_shadow_assembly_location_base (domain, &error);
1642 if (!mono_error_ok (&error)) {
1643 mono_error_cleanup (&error);
1647 if (strstr (dir_name, base_dir)) {
1653 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1654 if (!mono_error_ok (&error)) {
1655 mono_error_cleanup (&error);
1659 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1660 dir_ptr = directories;
1662 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1668 g_strfreev (directories);
1674 This function raises exceptions so it can cause as sorts of nasty stuff if called
1675 while holding a lock.
1676 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1677 or NULL if source file not found.
1678 FIXME bubble up the error instead of raising it here
1681 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1684 gchar *sibling_source, *sibling_target;
1685 gint sibling_source_len, sibling_target_len;
1686 guint16 *orig, *dest;
1689 gboolean copy_result;
1690 struct stat src_sbuf;
1691 struct utimbuf utbuf;
1692 char *dir_name = g_path_get_dirname (filename);
1693 MonoDomain *domain = mono_domain_get ();
1697 mono_error_init (oerror);
1699 set_domain_search_path (domain);
1701 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1703 return (char *) filename;
1706 /* Is dir_name a shadow_copy destination already? */
1707 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1708 if (!mono_error_ok (&error)) {
1709 mono_error_cleanup (&error);
1711 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1715 if (strstr (dir_name, shadow_dir)) {
1716 g_free (shadow_dir);
1718 return (char *) filename;
1720 g_free (shadow_dir);
1723 shadow = get_shadow_assembly_location (filename, &error);
1724 if (!mono_error_ok (&error)) {
1725 mono_error_cleanup (&error);
1726 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1730 if (g_ensure_directory_exists (shadow) == FALSE) {
1732 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1736 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1737 return (char*) shadow;
1739 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1740 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1741 mono_w32file_delete (dest);
1743 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1744 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1745 * and not have it runtime error" */
1746 attrs = mono_w32file_get_attributes (orig);
1747 if (attrs == INVALID_FILE_ATTRIBUTES) {
1749 return (char *)filename;
1752 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1754 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1755 * overwritten when updated in their original locations. */
1757 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1762 if (copy_result == FALSE) {
1765 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1766 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1767 return NULL; /* file not found, shadow copy failed */
1769 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1773 /* attempt to copy .mdb, .config if they exist */
1774 sibling_source = g_strconcat (filename, ".config", NULL);
1775 sibling_source_len = strlen (sibling_source);
1776 sibling_target = g_strconcat (shadow, ".config", NULL);
1777 sibling_target_len = strlen (sibling_target);
1779 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1781 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1783 g_free (sibling_source);
1784 g_free (sibling_target);
1788 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1792 /* Create a .ini file containing the original assembly location */
1793 if (!shadow_copy_create_ini (shadow, filename)) {
1795 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1799 utbuf.actime = src_sbuf.st_atime;
1800 utbuf.modtime = src_sbuf.st_mtime;
1801 utime (shadow, &utbuf);
1805 #endif /* DISABLE_SHADOW_COPY */
1808 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1810 if (appdomain == NULL)
1813 if (mono_object_is_transparent_proxy (&appdomain->mbr.obj)) {
1814 MonoTransparentProxy *tp = (MonoTransparentProxy*)appdomain;
1815 return mono_domain_get_by_id (tp->rp->target_domain_id);
1818 return appdomain->data;
1822 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1823 const gchar *path3, const gchar *path4,
1824 gboolean refonly, gboolean is_private)
1827 gboolean found = FALSE;
1830 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1832 if (IS_PORTABILITY_SET) {
1833 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1836 fullpath = new_fullpath;
1840 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1843 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1846 return (*assembly != NULL);
1849 static MonoAssembly *
1850 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1852 MonoAssembly *result = NULL;
1855 const gchar *local_culture;
1857 gboolean is_private = FALSE;
1859 if (!culture || *culture == '\0') {
1862 local_culture = culture;
1865 filename = g_strconcat (name, ".dll", NULL);
1866 len = strlen (filename);
1868 for (path = search_path; *path; path++) {
1869 if (**path == '\0') {
1871 continue; /* Ignore empty ApplicationBase */
1874 /* See test cases in bug #58992 and bug #57710 */
1875 /* 1st try: [culture]/[name].dll (culture may be empty) */
1876 strcpy (filename + len - 4, ".dll");
1877 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1880 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1881 strcpy (filename + len - 4, ".exe");
1882 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1885 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1886 strcpy (filename + len - 4, ".dll");
1887 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1890 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1891 strcpy (filename + len - 4, ".exe");
1892 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1901 * Try loading the assembly from ApplicationBase and PrivateBinPath
1902 * and then from assemblies_path if any.
1903 * LOCKING: This is called from the assembly loading code, which means the caller
1904 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1906 static MonoAssembly *
1907 mono_domain_assembly_preload (MonoAssemblyName *aname,
1908 gchar **assemblies_path,
1911 MonoDomain *domain = mono_domain_get ();
1912 MonoAssembly *result = NULL;
1913 gboolean refonly = GPOINTER_TO_UINT (user_data);
1915 set_domain_search_path (domain);
1917 if (domain->search_path && domain->search_path [0] != NULL) {
1918 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1921 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1922 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1929 * Check whenever a given assembly was already loaded in the current appdomain.
1931 static MonoAssembly *
1932 mono_domain_assembly_search (MonoAssemblyName *aname,
1935 MonoDomain *domain = mono_domain_get ();
1938 gboolean refonly = GPOINTER_TO_UINT (user_data);
1940 mono_domain_assemblies_lock (domain);
1941 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1942 ass = (MonoAssembly *)tmp->data;
1943 /* Dynamic assemblies can't match here in MS.NET */
1944 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1947 mono_domain_assemblies_unlock (domain);
1950 mono_domain_assemblies_unlock (domain);
1955 MonoReflectionAssemblyHandle
1956 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
1958 mono_error_init (error);
1959 MonoDomain *domain = mono_domain_get ();
1960 char *name, *filename;
1961 MonoImageOpenStatus status = MONO_IMAGE_OK;
1962 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
1967 if (fname == NULL) {
1968 mono_error_set_argument_null (error, "assemblyFile", "");
1972 name = filename = mono_string_handle_to_utf8 (fname, error);
1976 MonoAssembly *ass = mono_assembly_open_full (filename, &status, refOnly);
1979 if (status == MONO_IMAGE_IMAGE_INVALID)
1980 mono_error_set_bad_image_name (error, g_strdup (name), "");
1982 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
1986 result = mono_assembly_get_object_handle (domain, ass, error);
1993 MonoReflectionAssemblyHandle
1994 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
1995 MonoArrayHandle raw_assembly,
1996 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
1997 MonoBoolean refonly,
2000 mono_error_init (error);
2002 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2003 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2004 MonoImageOpenStatus status;
2005 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2007 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2008 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2009 if (!assembly_data) {
2010 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2014 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2015 memcpy (assembly_data, raw_data, raw_assembly_len);
2016 mono_gchandle_free (gchandle); /* unpin */
2017 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2019 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2022 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2026 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2027 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2028 uint32_t symbol_gchandle;
2029 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2030 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2031 mono_gchandle_free (symbol_gchandle);
2034 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2038 mono_image_close (image);
2039 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2043 refass = mono_assembly_get_object_handle (domain, ass, error);
2044 if (!MONO_HANDLE_IS_NULL(refass))
2045 MONO_HANDLE_SET (refass, evidence, evidence);
2049 MonoReflectionAssemblyHandle
2050 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2052 mono_error_init (error);
2053 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2054 MonoImageOpenStatus status = MONO_IMAGE_OK;
2056 MonoAssemblyName aname;
2062 name = mono_string_handle_to_utf8 (assRef, error);
2065 parsed = mono_assembly_name_parse (name, &aname);
2069 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2070 /* This is a parse error... */
2072 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2076 refass = mono_assembly_get_object_handle (domain, assm, error);
2084 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2085 mono_assembly_name_free (&aname);
2088 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2090 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2099 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2103 MONO_HANDLE_SET (refass, evidence, evidence);
2107 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2111 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2113 MonoException *exc = NULL;
2114 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2116 if (NULL == domain) {
2117 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2118 mono_set_pending_exception (exc);
2122 if (domain == mono_get_root_domain ()) {
2123 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2128 * Unloading seems to cause problems when running NUnit/NAnt, hence
2131 if (g_getenv ("MONO_NO_UNLOAD"))
2133 #ifdef __native_client__
2137 mono_domain_try_unload (domain, (MonoObject**)&exc);
2139 mono_set_pending_exception (exc);
2143 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2145 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2150 return mono_domain_is_unloading (domain);
2154 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2156 mono_unhandled_exception ((MonoObject*) exc);
2160 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2161 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2164 mono_error_init (error);
2168 g_assert (!MONO_HANDLE_IS_NULL (refass));
2169 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2170 image = assembly->image;
2173 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2176 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2178 if (MONO_HANDLE_IS_NULL (args)) {
2179 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2180 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2181 mono_error_assert_ok (error);
2184 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2189 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2191 return ad->data->domain_id;
2195 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2197 MonoDomain *old_domain = mono_domain_get();
2199 if (!mono_domain_set (ad->data, FALSE)) {
2200 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2204 return old_domain->domain;
2208 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2210 MonoDomain *current_domain = mono_domain_get ();
2211 MonoDomain *domain = mono_domain_get_by_id (domainid);
2213 if (!domain || !mono_domain_set (domain, FALSE)) {
2214 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2218 return current_domain->domain;
2222 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2224 mono_thread_push_appdomain_ref (ad->data);
2228 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2230 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2234 * Raise an exception to prevent the managed code from executing a pop
2237 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2241 mono_thread_push_appdomain_ref (domain);
2245 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2247 mono_thread_pop_appdomain_ref ();
2251 ves_icall_System_AppDomain_InternalGetContext ()
2253 return mono_context_get ();
2257 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2259 return mono_domain_get ()->default_context;
2263 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2265 MonoAppContext *old_context = mono_context_get ();
2267 mono_context_set (mc);
2273 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2275 MonoDomain* mono_root_domain = mono_get_root_domain ();
2276 mono_domain_lock (mono_root_domain);
2277 if (process_guid_set) {
2278 mono_domain_unlock (mono_root_domain);
2280 MonoString *res = NULL;
2281 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2282 mono_error_set_pending_exception (&error);
2285 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2286 process_guid_set = TRUE;
2287 mono_domain_unlock (mono_root_domain);
2292 mono_domain_is_unloading (MonoDomain *domain)
2294 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2301 clear_cached_vtable (MonoVTable *vtable)
2303 MonoClass *klass = vtable->klass;
2304 MonoDomain *domain = vtable->domain;
2305 MonoClassRuntimeInfo *runtime_info;
2308 runtime_info = klass->runtime_info;
2309 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2310 runtime_info->domain_vtables [domain->domain_id] = NULL;
2311 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2312 mono_gc_free_fixed (data);
2315 static G_GNUC_UNUSED void
2316 zero_static_data (MonoVTable *vtable)
2318 MonoClass *klass = vtable->klass;
2321 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2322 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2325 typedef struct unload_data {
2328 char *failure_reason;
2333 unload_data_unref (unload_data *data)
2337 mono_atomic_load_acquire (count, gint32, &data->refcount);
2338 g_assert (count >= 1 && count <= 2);
2343 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2347 deregister_reflection_info_roots_from_list (MonoImage *image)
2349 GSList *list = image->reflection_info_unregister_classes;
2352 MonoClass *klass = (MonoClass *)list->data;
2354 mono_class_free_ref_info (klass);
2359 image->reflection_info_unregister_classes = NULL;
2363 deregister_reflection_info_roots (MonoDomain *domain)
2367 mono_domain_assemblies_lock (domain);
2368 for (list = domain->domain_assemblies; list; list = list->next) {
2369 MonoAssembly *assembly = (MonoAssembly *)list->data;
2370 MonoImage *image = assembly->image;
2374 * No need to take the image lock here since dynamic images are appdomain bound and
2375 * at this point the mutator is gone. Taking the image lock here would mean
2376 * promoting it from a simple lock to a complex lock, which we better avoid if
2379 if (image_is_dynamic (image))
2380 deregister_reflection_info_roots_from_list (image);
2382 for (i = 0; i < image->module_count; ++i) {
2383 MonoImage *module = image->modules [i];
2384 if (module && image_is_dynamic (module))
2385 deregister_reflection_info_roots_from_list (module);
2388 mono_domain_assemblies_unlock (domain);
2392 unload_thread_main (void *arg)
2395 unload_data *data = (unload_data*)arg;
2396 MonoDomain *domain = data->domain;
2400 /* Have to attach to the runtime so shutdown can wait for this thread */
2401 /* Force it to be attached to avoid racing during shutdown. */
2402 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2404 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2405 if (!is_ok (&error)) {
2406 data->failure_reason = g_strdup (mono_error_get_message (&error));
2407 mono_error_cleanup (&error);
2412 * FIXME: Abort our parent thread last, so we can return a failure
2413 * indication if aborting times out.
2415 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2416 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2420 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2421 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2425 /* Finalize all finalizable objects in the doomed appdomain */
2426 if (!mono_domain_finalize (domain, -1)) {
2427 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2431 /* Clear references to our vtables in class->runtime_info.
2432 * We also hold the loader lock because we're going to change
2433 * class->runtime_info.
2436 mono_loader_lock (); //FIXME why do we need the loader lock here?
2437 mono_domain_lock (domain);
2440 * We need to make sure that we don't have any remsets
2441 * pointing into static data of the to-be-freed domain because
2442 * at the next collections they would be invalid. So what we
2443 * do is we first zero all static data and then do a minor
2444 * collection. Because all references in the static data will
2445 * now be null we won't do any unnecessary copies and after
2446 * the collection there won't be any more remsets.
2448 for (i = 0; i < domain->class_vtable_array->len; ++i)
2449 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2450 mono_gc_collect (0);
2452 for (i = 0; i < domain->class_vtable_array->len; ++i)
2453 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2454 deregister_reflection_info_roots (domain);
2456 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2458 mono_domain_unlock (domain);
2459 mono_loader_unlock ();
2461 mono_threads_clear_cached_culture (domain);
2463 domain->state = MONO_APPDOMAIN_UNLOADED;
2465 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2467 /* remove from the handle table the items related to this domain */
2468 mono_gchandle_free_domain (domain);
2470 mono_domain_free (domain, FALSE);
2472 mono_gc_collect (mono_gc_max_generation ());
2474 mono_atomic_store_release (&data->done, TRUE);
2475 unload_data_unref (data);
2476 mono_thread_detach (thread);
2480 mono_atomic_store_release (&data->done, TRUE);
2481 unload_data_unref (data);
2482 mono_thread_detach (thread);
2487 * mono_domain_unload:
2488 * @domain: The domain to unload
2490 * Unloads an appdomain. Follows the process outlined in the comment
2491 * for mono_domain_try_unload.
2494 mono_domain_unload (MonoDomain *domain)
2496 MonoObject *exc = NULL;
2497 mono_domain_try_unload (domain, &exc);
2500 static MonoThreadInfoWaitRet
2501 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2503 MonoThreadInfoWaitRet result;
2506 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2513 * mono_domain_unload:
2514 * @domain: The domain to unload
2515 * @exc: Exception information
2517 * Unloads an appdomain. Follows the process outlined in:
2518 * http://blogs.gotdotnet.com/cbrumme
2520 * If doing things the 'right' way is too hard or complex, we do it the
2521 * 'simple' way, which means do everything needed to avoid crashes and
2522 * memory leaks, but not much else.
2524 * It is required to pass a valid reference to the exc argument, upon return
2525 * from this function *exc will be set to the exception thrown, if any.
2527 * If this method is not called from an icall (embedded scenario for instance),
2528 * it must not be called with any managed frames on the stack, since the unload
2529 * process could end up trying to abort the current thread.
2532 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2535 MonoThreadHandle *thread_handle;
2536 MonoAppDomainState prev_state;
2538 unload_data *thread_data;
2539 MonoNativeThreadId tid;
2540 MonoDomain *caller_domain = mono_domain_get ();
2542 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2544 /* Atomically change our state to UNLOADING */
2545 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2546 MONO_APPDOMAIN_UNLOADING_START,
2547 MONO_APPDOMAIN_CREATED);
2548 if (prev_state != MONO_APPDOMAIN_CREATED) {
2549 switch (prev_state) {
2550 case MONO_APPDOMAIN_UNLOADING_START:
2551 case MONO_APPDOMAIN_UNLOADING:
2552 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2554 case MONO_APPDOMAIN_UNLOADED:
2555 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2558 g_warning ("Invalid appdomain state %d", prev_state);
2559 g_assert_not_reached ();
2563 mono_domain_set (domain, FALSE);
2564 /* Notify OnDomainUnload listeners */
2565 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2568 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2570 if (!mono_error_ok (&error)) {
2572 mono_error_cleanup (&error);
2574 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2578 /* Roll back the state change */
2579 domain->state = MONO_APPDOMAIN_CREATED;
2580 mono_domain_set (caller_domain, FALSE);
2583 mono_domain_set (caller_domain, FALSE);
2585 thread_data = g_new0 (unload_data, 1);
2586 thread_data->domain = domain;
2587 thread_data->failure_reason = NULL;
2588 thread_data->done = FALSE;
2589 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2591 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2592 domain->state = MONO_APPDOMAIN_UNLOADING;
2594 * First we create a separate thread for unloading, since
2595 * we might have to abort some threads, including the current one.
2597 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2598 if (thread_handle == NULL)
2601 /* Wait for the thread */
2602 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2603 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2604 /* The unload thread tries to abort us */
2605 /* The icall wrapper will execute the abort */
2606 mono_threads_close_thread_handle (thread_handle);
2607 unload_data_unref (thread_data);
2612 mono_threads_close_thread_handle (thread_handle);
2614 if (thread_data->failure_reason) {
2615 /* Roll back the state change */
2616 domain->state = MONO_APPDOMAIN_CREATED;
2618 g_warning ("%s", thread_data->failure_reason);
2620 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2622 g_free (thread_data->failure_reason);
2623 thread_data->failure_reason = NULL;
2626 unload_data_unref (thread_data);