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/file-io.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;
1402 strcpy (src + srclen - tail_len, extension);
1404 if (IS_PORTABILITY_CASE) {
1405 gchar *file = mono_portability_find_file (src, TRUE);
1411 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1415 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1417 strcpy (target + targetlen - tail_len, extension);
1418 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1422 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1423 copy_result = CopyFile (orig, dest, FALSE);
1425 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1428 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1429 * overwritten when updated in their original locations. */
1431 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1440 get_cstring_hash (const char *str)
1446 if (!str || !str [0])
1451 for (i = 0; i < len; i++) {
1452 h = (h << 5) - h + *p;
1460 * Returned memory is malloc'd. Called must free it
1463 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1465 MonoAppDomainSetup *setup;
1466 char *cache_path, *appname;
1470 mono_error_init (error);
1472 setup = domain->setup;
1473 if (setup->cache_path != NULL && setup->application_name != NULL) {
1474 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1475 return_val_if_nok (error, NULL);
1477 #ifndef TARGET_WIN32
1480 for (i = strlen (cache_path) - 1; i >= 0; i--)
1481 if (cache_path [i] == '\\')
1482 cache_path [i] = '/';
1486 appname = mono_string_to_utf8_checked (setup->application_name, error);
1487 if (!mono_error_ok (error)) {
1488 g_free (cache_path);
1492 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1494 g_free (cache_path);
1496 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1497 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1504 get_shadow_assembly_location (const char *filename, MonoError *error)
1506 gint32 hash = 0, hash2 = 0;
1508 char path_hash [30];
1509 char *bname = g_path_get_basename (filename);
1510 char *dirname = g_path_get_dirname (filename);
1511 char *location, *tmploc;
1512 MonoDomain *domain = mono_domain_get ();
1514 mono_error_init (error);
1516 hash = get_cstring_hash (bname);
1517 hash2 = get_cstring_hash (dirname);
1518 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1519 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1520 tmploc = get_shadow_assembly_location_base (domain, error);
1521 if (!mono_error_ok (error)) {
1527 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1535 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1537 struct stat sbuf_dest;
1539 gchar *real_src = mono_portability_find_file (src, TRUE);
1542 stat_src = (gchar*)src;
1544 stat_src = real_src;
1546 if (stat (stat_src, sbuf_src) == -1) {
1547 time_t tnow = time (NULL);
1552 memset (sbuf_src, 0, sizeof (*sbuf_src));
1553 sbuf_src->st_mtime = tnow;
1554 sbuf_src->st_atime = tnow;
1561 if (stat (dest, &sbuf_dest) == -1)
1564 if (sbuf_src->st_size == sbuf_dest.st_size &&
1565 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1572 shadow_copy_create_ini (const char *shadow, const char *filename)
1582 dir_name = g_path_get_dirname (shadow);
1583 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1585 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1590 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1595 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1596 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1598 if (handle == INVALID_HANDLE_VALUE) {
1602 full_path = mono_path_resolve_symlinks (filename);
1603 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1605 CloseHandle (handle);
1610 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1613 MonoAppDomainSetup *setup;
1616 gchar **directories;
1617 gchar *shadow_status_string;
1619 gboolean shadow_enabled;
1620 gboolean found = FALSE;
1625 setup = domain->setup;
1626 if (setup == NULL || setup->shadow_copy_files == NULL)
1629 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1630 if (!mono_error_ok (&error)) {
1631 mono_error_cleanup (&error);
1634 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1635 g_free (shadow_status_string);
1637 if (!shadow_enabled)
1640 if (setup->shadow_copy_directories == NULL)
1643 /* Is dir_name a shadow_copy destination already? */
1644 base_dir = get_shadow_assembly_location_base (domain, &error);
1645 if (!mono_error_ok (&error)) {
1646 mono_error_cleanup (&error);
1650 if (strstr (dir_name, base_dir)) {
1656 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1657 if (!mono_error_ok (&error)) {
1658 mono_error_cleanup (&error);
1662 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1663 dir_ptr = directories;
1665 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1671 g_strfreev (directories);
1677 This function raises exceptions so it can cause as sorts of nasty stuff if called
1678 while holding a lock.
1679 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1680 or NULL if source file not found.
1681 FIXME bubble up the error instead of raising it here
1684 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1687 gchar *sibling_source, *sibling_target;
1688 gint sibling_source_len, sibling_target_len;
1689 guint16 *orig, *dest;
1692 gboolean copy_result;
1693 struct stat src_sbuf;
1694 struct utimbuf utbuf;
1695 char *dir_name = g_path_get_dirname (filename);
1696 MonoDomain *domain = mono_domain_get ();
1699 mono_error_init (oerror);
1701 set_domain_search_path (domain);
1703 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1705 return (char *) filename;
1708 /* Is dir_name a shadow_copy destination already? */
1709 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1710 if (!mono_error_ok (&error)) {
1711 mono_error_cleanup (&error);
1713 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1717 if (strstr (dir_name, shadow_dir)) {
1718 g_free (shadow_dir);
1720 return (char *) filename;
1722 g_free (shadow_dir);
1725 shadow = get_shadow_assembly_location (filename, &error);
1726 if (!mono_error_ok (&error)) {
1727 mono_error_cleanup (&error);
1728 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1732 if (g_ensure_directory_exists (shadow) == FALSE) {
1734 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1738 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1739 return (char*) shadow;
1741 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1742 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1745 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1746 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1747 * and not have it runtime error" */
1748 attrs = GetFileAttributes (orig);
1749 if (attrs == INVALID_FILE_ATTRIBUTES) {
1751 return (char *)filename;
1754 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1755 copy_result = CopyFile (orig, dest, FALSE);
1757 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1760 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1761 * overwritten when updated in their original locations. */
1763 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1768 if (copy_result == FALSE) {
1771 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1772 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1773 return NULL; /* file not found, shadow copy failed */
1775 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1779 /* attempt to copy .mdb, .config if they exist */
1780 sibling_source = g_strconcat (filename, ".config", NULL);
1781 sibling_source_len = strlen (sibling_source);
1782 sibling_target = g_strconcat (shadow, ".config", NULL);
1783 sibling_target_len = strlen (sibling_target);
1785 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1787 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1789 g_free (sibling_source);
1790 g_free (sibling_target);
1794 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1798 /* Create a .ini file containing the original assembly location */
1799 if (!shadow_copy_create_ini (shadow, filename)) {
1801 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1805 utbuf.actime = src_sbuf.st_atime;
1806 utbuf.modtime = src_sbuf.st_mtime;
1807 utime (shadow, &utbuf);
1811 #endif /* DISABLE_SHADOW_COPY */
1814 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1816 if (appdomain == NULL)
1819 if (mono_object_is_transparent_proxy (&appdomain->mbr.obj)) {
1820 MonoTransparentProxy *tp = (MonoTransparentProxy*)appdomain;
1821 return mono_domain_get_by_id (tp->rp->target_domain_id);
1824 return appdomain->data;
1828 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1829 const gchar *path3, const gchar *path4,
1830 gboolean refonly, gboolean is_private)
1833 gboolean found = FALSE;
1836 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1838 if (IS_PORTABILITY_SET) {
1839 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1842 fullpath = new_fullpath;
1846 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1849 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1852 return (*assembly != NULL);
1855 static MonoAssembly *
1856 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1858 MonoAssembly *result = NULL;
1861 const gchar *local_culture;
1863 gboolean is_private = FALSE;
1865 if (!culture || *culture == '\0') {
1868 local_culture = culture;
1871 filename = g_strconcat (name, ".dll", NULL);
1872 len = strlen (filename);
1874 for (path = search_path; *path; path++) {
1875 if (**path == '\0') {
1877 continue; /* Ignore empty ApplicationBase */
1880 /* See test cases in bug #58992 and bug #57710 */
1881 /* 1st try: [culture]/[name].dll (culture may be empty) */
1882 strcpy (filename + len - 4, ".dll");
1883 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1886 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1887 strcpy (filename + len - 4, ".exe");
1888 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1891 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1892 strcpy (filename + len - 4, ".dll");
1893 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1896 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1897 strcpy (filename + len - 4, ".exe");
1898 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1907 * Try loading the assembly from ApplicationBase and PrivateBinPath
1908 * and then from assemblies_path if any.
1909 * LOCKING: This is called from the assembly loading code, which means the caller
1910 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1912 static MonoAssembly *
1913 mono_domain_assembly_preload (MonoAssemblyName *aname,
1914 gchar **assemblies_path,
1917 MonoDomain *domain = mono_domain_get ();
1918 MonoAssembly *result = NULL;
1919 gboolean refonly = GPOINTER_TO_UINT (user_data);
1921 set_domain_search_path (domain);
1923 if (domain->search_path && domain->search_path [0] != NULL) {
1924 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1927 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1928 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1935 * Check whenever a given assembly was already loaded in the current appdomain.
1937 static MonoAssembly *
1938 mono_domain_assembly_search (MonoAssemblyName *aname,
1941 MonoDomain *domain = mono_domain_get ();
1944 gboolean refonly = GPOINTER_TO_UINT (user_data);
1946 mono_domain_assemblies_lock (domain);
1947 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1948 ass = (MonoAssembly *)tmp->data;
1949 /* Dynamic assemblies can't match here in MS.NET */
1950 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1953 mono_domain_assemblies_unlock (domain);
1956 mono_domain_assemblies_unlock (domain);
1961 MonoReflectionAssemblyHandle
1962 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
1964 mono_error_init (error);
1965 MonoDomain *domain = mono_domain_get ();
1966 char *name, *filename;
1967 MonoImageOpenStatus status = MONO_IMAGE_OK;
1968 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
1973 if (fname == NULL) {
1974 mono_error_set_argument_null (error, "assemblyFile", "");
1978 name = filename = mono_string_handle_to_utf8 (fname, error);
1982 MonoAssembly *ass = mono_assembly_open_full (filename, &status, refOnly);
1985 if (status == MONO_IMAGE_IMAGE_INVALID)
1986 mono_error_set_bad_image_name (error, g_strdup (name), "");
1988 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
1992 result = mono_assembly_get_object_handle (domain, ass, error);
1999 MonoReflectionAssemblyHandle
2000 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2001 MonoArrayHandle raw_assembly,
2002 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2003 MonoBoolean refonly,
2006 mono_error_init (error);
2008 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2009 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2010 MonoImageOpenStatus status;
2011 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2013 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2014 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2015 if (!assembly_data) {
2016 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2020 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2021 memcpy (assembly_data, raw_data, raw_assembly_len);
2022 mono_gchandle_free (gchandle); /* unpin */
2023 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2025 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2028 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2032 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2033 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2034 uint32_t symbol_gchandle;
2035 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2036 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2037 mono_gchandle_free (symbol_gchandle);
2040 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2044 mono_image_close (image);
2045 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2049 refass = mono_assembly_get_object_handle (domain, ass, error);
2050 if (!MONO_HANDLE_IS_NULL(refass))
2051 MONO_HANDLE_SET (refass, evidence, evidence);
2055 MonoReflectionAssemblyHandle
2056 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2058 mono_error_init (error);
2059 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2060 MonoImageOpenStatus status = MONO_IMAGE_OK;
2062 MonoAssemblyName aname;
2068 name = mono_string_handle_to_utf8 (assRef, error);
2071 parsed = mono_assembly_name_parse (name, &aname);
2075 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2076 /* This is a parse error... */
2078 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2082 refass = mono_assembly_get_object_handle (domain, assm, error);
2090 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2091 mono_assembly_name_free (&aname);
2094 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2096 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2105 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2109 MONO_HANDLE_SET (refass, evidence, evidence);
2113 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2117 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2119 MonoException *exc = NULL;
2120 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2122 if (NULL == domain) {
2123 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2124 mono_set_pending_exception (exc);
2128 if (domain == mono_get_root_domain ()) {
2129 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2134 * Unloading seems to cause problems when running NUnit/NAnt, hence
2137 if (g_getenv ("MONO_NO_UNLOAD"))
2139 #ifdef __native_client__
2143 mono_domain_try_unload (domain, (MonoObject**)&exc);
2145 mono_set_pending_exception (exc);
2149 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2151 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2156 return mono_domain_is_unloading (domain);
2160 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2162 mono_unhandled_exception ((MonoObject*) exc);
2166 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2167 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2170 mono_error_init (error);
2174 g_assert (!MONO_HANDLE_IS_NULL (refass));
2175 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2176 image = assembly->image;
2179 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2182 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2184 if (MONO_HANDLE_IS_NULL (args)) {
2185 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2186 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2187 mono_error_assert_ok (error);
2190 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2195 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2197 return ad->data->domain_id;
2201 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2203 MonoDomain *old_domain = mono_domain_get();
2205 if (!mono_domain_set (ad->data, FALSE)) {
2206 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2210 return old_domain->domain;
2214 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2216 MonoDomain *current_domain = mono_domain_get ();
2217 MonoDomain *domain = mono_domain_get_by_id (domainid);
2219 if (!domain || !mono_domain_set (domain, FALSE)) {
2220 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2224 return current_domain->domain;
2228 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2230 mono_thread_push_appdomain_ref (ad->data);
2234 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2236 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2240 * Raise an exception to prevent the managed code from executing a pop
2243 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2247 mono_thread_push_appdomain_ref (domain);
2251 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2253 mono_thread_pop_appdomain_ref ();
2257 ves_icall_System_AppDomain_InternalGetContext ()
2259 return mono_context_get ();
2263 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2265 return mono_domain_get ()->default_context;
2269 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2271 MonoAppContext *old_context = mono_context_get ();
2273 mono_context_set (mc);
2279 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2281 MonoDomain* mono_root_domain = mono_get_root_domain ();
2282 mono_domain_lock (mono_root_domain);
2283 if (process_guid_set) {
2284 mono_domain_unlock (mono_root_domain);
2286 MonoString *res = NULL;
2287 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2288 mono_error_set_pending_exception (&error);
2291 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2292 process_guid_set = TRUE;
2293 mono_domain_unlock (mono_root_domain);
2298 mono_domain_is_unloading (MonoDomain *domain)
2300 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2307 clear_cached_vtable (MonoVTable *vtable)
2309 MonoClass *klass = vtable->klass;
2310 MonoDomain *domain = vtable->domain;
2311 MonoClassRuntimeInfo *runtime_info;
2314 runtime_info = klass->runtime_info;
2315 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2316 runtime_info->domain_vtables [domain->domain_id] = NULL;
2317 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2318 mono_gc_free_fixed (data);
2321 static G_GNUC_UNUSED void
2322 zero_static_data (MonoVTable *vtable)
2324 MonoClass *klass = vtable->klass;
2327 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2328 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2331 typedef struct unload_data {
2334 char *failure_reason;
2339 unload_data_unref (unload_data *data)
2343 mono_atomic_load_acquire (count, gint32, &data->refcount);
2344 g_assert (count >= 1 && count <= 2);
2349 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2353 deregister_reflection_info_roots_from_list (MonoImage *image)
2355 GSList *list = image->reflection_info_unregister_classes;
2358 MonoClass *klass = (MonoClass *)list->data;
2360 mono_class_free_ref_info (klass);
2365 image->reflection_info_unregister_classes = NULL;
2369 deregister_reflection_info_roots (MonoDomain *domain)
2373 mono_domain_assemblies_lock (domain);
2374 for (list = domain->domain_assemblies; list; list = list->next) {
2375 MonoAssembly *assembly = (MonoAssembly *)list->data;
2376 MonoImage *image = assembly->image;
2380 * No need to take the image lock here since dynamic images are appdomain bound and
2381 * at this point the mutator is gone. Taking the image lock here would mean
2382 * promoting it from a simple lock to a complex lock, which we better avoid if
2385 if (image_is_dynamic (image))
2386 deregister_reflection_info_roots_from_list (image);
2388 for (i = 0; i < image->module_count; ++i) {
2389 MonoImage *module = image->modules [i];
2390 if (module && image_is_dynamic (module))
2391 deregister_reflection_info_roots_from_list (module);
2394 mono_domain_assemblies_unlock (domain);
2398 unload_thread_main (void *arg)
2401 unload_data *data = (unload_data*)arg;
2402 MonoDomain *domain = data->domain;
2406 /* Have to attach to the runtime so shutdown can wait for this thread */
2407 /* Force it to be attached to avoid racing during shutdown. */
2408 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2410 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2411 if (!is_ok (&error)) {
2412 data->failure_reason = g_strdup (mono_error_get_message (&error));
2413 mono_error_cleanup (&error);
2418 * FIXME: Abort our parent thread last, so we can return a failure
2419 * indication if aborting times out.
2421 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2422 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2426 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2427 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2431 /* Finalize all finalizable objects in the doomed appdomain */
2432 if (!mono_domain_finalize (domain, -1)) {
2433 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2437 /* Clear references to our vtables in class->runtime_info.
2438 * We also hold the loader lock because we're going to change
2439 * class->runtime_info.
2442 mono_loader_lock (); //FIXME why do we need the loader lock here?
2443 mono_domain_lock (domain);
2446 * We need to make sure that we don't have any remsets
2447 * pointing into static data of the to-be-freed domain because
2448 * at the next collections they would be invalid. So what we
2449 * do is we first zero all static data and then do a minor
2450 * collection. Because all references in the static data will
2451 * now be null we won't do any unnecessary copies and after
2452 * the collection there won't be any more remsets.
2454 for (i = 0; i < domain->class_vtable_array->len; ++i)
2455 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2456 mono_gc_collect (0);
2458 for (i = 0; i < domain->class_vtable_array->len; ++i)
2459 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2460 deregister_reflection_info_roots (domain);
2462 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2464 mono_domain_unlock (domain);
2465 mono_loader_unlock ();
2467 mono_threads_clear_cached_culture (domain);
2469 domain->state = MONO_APPDOMAIN_UNLOADED;
2471 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2473 /* remove from the handle table the items related to this domain */
2474 mono_gchandle_free_domain (domain);
2476 mono_domain_free (domain, FALSE);
2478 mono_gc_collect (mono_gc_max_generation ());
2480 mono_atomic_store_release (&data->done, TRUE);
2481 unload_data_unref (data);
2482 mono_thread_detach (thread);
2486 mono_atomic_store_release (&data->done, TRUE);
2487 unload_data_unref (data);
2488 mono_thread_detach (thread);
2493 * mono_domain_unload:
2494 * @domain: The domain to unload
2496 * Unloads an appdomain. Follows the process outlined in the comment
2497 * for mono_domain_try_unload.
2500 mono_domain_unload (MonoDomain *domain)
2502 MonoObject *exc = NULL;
2503 mono_domain_try_unload (domain, &exc);
2506 static MonoThreadInfoWaitRet
2507 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2509 MonoThreadInfoWaitRet result;
2512 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2519 * mono_domain_unload:
2520 * @domain: The domain to unload
2521 * @exc: Exception information
2523 * Unloads an appdomain. Follows the process outlined in:
2524 * http://blogs.gotdotnet.com/cbrumme
2526 * If doing things the 'right' way is too hard or complex, we do it the
2527 * 'simple' way, which means do everything needed to avoid crashes and
2528 * memory leaks, but not much else.
2530 * It is required to pass a valid reference to the exc argument, upon return
2531 * from this function *exc will be set to the exception thrown, if any.
2533 * If this method is not called from an icall (embedded scenario for instance),
2534 * it must not be called with any managed frames on the stack, since the unload
2535 * process could end up trying to abort the current thread.
2538 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2541 MonoThreadHandle *thread_handle;
2542 MonoAppDomainState prev_state;
2544 unload_data *thread_data;
2545 MonoNativeThreadId tid;
2546 MonoDomain *caller_domain = mono_domain_get ();
2548 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2550 /* Atomically change our state to UNLOADING */
2551 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2552 MONO_APPDOMAIN_UNLOADING_START,
2553 MONO_APPDOMAIN_CREATED);
2554 if (prev_state != MONO_APPDOMAIN_CREATED) {
2555 switch (prev_state) {
2556 case MONO_APPDOMAIN_UNLOADING_START:
2557 case MONO_APPDOMAIN_UNLOADING:
2558 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2560 case MONO_APPDOMAIN_UNLOADED:
2561 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2564 g_warning ("Invalid appdomain state %d", prev_state);
2565 g_assert_not_reached ();
2569 mono_domain_set (domain, FALSE);
2570 /* Notify OnDomainUnload listeners */
2571 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2574 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2576 if (!mono_error_ok (&error)) {
2578 mono_error_cleanup (&error);
2580 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2584 /* Roll back the state change */
2585 domain->state = MONO_APPDOMAIN_CREATED;
2586 mono_domain_set (caller_domain, FALSE);
2589 mono_domain_set (caller_domain, FALSE);
2591 thread_data = g_new0 (unload_data, 1);
2592 thread_data->domain = domain;
2593 thread_data->failure_reason = NULL;
2594 thread_data->done = FALSE;
2595 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2597 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2598 domain->state = MONO_APPDOMAIN_UNLOADING;
2600 * First we create a separate thread for unloading, since
2601 * we might have to abort some threads, including the current one.
2603 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2604 if (thread_handle == NULL)
2607 /* Wait for the thread */
2608 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2609 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2610 /* The unload thread tries to abort us */
2611 /* The icall wrapper will execute the abort */
2612 mono_threads_close_thread_handle (thread_handle);
2613 unload_data_unref (thread_data);
2618 mono_threads_close_thread_handle (thread_handle);
2620 if (thread_data->failure_reason) {
2621 /* Roll back the state change */
2622 domain->state = MONO_APPDOMAIN_CREATED;
2624 g_warning ("%s", thread_data->failure_reason);
2626 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2628 g_free (thread_data->failure_reason);
2629 thread_data->failure_reason = NULL;
2632 unload_data_unref (thread_data);