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-internals.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/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/marshal-internals.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/w32file.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/abi-details.h>
61 #include <mono/metadata/w32socket.h>
62 #include <mono/utils/mono-uri.h>
63 #include <mono/utils/mono-logger-internals.h>
64 #include <mono/utils/mono-path.h>
65 #include <mono/utils/mono-stdlib.h>
66 #include <mono/utils/mono-io-portability.h>
67 #include <mono/utils/mono-error-internals.h>
68 #include <mono/utils/atomic.h>
69 #include <mono/utils/mono-memory-model.h>
70 #include <mono/utils/mono-threads.h>
71 #include <mono/metadata/w32handle.h>
72 #include <mono/metadata/w32error.h>
73 #include <mono/utils/w32api.h>
81 int assemblybinding_count;
86 static gunichar2 process_guid [36];
87 static gboolean process_guid_set = FALSE;
89 static gboolean no_exec = FALSE;
92 mono_domain_assembly_preload (MonoAssemblyName *aname,
93 gchar **assemblies_path,
97 mono_domain_assembly_search (MonoAssemblyName *aname,
101 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
104 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
106 static MonoAppDomainHandle
107 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
110 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
114 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
116 static MonoLoadFunc load_function = NULL;
118 /* Lazy class loading functions */
119 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
121 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
124 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
127 mono_error_set_appdomain_unloaded (MonoError *error)
129 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
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;
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;
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)
448 HANDLE_FUNCTION_ENTER ();
450 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
451 mono_error_cleanup (&error);
452 HANDLE_FUNCTION_RETURN_VAL (domain);
456 * mono_domain_create_appdomain_checked:
457 * @friendly_name: The friendly name of the appdomain to create
458 * @configuration_file: The configuration file to initialize the appdomain with
459 * @error: Set on error.
461 * Returns a MonoDomain initialized with the appdomain. On failure sets @error and returns NULL.
464 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
466 HANDLE_FUNCTION_ENTER ();
468 MonoDomain *result = NULL;
470 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
471 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
474 MonoStringHandle config_file;
475 if (configuration_file != NULL) {
476 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
480 config_file = MONO_HANDLE_NEW (MonoString, NULL);
482 MONO_HANDLE_SET (setup, configuration_file, config_file);
484 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
488 result = mono_domain_from_appdomain_handle (ad);
490 HANDLE_FUNCTION_RETURN_VAL (result);
494 * mono_domain_set_config:
495 * @domain: MonoDomain initialized with the appdomain we want to change
496 * @base_dir: new base directory for the appdomain
497 * @config_file_name: path to the new configuration for the app domain
499 * Used to set the system configuration for an appdomain
501 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
502 * Error Initializing the configuration system. ---> System.ArgumentException:
503 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
506 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
508 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
509 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
512 static MonoAppDomainSetupHandle
513 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
515 HANDLE_FUNCTION_ENTER ();
516 MonoDomain *caller_domain;
517 MonoClass *ads_class;
518 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
522 caller_domain = mono_domain_get ();
523 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
525 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
529 mono_domain_set_internal (domain);
531 #define XCOPY_FIELD(dst,field,src,error) \
533 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
534 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
535 if (!is_ok (error)) \
537 MONO_HANDLE_SET ((dst),field,copied_val); \
540 #define COPY_VAL(dst,field,type,src) \
542 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
545 XCOPY_FIELD (copy, application_base, setup, error);
546 XCOPY_FIELD (copy, application_name, setup, error);
547 XCOPY_FIELD (copy, cache_path, setup, error);
548 XCOPY_FIELD (copy, configuration_file, setup, error);
549 XCOPY_FIELD (copy, dynamic_base, setup, error);
550 XCOPY_FIELD (copy, license_file, setup, error);
551 XCOPY_FIELD (copy, private_bin_path, setup, error);
552 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
553 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
554 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
555 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
556 COPY_VAL (copy, path_changed, MonoBoolean, setup);
557 COPY_VAL (copy, loader_optimization, int, setup);
558 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
559 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
560 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
561 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
562 XCOPY_FIELD (copy, application_trust, setup, error);
563 XCOPY_FIELD (copy, configuration_bytes, setup, error);
564 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
569 mono_domain_set_internal (caller_domain);
571 MONO_HANDLE_ASSIGN (result, copy);
573 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
576 static MonoAppDomainHandle
577 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
579 HANDLE_FUNCTION_ENTER ();
580 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
586 adclass = mono_class_get_appdomain_class ();
588 /* FIXME: pin all those objects */
589 data = mono_domain_create();
591 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
594 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
595 data->domain = MONO_HANDLE_RAW (ad);
596 data->friendly_name = g_strdup (friendly_name);
598 mono_profiler_appdomain_name (data, data->friendly_name);
600 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
601 if (MONO_HANDLE_IS_NULL (app_base)) {
602 /* Inherit from the root domain since MS.NET does this */
603 MonoDomain *root = mono_get_root_domain ();
604 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
605 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
606 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
607 /* N.B. new string is in the new domain */
608 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
609 MonoStringHandle s = mono_string_new_utf16_handle (data, mono_string_chars (MONO_HANDLE_RAW (root_app_base)), mono_string_handle_length (root_app_base), error);
610 mono_gchandle_free (gchandle);
611 if (!is_ok (error)) {
612 g_free (data->friendly_name);
615 MONO_HANDLE_SET (setup, application_base, s);
619 mono_context_init_checked (data, error);
623 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
624 if (!mono_error_ok (error)) {
625 g_free (data->friendly_name);
629 mono_domain_set_options_from_config (data);
630 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
632 #ifndef DISABLE_SHADOW_COPY
633 /*FIXME, guard this for when the debugger is not running */
634 char *shadow_location = get_shadow_assembly_location_base (data, error);
635 if (!mono_error_ok (error)) {
636 g_free (data->friendly_name);
640 g_free (shadow_location);
643 create_domain_objects (data);
645 MONO_HANDLE_ASSIGN (result, ad);
647 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
651 * mono_domain_has_type_resolve:
652 * @domain: application domains being looked up
654 * Returns: TRUE if the AppDomain.TypeResolve field has been
658 mono_domain_has_type_resolve (MonoDomain *domain)
660 static MonoClassField *field = NULL;
664 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
668 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
672 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
677 * mono_domain_try_type_resolve:
678 * @domain: application domainwhere the name where the type is going to be resolved
679 * @name: the name of the type to resolve or NULL.
680 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
682 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
683 * the assembly that matches name.
685 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
687 * Returns: A MonoReflectionAssembly or NULL if not found
689 MonoReflectionAssembly *
690 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
693 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
694 mono_error_cleanup (&error);
699 MonoReflectionAssembly *
700 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
702 static MonoMethod *method = NULL;
703 MonoReflectionAssembly *ret;
708 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
710 if (method == NULL) {
711 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
712 if (method == NULL) {
713 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
719 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
723 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
724 return_val_if_nok (error, NULL);
730 * mono_domain_owns_vtable_slot:
732 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
735 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
739 mono_domain_lock (domain);
740 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
741 mono_domain_unlock (domain);
748 * @force: force setting.
750 * Set the current appdomain to @domain. If @force is set, set it even
751 * if it is being unloaded.
755 * FALSE if the domain is unloaded
758 mono_domain_set (MonoDomain *domain, gboolean force)
760 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
763 mono_domain_set_internal (domain);
769 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
773 if (MONO_HANDLE_IS_NULL (name)) {
774 mono_error_set_argument_null (error, "name", "");
778 g_assert (!MONO_HANDLE_IS_NULL (ad));
779 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
782 char *str = mono_string_handle_to_utf8 (name, error);
783 return_val_if_nok (error, NULL_HANDLE);
785 mono_domain_lock (add);
787 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
789 if (!strcmp (str, "APPBASE"))
790 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
791 else if (!strcmp (str, "APP_CONFIG_FILE"))
792 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
793 else if (!strcmp (str, "DYNAMIC_BASE"))
794 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
795 else if (!strcmp (str, "APP_NAME"))
796 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
797 else if (!strcmp (str, "CACHE_BASE"))
798 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
799 else if (!strcmp (str, "PRIVATE_BINPATH"))
800 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
801 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
802 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
803 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
804 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
805 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
806 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
808 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
810 mono_domain_unlock (add);
813 return MONO_HANDLE_CAST (MonoObject, o);
817 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
821 if (MONO_HANDLE_IS_NULL (name)) {
822 mono_error_set_argument_null (error, "name", "");
826 g_assert (!MONO_HANDLE_IS_NULL (ad));
827 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
830 mono_domain_lock (add);
832 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
834 mono_domain_unlock (add);
837 MonoAppDomainSetupHandle
838 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
841 g_assert (!MONO_HANDLE_IS_NULL (ad));
842 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
845 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
849 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
852 g_assert (!MONO_HANDLE_IS_NULL (ad));
853 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
856 return mono_string_new_handle (domain, domain->friendly_name, error);
860 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
863 MonoDomain *add = mono_domain_get ();
865 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
869 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
872 MonoDomain *root = mono_get_root_domain ();
874 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
878 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
880 MonoDomain *domain = mono_domain_get ();
882 return domain->throw_unobserved_task_exceptions;
886 get_attribute_value (const gchar **attribute_names,
887 const gchar **attribute_values,
888 const char *att_name)
891 for (n = 0; attribute_names [n] != NULL; n++) {
892 if (strcmp (attribute_names [n], att_name) == 0)
893 return g_strdup (attribute_values [n]);
899 start_element (GMarkupParseContext *context,
900 const gchar *element_name,
901 const gchar **attribute_names,
902 const gchar **attribute_values,
906 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
908 if (strcmp (element_name, "runtime") == 0) {
909 runtime_config->runtime_count++;
913 if (strcmp (element_name, "assemblyBinding") == 0) {
914 runtime_config->assemblybinding_count++;
918 if (runtime_config->runtime_count != 1)
921 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
922 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
924 if (value && g_ascii_strcasecmp (value, "true") == 0)
925 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
928 if (runtime_config->assemblybinding_count != 1)
931 if (strcmp (element_name, "probing") != 0)
934 g_free (runtime_config->domain->private_bin_path);
935 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
936 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
937 g_free (runtime_config->domain->private_bin_path);
938 runtime_config->domain->private_bin_path = NULL;
944 end_element (GMarkupParseContext *context,
945 const gchar *element_name,
949 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
950 if (strcmp (element_name, "runtime") == 0)
951 runtime_config->runtime_count--;
952 else if (strcmp (element_name, "assemblyBinding") == 0)
953 runtime_config->assemblybinding_count--;
957 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
959 RuntimeConfig *state = (RuntimeConfig *)user_data;
961 const gchar *filename;
963 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
964 msg = error && error->message ? error->message : "";
965 g_warning ("Error parsing %s: %s", filename, msg);
968 static const GMarkupParser
978 mono_domain_set_options_from_config (MonoDomain *domain)
981 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
983 GMarkupParseContext *context;
984 RuntimeConfig runtime_config;
987 if (!domain || !domain->setup || !domain->setup->configuration_file)
990 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
991 if (!mono_error_ok (&error)) {
992 mono_error_cleanup (&error);
996 config_file_path = mono_portability_find_file (config_file_name, TRUE);
997 if (!config_file_path)
998 config_file_path = config_file_name;
1000 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1003 runtime_config.runtime_count = 0;
1004 runtime_config.assemblybinding_count = 0;
1005 runtime_config.domain = domain;
1006 runtime_config.filename = config_file_path;
1009 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1010 offset = 3; /* Skip UTF-8 BOM */
1012 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1013 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1014 g_markup_parse_context_end_parse (context, NULL);
1015 g_markup_parse_context_free (context);
1019 if (config_file_name != config_file_path)
1020 g_free (config_file_name);
1021 g_free (config_file_path);
1025 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1028 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1030 #ifdef DISABLE_APPDOMAINS
1031 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1035 fname = mono_string_handle_to_utf8 (friendly_name, error);
1036 return_val_if_nok (error, ad);
1037 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1044 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1046 HANDLE_FUNCTION_ENTER ();
1048 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1051 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1053 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1057 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1060 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1064 GPtrArray *assemblies;
1067 * Make a copy of the list of assemblies because we can't hold the assemblies
1068 * lock while creating objects etc.
1070 assemblies = g_ptr_array_new ();
1071 /* Need to skip internal assembly builders created by remoting */
1072 mono_domain_assemblies_lock (domain);
1073 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1074 ass = (MonoAssembly *)tmp->data;
1075 if (refonly != ass->ref_only)
1077 if (ass->corlib_internal)
1079 g_ptr_array_add (assemblies, ass);
1081 mono_domain_assemblies_unlock (domain);
1083 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1086 for (i = 0; i < assemblies->len; ++i) {
1087 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1092 g_ptr_array_free (assemblies, TRUE);
1097 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1099 HANDLE_FUNCTION_ENTER ();
1101 MonoAssembly *result = NULL;
1102 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1105 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1107 HANDLE_FUNCTION_RETURN_VAL (result);
1111 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1113 MonoAssembly *ret = NULL;
1115 MonoBoolean isrefonly;
1116 gpointer params [3];
1120 if (mono_runtime_get_no_exec ())
1123 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1125 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1126 g_assert (method != NULL);
1128 isrefonly = refonly ? 1 : 0;
1129 MonoReflectionAssemblyHandle requesting_handle;
1131 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1132 return_val_if_nok (error, ret);
1134 params [0] = MONO_HANDLE_RAW (fname);
1135 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1136 params [2] = &isrefonly;
1137 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1138 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1143 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1147 MonoAssembly *assembly;
1148 MonoDomain *domain = mono_domain_get ();
1151 aname_str = mono_stringify_assembly_name (aname);
1153 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1155 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1157 mono_error_cleanup (&error);
1163 * LOCKING: assumes assemblies_lock in the domain is already locked.
1166 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1170 gboolean destroy_ht = FALSE;
1172 if (!ass->aname.name)
1176 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1178 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1179 g_hash_table_insert (ht, tmp->data, tmp->data);
1183 /* FIXME: handle lazy loaded assemblies */
1185 if (!g_hash_table_lookup (ht, ass)) {
1186 mono_assembly_addref (ass);
1187 g_hash_table_insert (ht, ass, ass);
1188 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1189 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);
1192 if (ass->image->references) {
1193 for (i = 0; i < ass->image->nreferences; i++) {
1194 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1195 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1196 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1202 g_hash_table_destroy (ht);
1206 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1208 static MonoClassField *assembly_load_field;
1209 static MonoMethod *assembly_load_method;
1211 MonoDomain *domain = mono_domain_get ();
1213 gpointer load_value;
1216 if (!domain->domain)
1217 /* This can happen during startup */
1219 #ifdef ASSEMBLY_LOAD_DEBUG
1220 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1222 klass = domain->domain->mbr.obj.vtable->klass;
1224 mono_domain_assemblies_lock (domain);
1225 add_assemblies_to_domain (domain, assembly, NULL);
1226 mono_domain_assemblies_unlock (domain);
1228 if (assembly_load_field == NULL) {
1229 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1230 g_assert (assembly_load_field);
1233 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1234 if (load_value == NULL) {
1235 /* No events waiting to be triggered */
1239 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1240 mono_error_assert_ok (&error);
1242 if (assembly_load_method == NULL) {
1243 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1244 g_assert (assembly_load_method);
1247 *params = MONO_HANDLE_RAW(ref_assembly);
1249 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1250 mono_error_cleanup (&error);
1254 * LOCKING: Acquires the domain assemblies lock.
1257 set_domain_search_path (MonoDomain *domain)
1260 MonoAppDomainSetup *setup;
1262 gchar *search_path = NULL;
1265 gchar **pvt_split = NULL;
1266 GError *gerror = NULL;
1267 gint appbaselen = -1;
1270 * We use the low-level domain assemblies lock, since this is called from
1271 * assembly loads hooks, which means this thread might hold the loader lock.
1273 mono_domain_assemblies_lock (domain);
1275 if (!domain->setup) {
1276 mono_domain_assemblies_unlock (domain);
1280 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1281 mono_domain_assemblies_unlock (domain);
1284 setup = domain->setup;
1285 if (!setup->application_base) {
1286 mono_domain_assemblies_unlock (domain);
1287 return; /* Must set application base to get private path working */
1292 if (setup->private_bin_path) {
1293 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1294 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1295 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1296 mono_error_cleanup (&error);
1297 mono_domain_assemblies_unlock (domain);
1302 if (domain->private_bin_path) {
1303 if (search_path == NULL)
1304 search_path = domain->private_bin_path;
1306 gchar *tmp2 = search_path;
1307 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1314 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1315 * directories relative to ApplicationBase separated by semicolons (see
1316 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1317 * The loop below copes with the fact that some Unix applications may use ':' (or
1318 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1319 * ';' for the subsequent split.
1321 * The issue was reported in bug #81446
1324 #ifndef TARGET_WIN32
1327 slen = strlen (search_path);
1328 for (i = 0; i < slen; i++)
1329 if (search_path [i] == ':')
1330 search_path [i] = ';';
1333 pvt_split = g_strsplit (search_path, ";", 1000);
1334 g_free (search_path);
1335 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1340 g_strfreev (pvt_split);
1342 * Don't do this because the first time is called, the domain
1343 * setup is not finished.
1345 * domain->search_path = g_malloc (sizeof (char *));
1346 * domain->search_path [0] = NULL;
1348 mono_domain_assemblies_unlock (domain);
1352 if (domain->search_path)
1353 g_strfreev (domain->search_path);
1355 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1356 tmp [npaths] = NULL;
1358 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1359 if (!mono_error_ok (&error)) {
1360 mono_error_cleanup (&error);
1361 g_strfreev (pvt_split);
1364 mono_domain_assemblies_unlock (domain);
1368 domain->search_path = tmp;
1370 /* FIXME: is this needed? */
1371 if (strncmp (*tmp, "file://", 7) == 0) {
1377 uri = g_strdup_printf ("file:///%s", uri + 7);
1380 uri = mono_escape_uri_string (tmpuri);
1381 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1387 if (gerror != NULL) {
1388 g_warning ("%s\n", gerror->message);
1389 g_error_free (gerror);
1396 for (i = 1; pvt_split && i < npaths; i++) {
1397 if (g_path_is_absolute (pvt_split [i - 1])) {
1398 tmp [i] = g_strdup (pvt_split [i - 1]);
1400 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1403 if (strchr (tmp [i], '.')) {
1407 reduced = mono_path_canonicalize (tmp [i]);
1408 if (appbaselen == -1)
1409 appbaselen = strlen (tmp [0]);
1411 if (strncmp (tmp [0], reduced, appbaselen)) {
1414 tmp [i] = g_strdup ("");
1424 if (setup->private_bin_path_probe != NULL) {
1426 tmp [0] = g_strdup ("");
1429 domain->setup->path_changed = FALSE;
1431 g_strfreev (pvt_split);
1433 mono_domain_assemblies_unlock (domain);
1436 #ifdef DISABLE_SHADOW_COPY
1438 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1444 mono_make_shadow_copy (const char *filename, MonoError *error)
1447 return (char *) filename;
1451 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1453 guint16 *orig, *dest;
1454 gboolean copy_result;
1457 strcpy (src + srclen - tail_len, extension);
1459 if (IS_PORTABILITY_CASE) {
1460 gchar *file = mono_portability_find_file (src, TRUE);
1466 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1470 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1472 strcpy (target + targetlen - tail_len, extension);
1473 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1475 mono_w32file_delete (dest);
1477 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1479 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1480 * overwritten when updated in their original locations. */
1482 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1491 get_cstring_hash (const char *str)
1497 if (!str || !str [0])
1502 for (i = 0; i < len; i++) {
1503 h = (h << 5) - h + *p;
1511 * Returned memory is malloc'd. Called must free it
1514 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1516 MonoAppDomainSetup *setup;
1517 char *cache_path, *appname;
1523 setup = domain->setup;
1524 if (setup->cache_path != NULL && setup->application_name != NULL) {
1525 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1526 return_val_if_nok (error, NULL);
1528 #ifndef TARGET_WIN32
1531 for (i = strlen (cache_path) - 1; i >= 0; i--)
1532 if (cache_path [i] == '\\')
1533 cache_path [i] = '/';
1537 appname = mono_string_to_utf8_checked (setup->application_name, error);
1538 if (!mono_error_ok (error)) {
1539 g_free (cache_path);
1543 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1545 g_free (cache_path);
1547 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1548 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1555 get_shadow_assembly_location (const char *filename, MonoError *error)
1557 gint32 hash = 0, hash2 = 0;
1559 char path_hash [30];
1560 char *bname = g_path_get_basename (filename);
1561 char *dirname = g_path_get_dirname (filename);
1562 char *location, *tmploc;
1563 MonoDomain *domain = mono_domain_get ();
1567 hash = get_cstring_hash (bname);
1568 hash2 = get_cstring_hash (dirname);
1569 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1570 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1571 tmploc = get_shadow_assembly_location_base (domain, error);
1572 if (!mono_error_ok (error)) {
1578 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1586 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1588 struct stat sbuf_dest;
1590 gchar *real_src = mono_portability_find_file (src, TRUE);
1593 stat_src = (gchar*)src;
1595 stat_src = real_src;
1597 if (stat (stat_src, sbuf_src) == -1) {
1598 time_t tnow = time (NULL);
1603 memset (sbuf_src, 0, sizeof (*sbuf_src));
1604 sbuf_src->st_mtime = tnow;
1605 sbuf_src->st_atime = tnow;
1612 if (stat (dest, &sbuf_dest) == -1)
1615 if (sbuf_src->st_size == sbuf_dest.st_size &&
1616 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1623 shadow_copy_create_ini (const char *shadow, const char *filename)
1633 dir_name = g_path_get_dirname (shadow);
1634 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1636 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1641 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1646 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1648 if (handle == INVALID_HANDLE_VALUE) {
1652 full_path = mono_path_resolve_symlinks (filename);
1653 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1655 mono_w32file_close (handle);
1660 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1663 MonoAppDomainSetup *setup;
1666 gchar **directories;
1667 gchar *shadow_status_string;
1669 gboolean shadow_enabled;
1670 gboolean found = FALSE;
1675 setup = domain->setup;
1676 if (setup == NULL || setup->shadow_copy_files == NULL)
1679 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1680 if (!mono_error_ok (&error)) {
1681 mono_error_cleanup (&error);
1684 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1685 g_free (shadow_status_string);
1687 if (!shadow_enabled)
1690 if (setup->shadow_copy_directories == NULL)
1693 /* Is dir_name a shadow_copy destination already? */
1694 base_dir = get_shadow_assembly_location_base (domain, &error);
1695 if (!mono_error_ok (&error)) {
1696 mono_error_cleanup (&error);
1700 if (strstr (dir_name, base_dir)) {
1706 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1707 if (!mono_error_ok (&error)) {
1708 mono_error_cleanup (&error);
1712 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1713 dir_ptr = directories;
1715 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1721 g_strfreev (directories);
1727 This function raises exceptions so it can cause as sorts of nasty stuff if called
1728 while holding a lock.
1729 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1730 or NULL if source file not found.
1731 FIXME bubble up the error instead of raising it here
1734 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1737 gchar *sibling_source, *sibling_target;
1738 gint sibling_source_len, sibling_target_len;
1739 guint16 *orig, *dest;
1742 gboolean copy_result;
1743 struct stat src_sbuf;
1744 struct utimbuf utbuf;
1745 char *dir_name = g_path_get_dirname (filename);
1746 MonoDomain *domain = mono_domain_get ();
1750 error_init (oerror);
1752 set_domain_search_path (domain);
1754 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1756 return (char *) filename;
1759 /* Is dir_name a shadow_copy destination already? */
1760 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1761 if (!mono_error_ok (&error)) {
1762 mono_error_cleanup (&error);
1764 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1768 if (strstr (dir_name, shadow_dir)) {
1769 g_free (shadow_dir);
1771 return (char *) filename;
1773 g_free (shadow_dir);
1776 shadow = get_shadow_assembly_location (filename, &error);
1777 if (!mono_error_ok (&error)) {
1778 mono_error_cleanup (&error);
1779 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1783 if (g_ensure_directory_exists (shadow) == FALSE) {
1785 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1789 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1790 return (char*) shadow;
1792 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1793 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1794 mono_w32file_delete (dest);
1796 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1797 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1798 * and not have it runtime error" */
1799 attrs = mono_w32file_get_attributes (orig);
1800 if (attrs == INVALID_FILE_ATTRIBUTES) {
1802 return (char *)filename;
1805 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1807 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1808 * overwritten when updated in their original locations. */
1810 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1815 if (copy_result == FALSE) {
1818 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1819 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1820 return NULL; /* file not found, shadow copy failed */
1822 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1826 /* attempt to copy .mdb, .config if they exist */
1827 sibling_source = g_strconcat (filename, ".config", NULL);
1828 sibling_source_len = strlen (sibling_source);
1829 sibling_target = g_strconcat (shadow, ".config", NULL);
1830 sibling_target_len = strlen (sibling_target);
1832 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1834 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1836 g_free (sibling_source);
1837 g_free (sibling_target);
1841 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1845 /* Create a .ini file containing the original assembly location */
1846 if (!shadow_copy_create_ini (shadow, filename)) {
1848 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1852 utbuf.actime = src_sbuf.st_atime;
1853 utbuf.modtime = src_sbuf.st_mtime;
1854 utime (shadow, &utbuf);
1858 #endif /* DISABLE_SHADOW_COPY */
1861 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1863 HANDLE_FUNCTION_ENTER ();
1864 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1865 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1866 HANDLE_FUNCTION_RETURN_VAL (result);
1870 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1872 HANDLE_FUNCTION_ENTER ();
1873 MonoDomain *dom = NULL;
1874 if (MONO_HANDLE_IS_NULL (appdomain))
1877 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1878 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1879 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1881 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1883 dom = MONO_HANDLE_GETVAL (appdomain, data);
1886 HANDLE_FUNCTION_RETURN_VAL (dom);
1891 try_load_from (MonoAssembly **assembly,
1892 const gchar *path1, const gchar *path2,
1893 const gchar *path3, const gchar *path4,
1894 gboolean refonly, gboolean is_private,
1895 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1898 gboolean found = FALSE;
1901 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1903 if (IS_PORTABILITY_SET) {
1904 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1907 fullpath = new_fullpath;
1911 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1914 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1917 return (*assembly != NULL);
1920 static MonoAssembly *
1921 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1923 MonoAssembly *result = NULL;
1926 const gchar *local_culture;
1928 gboolean is_private = FALSE;
1930 if (!culture || *culture == '\0') {
1933 local_culture = culture;
1936 filename = g_strconcat (name, ".dll", NULL);
1937 len = strlen (filename);
1939 for (path = search_path; *path; path++) {
1940 if (**path == '\0') {
1942 continue; /* Ignore empty ApplicationBase */
1945 /* See test cases in bug #58992 and bug #57710 */
1946 /* 1st try: [culture]/[name].dll (culture may be empty) */
1947 strcpy (filename + len - 4, ".dll");
1948 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1951 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1952 strcpy (filename + len - 4, ".exe");
1953 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1956 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1957 strcpy (filename + len - 4, ".dll");
1958 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1961 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1962 strcpy (filename + len - 4, ".exe");
1963 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1972 * Try loading the assembly from ApplicationBase and PrivateBinPath
1973 * and then from assemblies_path if any.
1974 * LOCKING: This is called from the assembly loading code, which means the caller
1975 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1977 static MonoAssembly *
1978 mono_domain_assembly_preload (MonoAssemblyName *aname,
1979 gchar **assemblies_path,
1982 MonoDomain *domain = mono_domain_get ();
1983 MonoAssembly *result = NULL;
1984 gboolean refonly = GPOINTER_TO_UINT (user_data);
1986 set_domain_search_path (domain);
1988 if (domain->search_path && domain->search_path [0] != NULL) {
1989 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
1990 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
1991 for (int i = 0; domain->search_path [i]; i++) {
1992 const char *p = domain->search_path[i];
1993 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
1995 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
1997 result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2000 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2001 result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2008 * Check whenever a given assembly was already loaded in the current appdomain.
2010 static MonoAssembly *
2011 mono_domain_assembly_search (MonoAssemblyName *aname,
2014 MonoDomain *domain = mono_domain_get ();
2017 gboolean refonly = GPOINTER_TO_UINT (user_data);
2019 mono_domain_assemblies_lock (domain);
2020 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2021 ass = (MonoAssembly *)tmp->data;
2022 /* Dynamic assemblies can't match here in MS.NET */
2023 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2026 mono_domain_assemblies_unlock (domain);
2029 mono_domain_assemblies_unlock (domain);
2034 MonoReflectionAssemblyHandle
2035 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2038 MonoDomain *domain = mono_domain_get ();
2039 char *name, *filename;
2040 MonoImageOpenStatus status = MONO_IMAGE_OK;
2041 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2046 if (fname == NULL) {
2047 mono_error_set_argument_null (error, "assemblyFile", "");
2051 name = filename = mono_string_handle_to_utf8 (fname, error);
2055 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2058 if (status == MONO_IMAGE_IMAGE_INVALID)
2059 mono_error_set_bad_image_name (error, g_strdup (name), "");
2061 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2065 result = mono_assembly_get_object_handle (domain, ass, error);
2072 MonoReflectionAssemblyHandle
2073 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2074 MonoArrayHandle raw_assembly,
2075 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2076 MonoBoolean refonly,
2081 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2082 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2083 MonoImageOpenStatus status;
2084 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2086 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2087 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2088 if (!assembly_data) {
2089 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2093 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2094 memcpy (assembly_data, raw_data, raw_assembly_len);
2095 mono_gchandle_free (gchandle); /* unpin */
2096 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2098 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2101 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2105 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2106 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2107 uint32_t symbol_gchandle;
2108 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2109 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2110 mono_gchandle_free (symbol_gchandle);
2113 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2117 mono_image_close (image);
2118 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2122 refass = mono_assembly_get_object_handle (domain, ass, error);
2123 if (!MONO_HANDLE_IS_NULL(refass))
2124 MONO_HANDLE_SET (refass, evidence, evidence);
2128 MonoReflectionAssemblyHandle
2129 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2132 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2133 MonoImageOpenStatus status = MONO_IMAGE_OK;
2135 MonoAssemblyName aname;
2141 name = mono_string_handle_to_utf8 (assRef, error);
2144 parsed = mono_assembly_name_parse (name, &aname);
2148 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2149 /* This is a parse error... */
2151 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2155 refass = mono_assembly_get_object_handle (domain, assm, error);
2163 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2164 mono_assembly_name_free (&aname);
2167 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2169 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2178 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2182 MONO_HANDLE_SET (refass, evidence, evidence);
2186 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2190 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2193 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2195 if (NULL == domain) {
2196 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2200 if (domain == mono_get_root_domain ()) {
2201 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2206 * Unloading seems to cause problems when running NUnit/NAnt, hence
2209 if (g_getenv ("MONO_NO_UNLOAD"))
2211 #ifdef __native_client__
2215 MonoException *exc = NULL;
2216 mono_domain_try_unload (domain, (MonoObject**)&exc);
2218 mono_error_set_exception_instance (error, exc);
2222 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2225 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2230 return mono_domain_is_unloading (domain);
2234 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2236 mono_unhandled_exception ((MonoObject*) exc);
2240 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2241 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2248 g_assert (!MONO_HANDLE_IS_NULL (refass));
2249 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2250 image = assembly->image;
2253 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2256 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2258 if (MONO_HANDLE_IS_NULL (args)) {
2259 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2260 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2261 mono_error_assert_ok (error);
2264 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2269 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2271 return ad->data->domain_id;
2275 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2278 MonoDomain *old_domain = mono_domain_get ();
2280 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2281 mono_error_set_appdomain_unloaded (error);
2282 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2285 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2289 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2291 MonoDomain *current_domain = mono_domain_get ();
2292 MonoDomain *domain = mono_domain_get_by_id (domainid);
2294 if (!domain || !mono_domain_set (domain, FALSE)) {
2295 mono_error_set_appdomain_unloaded (error);
2296 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2299 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2303 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2306 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2310 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2313 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2317 * Raise an exception to prevent the managed code from executing a pop
2320 mono_error_set_appdomain_unloaded (error);
2324 mono_thread_push_appdomain_ref (domain);
2328 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2331 mono_thread_pop_appdomain_ref ();
2335 ves_icall_System_AppDomain_InternalGetContext ()
2337 return mono_context_get ();
2341 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2343 return mono_domain_get ()->default_context;
2347 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2349 MonoAppContext *old_context = mono_context_get ();
2351 mono_context_set (mc);
2357 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2360 MonoDomain* mono_root_domain = mono_get_root_domain ();
2361 mono_domain_lock (mono_root_domain);
2362 if (process_guid_set) {
2363 mono_domain_unlock (mono_root_domain);
2364 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2366 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2367 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2368 mono_gchandle_free (gchandle);
2369 process_guid_set = TRUE;
2370 mono_domain_unlock (mono_root_domain);
2375 mono_domain_is_unloading (MonoDomain *domain)
2377 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2384 clear_cached_vtable (MonoVTable *vtable)
2386 MonoClass *klass = vtable->klass;
2387 MonoDomain *domain = vtable->domain;
2388 MonoClassRuntimeInfo *runtime_info;
2391 runtime_info = klass->runtime_info;
2392 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2393 runtime_info->domain_vtables [domain->domain_id] = NULL;
2394 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2395 mono_gc_free_fixed (data);
2398 static G_GNUC_UNUSED void
2399 zero_static_data (MonoVTable *vtable)
2401 MonoClass *klass = vtable->klass;
2404 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2405 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2408 typedef struct unload_data {
2411 char *failure_reason;
2416 unload_data_unref (unload_data *data)
2420 mono_atomic_load_acquire (count, gint32, &data->refcount);
2421 g_assert (count >= 1 && count <= 2);
2426 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2430 deregister_reflection_info_roots_from_list (MonoImage *image)
2432 GSList *list = image->reflection_info_unregister_classes;
2435 MonoClass *klass = (MonoClass *)list->data;
2437 mono_class_free_ref_info (klass);
2442 image->reflection_info_unregister_classes = NULL;
2446 deregister_reflection_info_roots (MonoDomain *domain)
2450 mono_domain_assemblies_lock (domain);
2451 for (list = domain->domain_assemblies; list; list = list->next) {
2452 MonoAssembly *assembly = (MonoAssembly *)list->data;
2453 MonoImage *image = assembly->image;
2457 * No need to take the image lock here since dynamic images are appdomain bound and
2458 * at this point the mutator is gone. Taking the image lock here would mean
2459 * promoting it from a simple lock to a complex lock, which we better avoid if
2462 if (image_is_dynamic (image))
2463 deregister_reflection_info_roots_from_list (image);
2465 for (i = 0; i < image->module_count; ++i) {
2466 MonoImage *module = image->modules [i];
2467 if (module && image_is_dynamic (module))
2468 deregister_reflection_info_roots_from_list (module);
2471 mono_domain_assemblies_unlock (domain);
2475 unload_thread_main (void *arg)
2478 unload_data *data = (unload_data*)arg;
2479 MonoDomain *domain = data->domain;
2480 MonoInternalThread *internal;
2483 internal = mono_thread_internal_current ();
2485 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2486 if (!is_ok (&error)) {
2487 data->failure_reason = g_strdup (mono_error_get_message (&error));
2488 mono_error_cleanup (&error);
2493 * FIXME: Abort our parent thread last, so we can return a failure
2494 * indication if aborting times out.
2496 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2497 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2501 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2502 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2506 /* Finalize all finalizable objects in the doomed appdomain */
2507 if (!mono_domain_finalize (domain, -1)) {
2508 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2512 /* Clear references to our vtables in class->runtime_info.
2513 * We also hold the loader lock because we're going to change
2514 * class->runtime_info.
2517 mono_loader_lock (); //FIXME why do we need the loader lock here?
2518 mono_domain_lock (domain);
2521 * We need to make sure that we don't have any remsets
2522 * pointing into static data of the to-be-freed domain because
2523 * at the next collections they would be invalid. So what we
2524 * do is we first zero all static data and then do a minor
2525 * collection. Because all references in the static data will
2526 * now be null we won't do any unnecessary copies and after
2527 * the collection there won't be any more remsets.
2529 for (i = 0; i < domain->class_vtable_array->len; ++i)
2530 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2531 mono_gc_collect (0);
2533 for (i = 0; i < domain->class_vtable_array->len; ++i)
2534 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2535 deregister_reflection_info_roots (domain);
2537 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2539 mono_domain_unlock (domain);
2540 mono_loader_unlock ();
2542 domain->state = MONO_APPDOMAIN_UNLOADED;
2544 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2546 /* remove from the handle table the items related to this domain */
2547 mono_gchandle_free_domain (domain);
2549 mono_domain_free (domain, FALSE);
2551 mono_gc_collect (mono_gc_max_generation ());
2553 mono_atomic_store_release (&data->done, TRUE);
2554 unload_data_unref (data);
2558 mono_atomic_store_release (&data->done, TRUE);
2559 unload_data_unref (data);
2564 * mono_domain_unload:
2565 * @domain: The domain to unload
2567 * Unloads an appdomain. Follows the process outlined in the comment
2568 * for mono_domain_try_unload.
2571 mono_domain_unload (MonoDomain *domain)
2573 MonoObject *exc = NULL;
2574 mono_domain_try_unload (domain, &exc);
2577 static MonoThreadInfoWaitRet
2578 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2580 MonoThreadInfoWaitRet result;
2583 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2590 * mono_domain_unload:
2591 * @domain: The domain to unload
2592 * @exc: Exception information
2594 * Unloads an appdomain. Follows the process outlined in:
2595 * http://blogs.gotdotnet.com/cbrumme
2597 * If doing things the 'right' way is too hard or complex, we do it the
2598 * 'simple' way, which means do everything needed to avoid crashes and
2599 * memory leaks, but not much else.
2601 * It is required to pass a valid reference to the exc argument, upon return
2602 * from this function *exc will be set to the exception thrown, if any.
2604 * If this method is not called from an icall (embedded scenario for instance),
2605 * it must not be called with any managed frames on the stack, since the unload
2606 * process could end up trying to abort the current thread.
2609 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2612 MonoThreadHandle *thread_handle;
2613 MonoAppDomainState prev_state;
2615 unload_data *thread_data;
2616 MonoInternalThread *internal;
2617 MonoDomain *caller_domain = mono_domain_get ();
2619 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2621 /* Atomically change our state to UNLOADING */
2622 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2623 MONO_APPDOMAIN_UNLOADING_START,
2624 MONO_APPDOMAIN_CREATED);
2625 if (prev_state != MONO_APPDOMAIN_CREATED) {
2626 switch (prev_state) {
2627 case MONO_APPDOMAIN_UNLOADING_START:
2628 case MONO_APPDOMAIN_UNLOADING:
2629 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2631 case MONO_APPDOMAIN_UNLOADED:
2632 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2635 g_warning ("Invalid appdomain state %d", prev_state);
2636 g_assert_not_reached ();
2640 mono_domain_set (domain, FALSE);
2641 /* Notify OnDomainUnload listeners */
2642 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2645 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2647 if (!mono_error_ok (&error)) {
2649 mono_error_cleanup (&error);
2651 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2655 /* Roll back the state change */
2656 domain->state = MONO_APPDOMAIN_CREATED;
2657 mono_domain_set (caller_domain, FALSE);
2660 mono_domain_set (caller_domain, FALSE);
2662 thread_data = g_new0 (unload_data, 1);
2663 thread_data->domain = domain;
2664 thread_data->failure_reason = NULL;
2665 thread_data->done = FALSE;
2666 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2668 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2669 domain->state = MONO_APPDOMAIN_UNLOADING;
2671 * First we create a separate thread for unloading, since
2672 * we might have to abort some threads, including the current one.
2674 * Have to attach to the runtime so shutdown can wait for this thread.
2676 * Force it to be attached to avoid racing during shutdown.
2678 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2679 mono_error_assert_ok (&error);
2681 thread_handle = mono_threads_open_thread_handle (internal->handle);
2683 /* Wait for the thread */
2684 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2685 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2686 /* The unload thread tries to abort us */
2687 /* The icall wrapper will execute the abort */
2688 mono_threads_close_thread_handle (thread_handle);
2689 unload_data_unref (thread_data);
2694 mono_threads_close_thread_handle (thread_handle);
2696 if (thread_data->failure_reason) {
2697 /* Roll back the state change */
2698 domain->state = MONO_APPDOMAIN_CREATED;
2700 g_warning ("%s", thread_data->failure_reason);
2702 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2704 g_free (thread_data->failure_reason);
2705 thread_data->failure_reason = NULL;
2708 unload_data_unref (thread_data);