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-ms.h>
46 #include <mono/metadata/socket-io.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/mono-debug-debugger.h>
54 #include <mono/metadata/attach.h>
55 #include <mono/metadata/file-io.h>
56 #include <mono/metadata/lock-tracer.h>
57 #include <mono/metadata/console-io.h>
58 #include <mono/metadata/threads-types.h>
59 #include <mono/metadata/tokentype.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/reflection-internals.h>
62 #include <mono/metadata/abi-details.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>
78 * This is the version number of the corlib-runtime interface. When
79 * making changes to this interface (by changing the layout
80 * of classes the runtime knows about, changing icall signature or
81 * semantics etc), increment this variable. Also increment the
82 * pair of this variable in mscorlib in:
83 * mcs/class/corlib/System/Environment.cs
85 * Changes which are already detected at runtime, like the addition
86 * of icalls, do not require an increment.
88 #define MONO_CORLIB_VERSION 164
93 int assemblybinding_count;
98 static gunichar2 process_guid [36];
99 static gboolean process_guid_set = FALSE;
101 static gboolean no_exec = FALSE;
103 static MonoAssembly *
104 mono_domain_assembly_preload (MonoAssemblyName *aname,
105 gchar **assemblies_path,
108 static MonoAssembly *
109 mono_domain_assembly_search (MonoAssemblyName *aname,
113 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
116 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
118 static MonoAppDomain *
119 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
122 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
124 static MonoLoadFunc load_function = NULL;
126 /* Lazy class loading functions */
127 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly);
129 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, System, AppDomain);
132 mono_install_runtime_load (MonoLoadFunc func)
134 load_function = func;
138 mono_runtime_load (const char *filename, const char *runtime_version)
140 g_assert (load_function);
141 return load_function (filename, runtime_version);
145 * mono_runtime_set_no_exec:
147 * Instructs the runtime to operate in static mode, i.e. avoid/do not
148 * allow managed code execution. This is useful for running the AOT
149 * compiler on platforms which allow full-aot execution only. This
150 * should be called before mono_runtime_init ().
153 mono_runtime_set_no_exec (gboolean val)
159 * mono_runtime_get_no_exec:
161 * If true, then the runtime will not allow managed code execution.
164 mono_runtime_get_no_exec (void)
170 create_domain_objects (MonoDomain *domain)
173 MonoDomain *old_domain = mono_domain_get ();
175 MonoVTable *string_vt;
176 MonoClassField *string_empty_fld;
178 if (domain != old_domain) {
179 mono_thread_push_appdomain_ref (domain);
180 mono_domain_set_internal_with_options (domain, FALSE);
184 * Initialize String.Empty. This enables the removal of
185 * the static cctor of the String class.
187 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
188 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
189 g_assert (string_empty_fld);
190 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
191 mono_error_assert_ok (&error);
192 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
193 domain->empty_string = empty_str;
196 * Create an instance early since we can't do it when there is no memory.
198 arg = mono_string_new (domain, "Out of memory");
199 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
200 mono_error_assert_ok (&error);
203 * These two are needed because the signal handlers might be executing on
204 * an alternate stack, and Boehm GC can't handle that.
206 arg = mono_string_new (domain, "A null value was found where an object instance was required");
207 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
208 mono_error_assert_ok (&error);
209 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
210 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
211 mono_error_assert_ok (&error);
213 /*The ephemeron tombstone i*/
214 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
215 mono_error_assert_ok (&error);
217 if (domain != old_domain) {
218 mono_thread_pop_appdomain_ref ();
219 mono_domain_set_internal_with_options (old_domain, FALSE);
223 * This class is used during exception handling, so initialize it here, to prevent
224 * stack overflows while handling stack overflows.
226 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
231 * @domain: domain returned by mono_init ()
233 * Initialize the core AppDomain: this function will run also some
234 * IL initialization code, so it needs the execution engine to be fully
237 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
238 * we know the entry_assembly.
242 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
245 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
246 mono_error_cleanup (&error);
250 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
252 MonoAppDomainSetup *setup;
256 mono_error_init (error);
258 mono_portability_helpers_init ();
260 mono_gc_base_init ();
261 mono_monitor_init ();
262 mono_marshal_init ();
264 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
265 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
266 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
267 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
268 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
269 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
270 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
272 mono_thread_init (start_cb, attach_cb);
274 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
275 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
276 return_if_nok (error);
278 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
280 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
281 return_if_nok (error);
285 domain->setup = setup;
287 mono_thread_attach (domain);
289 mono_type_initialization_init ();
291 if (!mono_runtime_get_no_exec ())
292 create_domain_objects (domain);
294 /* GC init has to happen after thread init */
297 /* contexts use GC handles, so they must be initialized after the GC */
298 mono_context_init_checked (domain, error);
299 return_if_nok (error);
300 mono_context_set (domain->default_context);
302 #ifndef DISABLE_SOCKETS
303 mono_network_init ();
306 mono_console_init ();
309 mono_locks_tracer_init ();
311 /* mscorlib is loaded before we install the load hook */
312 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
318 mono_get_corlib_version (void)
322 MonoClassField *field;
325 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
326 mono_class_init (klass);
327 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
330 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
332 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
333 mono_error_assert_ok (&error);
334 return *(gint32*)((gchar*)value + sizeof (MonoObject));
338 * mono_check_corlib_version
340 * Checks that the corlib that is loaded matches the version of this runtime.
342 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
343 * allocated string with the error otherwise.
346 mono_check_corlib_version (void)
348 int version = mono_get_corlib_version ();
349 if (version != MONO_CORLIB_VERSION)
350 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
352 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
353 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
354 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
355 if (native_offset != managed_offset)
356 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
363 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
365 * Initializes the @domain's default System.Runtime.Remoting's Context.
368 mono_context_init (MonoDomain *domain)
371 mono_context_init_checked (domain, &error);
372 mono_error_cleanup (&error);
376 mono_context_init_checked (MonoDomain *domain, MonoError *error)
379 MonoAppContext *context;
381 mono_error_init (error);
383 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
384 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
385 return_if_nok (error);
387 context->domain_id = domain->domain_id;
388 context->context_id = 0;
389 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
390 domain->default_context = context;
394 * mono_runtime_cleanup:
399 * This must not be called while there are still running threads executing
403 mono_runtime_cleanup (MonoDomain *domain)
405 mono_attach_cleanup ();
407 /* This ends up calling any pending pending (for at most 2 seconds) */
410 mono_thread_cleanup ();
412 #ifndef DISABLE_SOCKETS
413 mono_network_cleanup ();
415 mono_marshal_cleanup ();
417 mono_type_initialization_cleanup ();
419 mono_monitor_cleanup ();
422 static MonoDomainFunc quit_function = NULL;
425 mono_install_runtime_cleanup (MonoDomainFunc func)
427 quit_function = func;
433 if (quit_function != NULL)
434 quit_function (mono_get_root_domain (), NULL);
438 * mono_domain_create_appdomain:
439 * @friendly_name: The friendly name of the appdomain to create
440 * @configuration_file: The configuration file to initialize the appdomain with
442 * Returns a MonoDomain initialized with the appdomain
445 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
449 MonoAppDomainSetup *setup;
452 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
453 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
456 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
458 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
462 return mono_domain_from_appdomain (ad);
464 mono_error_cleanup (&error);
469 * mono_domain_set_config:
470 * @domain: MonoDomain initialized with the appdomain we want to change
471 * @base_dir: new base directory for the appdomain
472 * @config_file_name: path to the new configuration for the app domain
474 * Used to set the system configuration for an appdomain
476 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
477 * Error Initializing the configuration system. ---> System.ArgumentException:
478 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
481 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
483 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
484 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
487 static MonoAppDomainSetup*
488 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
490 MonoDomain *caller_domain;
491 MonoClass *ads_class;
492 MonoAppDomainSetup *copy;
494 mono_error_init (error);
496 caller_domain = mono_domain_get ();
497 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
499 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
500 return_val_if_nok (error, NULL);
502 mono_domain_set_internal (domain);
504 #define XCOPY_FIELD(dst,field,src,error) \
506 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
507 return_val_if_nok (error, NULL); \
508 MONO_OBJECT_SETREF ((dst),field,copied_val); \
511 XCOPY_FIELD (copy, application_base, setup->application_base, error);
512 XCOPY_FIELD (copy, application_name, setup->application_name, error);
513 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
514 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
515 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
516 XCOPY_FIELD (copy, license_file, setup->license_file, error);
517 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
518 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
519 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
520 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
521 copy->publisher_policy = setup->publisher_policy;
522 copy->path_changed = setup->path_changed;
523 copy->loader_optimization = setup->loader_optimization;
524 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
525 copy->disallow_code_downloads = setup->disallow_code_downloads;
526 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
527 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
528 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
529 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
530 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
534 mono_domain_set_internal (caller_domain);
539 static MonoAppDomain *
540 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
545 char *shadow_location;
547 mono_error_init (error);
549 adclass = mono_class_get_appdomain_class ();
551 /* FIXME: pin all those objects */
552 data = mono_domain_create();
554 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
555 return_val_if_nok (error, NULL);
558 data->friendly_name = g_strdup (friendly_name);
560 mono_profiler_appdomain_name (data, data->friendly_name);
562 if (!setup->application_base) {
563 /* Inherit from the root domain since MS.NET does this */
564 MonoDomain *root = mono_get_root_domain ();
565 if (root->setup->application_base) {
566 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
567 mono_error_assert_ok (error); /* FIXME don't swallow the error */
568 MONO_OBJECT_SETREF (setup, application_base, s);
572 mono_context_init_checked (data, error);
573 return_val_if_nok (error, NULL);
575 data->setup = copy_app_domain_setup (data, setup, error);
576 if (!mono_error_ok (error)) {
577 g_free (data->friendly_name);
581 mono_domain_set_options_from_config (data);
582 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
584 #ifndef DISABLE_SHADOW_COPY
585 /*FIXME, guard this for when the debugger is not running */
586 shadow_location = get_shadow_assembly_location_base (data, error);
587 if (!mono_error_ok (error)) {
588 g_free (data->friendly_name);
592 g_free (shadow_location);
595 create_domain_objects (data);
601 * mono_domain_has_type_resolve:
602 * @domain: application domains being looked up
604 * Returns: TRUE if the AppDomain.TypeResolve field has been
608 mono_domain_has_type_resolve (MonoDomain *domain)
610 static MonoClassField *field = NULL;
614 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
618 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
622 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
627 * mono_domain_try_type_resolve:
628 * @domain: application domainwhere the name where the type is going to be resolved
629 * @name: the name of the type to resolve or NULL.
630 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
632 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
633 * the assembly that matches name.
635 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
637 * Returns: A MonoReflectionAssembly or NULL if not found
639 MonoReflectionAssembly *
640 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
643 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
644 mono_error_cleanup (&error);
649 MonoReflectionAssembly *
650 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
652 static MonoMethod *method = NULL;
653 MonoReflectionAssembly *ret;
656 mono_error_init (error);
658 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
660 if (method == NULL) {
661 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
662 if (method == NULL) {
663 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
669 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
673 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
674 return_val_if_nok (error, NULL);
680 * mono_domain_owns_vtable_slot:
682 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
685 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
689 mono_domain_lock (domain);
690 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
691 mono_domain_unlock (domain);
698 * @force: force setting.
700 * Set the current appdomain to @domain. If @force is set, set it even
701 * if it is being unloaded.
705 * FALSE if the domain is unloaded
708 mono_domain_set (MonoDomain *domain, gboolean force)
710 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
713 mono_domain_set_internal (domain);
719 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
726 MONO_CHECK_ARG_NULL (name, NULL);
732 str = mono_string_to_utf8_checked (name, &error);
733 if (mono_error_set_pending_exception (&error))
736 mono_domain_lock (add);
738 if (!strcmp (str, "APPBASE"))
739 o = (MonoObject *)add->setup->application_base;
740 else if (!strcmp (str, "APP_CONFIG_FILE"))
741 o = (MonoObject *)add->setup->configuration_file;
742 else if (!strcmp (str, "DYNAMIC_BASE"))
743 o = (MonoObject *)add->setup->dynamic_base;
744 else if (!strcmp (str, "APP_NAME"))
745 o = (MonoObject *)add->setup->application_name;
746 else if (!strcmp (str, "CACHE_BASE"))
747 o = (MonoObject *)add->setup->cache_path;
748 else if (!strcmp (str, "PRIVATE_BINPATH"))
749 o = (MonoObject *)add->setup->private_bin_path;
750 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
751 o = (MonoObject *)add->setup->private_bin_path_probe;
752 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
753 o = (MonoObject *)add->setup->shadow_copy_directories;
754 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
755 o = (MonoObject *)add->setup->shadow_copy_files;
757 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
759 mono_domain_unlock (add);
769 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
773 MONO_CHECK_ARG_NULL (name,);
779 mono_domain_lock (add);
781 mono_g_hash_table_insert (add->env, name, data);
783 mono_domain_unlock (add);
787 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
792 return ad->data->setup;
796 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
801 return mono_string_new (ad->data, ad->data->friendly_name);
805 ves_icall_System_AppDomain_getCurDomain ()
807 MonoDomain *add = mono_domain_get ();
813 ves_icall_System_AppDomain_getRootDomain ()
815 MonoDomain *root = mono_get_root_domain ();
821 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
823 MonoDomain *domain = mono_domain_get ();
825 return domain->throw_unobserved_task_exceptions;
829 get_attribute_value (const gchar **attribute_names,
830 const gchar **attribute_values,
831 const char *att_name)
834 for (n = 0; attribute_names [n] != NULL; n++) {
835 if (strcmp (attribute_names [n], att_name) == 0)
836 return g_strdup (attribute_values [n]);
842 start_element (GMarkupParseContext *context,
843 const gchar *element_name,
844 const gchar **attribute_names,
845 const gchar **attribute_values,
849 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
851 if (strcmp (element_name, "runtime") == 0) {
852 runtime_config->runtime_count++;
856 if (strcmp (element_name, "assemblyBinding") == 0) {
857 runtime_config->assemblybinding_count++;
861 if (runtime_config->runtime_count != 1)
864 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
865 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
867 if (value && g_ascii_strcasecmp (value, "true") == 0)
868 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
871 if (runtime_config->assemblybinding_count != 1)
874 if (strcmp (element_name, "probing") != 0)
877 g_free (runtime_config->domain->private_bin_path);
878 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
879 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
880 g_free (runtime_config->domain->private_bin_path);
881 runtime_config->domain->private_bin_path = NULL;
887 end_element (GMarkupParseContext *context,
888 const gchar *element_name,
892 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
893 if (strcmp (element_name, "runtime") == 0)
894 runtime_config->runtime_count--;
895 else if (strcmp (element_name, "assemblyBinding") == 0)
896 runtime_config->assemblybinding_count--;
900 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
902 RuntimeConfig *state = (RuntimeConfig *)user_data;
904 const gchar *filename;
906 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
907 msg = error && error->message ? error->message : "";
908 g_warning ("Error parsing %s: %s", filename, msg);
911 static const GMarkupParser
921 mono_domain_set_options_from_config (MonoDomain *domain)
924 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
926 GMarkupParseContext *context;
927 RuntimeConfig runtime_config;
930 if (!domain || !domain->setup || !domain->setup->configuration_file)
933 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
934 if (!mono_error_ok (&error)) {
935 mono_error_cleanup (&error);
939 config_file_path = mono_portability_find_file (config_file_name, TRUE);
940 if (!config_file_path)
941 config_file_path = config_file_name;
943 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
946 runtime_config.runtime_count = 0;
947 runtime_config.assemblybinding_count = 0;
948 runtime_config.domain = domain;
949 runtime_config.filename = config_file_path;
952 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
953 offset = 3; /* Skip UTF-8 BOM */
955 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
956 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
957 g_markup_parse_context_end_parse (context, NULL);
958 g_markup_parse_context_free (context);
962 if (config_file_name != config_file_path)
963 g_free (config_file_name);
964 g_free (config_file_path);
968 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
971 MonoAppDomain *ad = NULL;
973 #ifdef DISABLE_APPDOMAINS
974 mono_error_init (&error);
975 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
979 fname = mono_string_to_utf8_checked (friendly_name, &error);
980 if (mono_error_set_pending_exception (&error))
982 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
986 mono_error_set_pending_exception (&error);
991 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
993 HANDLE_FUNCTION_ENTER ();
994 mono_error_init (error);
995 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
998 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1000 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1004 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1006 mono_error_init (error);
1007 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1011 GPtrArray *assemblies;
1014 * Make a copy of the list of assemblies because we can't hold the assemblies
1015 * lock while creating objects etc.
1017 assemblies = g_ptr_array_new ();
1018 /* Need to skip internal assembly builders created by remoting */
1019 mono_domain_assemblies_lock (domain);
1020 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1021 ass = (MonoAssembly *)tmp->data;
1022 if (refonly != ass->ref_only)
1024 if (ass->corlib_internal)
1026 g_ptr_array_add (assemblies, ass);
1028 mono_domain_assemblies_unlock (domain);
1030 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1033 for (i = 0; i < assemblies->len; ++i) {
1034 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1039 g_ptr_array_free (assemblies, TRUE);
1044 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1046 HANDLE_FUNCTION_ENTER ();
1047 mono_error_init (error);
1048 MonoAssembly *result = NULL;
1049 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1052 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1054 HANDLE_FUNCTION_RETURN_VAL (result);
1058 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1060 MonoAssembly *ret = NULL;
1062 MonoBoolean isrefonly;
1063 gpointer params [3];
1065 mono_error_init (error);
1067 if (mono_runtime_get_no_exec ())
1070 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1072 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1073 g_assert (method != NULL);
1075 isrefonly = refonly ? 1 : 0;
1076 MonoReflectionAssemblyHandle requesting_handle;
1078 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1079 return_val_if_nok (error, ret);
1081 params [0] = MONO_HANDLE_RAW (fname);
1082 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1083 params [2] = &isrefonly;
1084 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1085 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1090 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1094 MonoAssembly *assembly;
1095 MonoDomain *domain = mono_domain_get ();
1098 aname_str = mono_stringify_assembly_name (aname);
1100 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1102 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1104 mono_error_cleanup (&error);
1110 * LOCKING: assumes assemblies_lock in the domain is already locked.
1113 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1117 gboolean destroy_ht = FALSE;
1119 if (!ass->aname.name)
1123 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1127 /* FIXME: handle lazy loaded assemblies */
1128 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1129 g_hash_table_insert (ht, tmp->data, tmp->data);
1131 if (!g_hash_table_lookup (ht, ass)) {
1132 mono_assembly_addref (ass);
1133 g_hash_table_insert (ht, ass, ass);
1134 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1135 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);
1138 if (ass->image->references) {
1139 for (i = 0; ass->image->references [i] != NULL; i++) {
1140 if (ass->image->references [i] != REFERENCE_MISSING)
1141 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1142 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1147 g_hash_table_destroy (ht);
1151 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1153 static MonoClassField *assembly_load_field;
1154 static MonoMethod *assembly_load_method;
1156 MonoDomain *domain = mono_domain_get ();
1158 gpointer load_value;
1161 if (!domain->domain)
1162 /* This can happen during startup */
1164 #ifdef ASSEMBLY_LOAD_DEBUG
1165 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1167 klass = domain->domain->mbr.obj.vtable->klass;
1169 mono_domain_assemblies_lock (domain);
1170 add_assemblies_to_domain (domain, assembly, NULL);
1171 mono_domain_assemblies_unlock (domain);
1173 if (assembly_load_field == NULL) {
1174 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1175 g_assert (assembly_load_field);
1178 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1179 if (load_value == NULL) {
1180 /* No events waiting to be triggered */
1184 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1185 mono_error_assert_ok (&error);
1187 if (assembly_load_method == NULL) {
1188 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1189 g_assert (assembly_load_method);
1192 *params = MONO_HANDLE_RAW(ref_assembly);
1194 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1195 mono_error_cleanup (&error);
1199 * LOCKING: Acquires the domain assemblies lock.
1202 set_domain_search_path (MonoDomain *domain)
1205 MonoAppDomainSetup *setup;
1207 gchar *search_path = NULL;
1210 gchar **pvt_split = NULL;
1211 GError *gerror = NULL;
1212 gint appbaselen = -1;
1215 * We use the low-level domain assemblies lock, since this is called from
1216 * assembly loads hooks, which means this thread might hold the loader lock.
1218 mono_domain_assemblies_lock (domain);
1220 if (!domain->setup) {
1221 mono_domain_assemblies_unlock (domain);
1225 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1226 mono_domain_assemblies_unlock (domain);
1229 setup = domain->setup;
1230 if (!setup->application_base) {
1231 mono_domain_assemblies_unlock (domain);
1232 return; /* Must set application base to get private path working */
1237 if (setup->private_bin_path) {
1238 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1239 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1240 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1241 mono_error_cleanup (&error);
1242 mono_domain_assemblies_unlock (domain);
1247 if (domain->private_bin_path) {
1248 if (search_path == NULL)
1249 search_path = domain->private_bin_path;
1251 gchar *tmp2 = search_path;
1252 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1259 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1260 * directories relative to ApplicationBase separated by semicolons (see
1261 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1262 * The loop below copes with the fact that some Unix applications may use ':' (or
1263 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1264 * ';' for the subsequent split.
1266 * The issue was reported in bug #81446
1269 #ifndef TARGET_WIN32
1272 slen = strlen (search_path);
1273 for (i = 0; i < slen; i++)
1274 if (search_path [i] == ':')
1275 search_path [i] = ';';
1278 pvt_split = g_strsplit (search_path, ";", 1000);
1279 g_free (search_path);
1280 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1285 g_strfreev (pvt_split);
1287 * Don't do this because the first time is called, the domain
1288 * setup is not finished.
1290 * domain->search_path = g_malloc (sizeof (char *));
1291 * domain->search_path [0] = NULL;
1293 mono_domain_assemblies_unlock (domain);
1297 if (domain->search_path)
1298 g_strfreev (domain->search_path);
1300 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1301 tmp [npaths] = NULL;
1303 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1304 if (!mono_error_ok (&error)) {
1305 mono_error_cleanup (&error);
1306 g_strfreev (pvt_split);
1309 mono_domain_assemblies_unlock (domain);
1313 domain->search_path = tmp;
1315 /* FIXME: is this needed? */
1316 if (strncmp (*tmp, "file://", 7) == 0) {
1322 uri = g_strdup_printf ("file:///%s", uri + 7);
1325 uri = mono_escape_uri_string (tmpuri);
1326 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1332 if (gerror != NULL) {
1333 g_warning ("%s\n", gerror->message);
1334 g_error_free (gerror);
1341 for (i = 1; pvt_split && i < npaths; i++) {
1342 if (g_path_is_absolute (pvt_split [i - 1])) {
1343 tmp [i] = g_strdup (pvt_split [i - 1]);
1345 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1348 if (strchr (tmp [i], '.')) {
1352 reduced = mono_path_canonicalize (tmp [i]);
1353 if (appbaselen == -1)
1354 appbaselen = strlen (tmp [0]);
1356 if (strncmp (tmp [0], reduced, appbaselen)) {
1359 tmp [i] = g_strdup ("");
1369 if (setup->private_bin_path_probe != NULL) {
1371 tmp [0] = g_strdup ("");
1374 domain->setup->path_changed = FALSE;
1376 g_strfreev (pvt_split);
1378 mono_domain_assemblies_unlock (domain);
1381 #ifdef DISABLE_SHADOW_COPY
1383 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1389 mono_make_shadow_copy (const char *filename, MonoError *error)
1391 mono_error_init (error);
1392 return (char *) filename;
1396 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1398 guint16 *orig, *dest;
1399 gboolean copy_result;
1401 strcpy (src + srclen - tail_len, extension);
1403 if (IS_PORTABILITY_CASE) {
1404 gchar *file = mono_portability_find_file (src, TRUE);
1410 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1414 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1416 strcpy (target + targetlen - tail_len, extension);
1417 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1421 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1422 copy_result = CopyFile (orig, dest, FALSE);
1424 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1427 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1428 * overwritten when updated in their original locations. */
1430 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1439 get_cstring_hash (const char *str)
1445 if (!str || !str [0])
1450 for (i = 0; i < len; i++) {
1451 h = (h << 5) - h + *p;
1459 * Returned memory is malloc'd. Called must free it
1462 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1464 MonoAppDomainSetup *setup;
1465 char *cache_path, *appname;
1469 mono_error_init (error);
1471 setup = domain->setup;
1472 if (setup->cache_path != NULL && setup->application_name != NULL) {
1473 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1474 return_val_if_nok (error, NULL);
1476 #ifndef TARGET_WIN32
1479 for (i = strlen (cache_path) - 1; i >= 0; i--)
1480 if (cache_path [i] == '\\')
1481 cache_path [i] = '/';
1485 appname = mono_string_to_utf8_checked (setup->application_name, error);
1486 if (!mono_error_ok (error)) {
1487 g_free (cache_path);
1491 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1493 g_free (cache_path);
1495 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1496 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1503 get_shadow_assembly_location (const char *filename, MonoError *error)
1505 gint32 hash = 0, hash2 = 0;
1507 char path_hash [30];
1508 char *bname = g_path_get_basename (filename);
1509 char *dirname = g_path_get_dirname (filename);
1510 char *location, *tmploc;
1511 MonoDomain *domain = mono_domain_get ();
1513 mono_error_init (error);
1515 hash = get_cstring_hash (bname);
1516 hash2 = get_cstring_hash (dirname);
1517 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1518 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1519 tmploc = get_shadow_assembly_location_base (domain, error);
1520 if (!mono_error_ok (error)) {
1526 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1534 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1536 struct stat sbuf_dest;
1538 gchar *real_src = mono_portability_find_file (src, TRUE);
1541 stat_src = (gchar*)src;
1543 stat_src = real_src;
1545 if (stat (stat_src, sbuf_src) == -1) {
1546 time_t tnow = time (NULL);
1551 memset (sbuf_src, 0, sizeof (*sbuf_src));
1552 sbuf_src->st_mtime = tnow;
1553 sbuf_src->st_atime = tnow;
1560 if (stat (dest, &sbuf_dest) == -1)
1563 if (sbuf_src->st_size == sbuf_dest.st_size &&
1564 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1571 shadow_copy_create_ini (const char *shadow, const char *filename)
1581 dir_name = g_path_get_dirname (shadow);
1582 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1584 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1589 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1594 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1595 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1597 if (handle == INVALID_HANDLE_VALUE) {
1601 full_path = mono_path_resolve_symlinks (filename);
1602 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1604 CloseHandle (handle);
1609 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1612 MonoAppDomainSetup *setup;
1615 gchar **directories;
1616 gchar *shadow_status_string;
1618 gboolean shadow_enabled;
1619 gboolean found = FALSE;
1624 setup = domain->setup;
1625 if (setup == NULL || setup->shadow_copy_files == NULL)
1628 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1629 if (!mono_error_ok (&error)) {
1630 mono_error_cleanup (&error);
1633 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1634 g_free (shadow_status_string);
1636 if (!shadow_enabled)
1639 if (setup->shadow_copy_directories == NULL)
1642 /* Is dir_name a shadow_copy destination already? */
1643 base_dir = get_shadow_assembly_location_base (domain, &error);
1644 if (!mono_error_ok (&error)) {
1645 mono_error_cleanup (&error);
1649 if (strstr (dir_name, base_dir)) {
1655 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1656 if (!mono_error_ok (&error)) {
1657 mono_error_cleanup (&error);
1661 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1662 dir_ptr = directories;
1664 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1670 g_strfreev (directories);
1676 This function raises exceptions so it can cause as sorts of nasty stuff if called
1677 while holding a lock.
1678 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1679 or NULL if source file not found.
1680 FIXME bubble up the error instead of raising it here
1683 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1686 gchar *sibling_source, *sibling_target;
1687 gint sibling_source_len, sibling_target_len;
1688 guint16 *orig, *dest;
1691 gboolean copy_result;
1692 struct stat src_sbuf;
1693 struct utimbuf utbuf;
1694 char *dir_name = g_path_get_dirname (filename);
1695 MonoDomain *domain = mono_domain_get ();
1698 mono_error_init (oerror);
1700 set_domain_search_path (domain);
1702 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1704 return (char *) filename;
1707 /* Is dir_name a shadow_copy destination already? */
1708 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1709 if (!mono_error_ok (&error)) {
1710 mono_error_cleanup (&error);
1712 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1716 if (strstr (dir_name, shadow_dir)) {
1717 g_free (shadow_dir);
1719 return (char *) filename;
1721 g_free (shadow_dir);
1724 shadow = get_shadow_assembly_location (filename, &error);
1725 if (!mono_error_ok (&error)) {
1726 mono_error_cleanup (&error);
1727 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1731 if (g_ensure_directory_exists (shadow) == FALSE) {
1733 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1737 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1738 return (char*) shadow;
1740 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1741 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1744 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1745 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1746 * and not have it runtime error" */
1747 attrs = GetFileAttributes (orig);
1748 if (attrs == INVALID_FILE_ATTRIBUTES) {
1750 return (char *)filename;
1753 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1754 copy_result = CopyFile (orig, dest, FALSE);
1756 copy_result = SUCCEEDED (CopyFile2 (orig, dest, NULL));
1759 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1760 * overwritten when updated in their original locations. */
1762 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1767 if (copy_result == FALSE) {
1770 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1771 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1772 return NULL; /* file not found, shadow copy failed */
1774 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1778 /* attempt to copy .mdb, .config if they exist */
1779 sibling_source = g_strconcat (filename, ".config", NULL);
1780 sibling_source_len = strlen (sibling_source);
1781 sibling_target = g_strconcat (shadow, ".config", NULL);
1782 sibling_target_len = strlen (sibling_target);
1784 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1786 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1788 g_free (sibling_source);
1789 g_free (sibling_target);
1793 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1797 /* Create a .ini file containing the original assembly location */
1798 if (!shadow_copy_create_ini (shadow, filename)) {
1800 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1804 utbuf.actime = src_sbuf.st_atime;
1805 utbuf.modtime = src_sbuf.st_mtime;
1806 utime (shadow, &utbuf);
1810 #endif /* DISABLE_SHADOW_COPY */
1813 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1815 if (appdomain == NULL)
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_ms_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);