6 * Dietmar Maurer (dietmar@ximian.com)
8 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2012 Xamarin Inc
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #undef ASSEMBLY_LOAD_DEBUG
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_TIME_H
32 #ifdef HAVE_SYS_UTIME_H
33 #include <sys/utime.h>
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/domain-internals.h>
41 #include "mono/metadata/metadata-internals.h"
42 #include <mono/metadata/assembly-internals.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/exception-internals.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/marshal-internals.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
82 int assemblybinding_count;
87 static gunichar2 process_guid [36];
88 static gboolean process_guid_set = FALSE;
90 static gboolean no_exec = FALSE;
93 mono_domain_assembly_preload (MonoAssemblyName *aname,
94 gchar **assemblies_path,
98 mono_domain_assembly_search (MonoAssemblyName *aname,
102 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
105 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
107 static MonoAppDomainHandle
108 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
111 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
115 mono_context_set_default_context (MonoDomain *domain);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
125 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
128 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
131 mono_error_set_appdomain_unloaded (MonoError *error)
133 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
137 mono_install_runtime_load (MonoLoadFunc func)
139 load_function = func;
143 mono_runtime_load (const char *filename, const char *runtime_version)
145 g_assert (load_function);
146 return load_function (filename, runtime_version);
150 * mono_runtime_set_no_exec:
152 * Instructs the runtime to operate in static mode, i.e. avoid/do not
153 * allow managed code execution. This is useful for running the AOT
154 * compiler on platforms which allow full-aot execution only. This
155 * should be called before mono_runtime_init ().
158 mono_runtime_set_no_exec (gboolean val)
164 * mono_runtime_get_no_exec:
166 * If true, then the runtime will not allow managed code execution.
169 mono_runtime_get_no_exec (void)
175 create_domain_objects (MonoDomain *domain)
178 MonoDomain *old_domain = mono_domain_get ();
180 MonoVTable *string_vt;
181 MonoClassField *string_empty_fld;
183 if (domain != old_domain) {
184 mono_thread_push_appdomain_ref (domain);
185 mono_domain_set_internal_with_options (domain, FALSE);
189 * Initialize String.Empty. This enables the removal of
190 * the static cctor of the String class.
192 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
193 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
194 g_assert (string_empty_fld);
195 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
196 mono_error_assert_ok (&error);
197 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
198 domain->empty_string = empty_str;
201 * Create an instance early since we can't do it when there is no memory.
203 arg = mono_string_new (domain, "Out of memory");
204 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
205 mono_error_assert_ok (&error);
208 * These two are needed because the signal handlers might be executing on
209 * an alternate stack, and Boehm GC can't handle that.
211 arg = mono_string_new (domain, "A null value was found where an object instance was required");
212 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
213 mono_error_assert_ok (&error);
214 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
215 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
216 mono_error_assert_ok (&error);
218 /*The ephemeron tombstone i*/
219 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
220 mono_error_assert_ok (&error);
222 if (domain != old_domain) {
223 mono_thread_pop_appdomain_ref ();
224 mono_domain_set_internal_with_options (old_domain, FALSE);
228 * This class is used during exception handling, so initialize it here, to prevent
229 * stack overflows while handling stack overflows.
231 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
236 * \param domain domain returned by \c mono_init
238 * Initialize the core AppDomain: this function will run also some
239 * IL initialization code, so it needs the execution engine to be fully
242 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
243 * we know the \c entry_assembly.
247 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
250 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
251 mono_error_cleanup (&error);
255 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
257 MonoAppDomainSetup *setup;
263 mono_portability_helpers_init ();
265 mono_gc_base_init ();
266 mono_monitor_init ();
267 mono_marshal_init ();
269 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
270 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
271 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
272 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
273 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
274 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
275 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
277 mono_thread_init (start_cb, attach_cb);
279 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
280 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
281 return_if_nok (error);
283 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
285 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
286 return_if_nok (error);
290 domain->setup = setup;
292 mono_thread_attach (domain);
294 mono_type_initialization_init ();
296 if (!mono_runtime_get_no_exec ())
297 create_domain_objects (domain);
299 /* GC init has to happen after thread init */
302 /* contexts use GC handles, so they must be initialized after the GC */
303 mono_context_init_checked (domain, error);
304 return_if_nok (error);
305 mono_context_set_default_context (domain);
307 #ifndef DISABLE_SOCKETS
308 mono_network_init ();
311 mono_console_init ();
314 mono_locks_tracer_init ();
316 /* mscorlib is loaded before we install the load hook */
317 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
323 mono_context_set_default_context (MonoDomain *domain)
325 HANDLE_FUNCTION_ENTER ();
326 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
327 HANDLE_FUNCTION_RETURN ();
332 mono_get_corlib_version (void)
336 MonoClassField *field;
339 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
340 mono_class_init (klass);
341 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
344 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
346 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
347 mono_error_assert_ok (&error);
348 return *(gint32*)((gchar*)value + sizeof (MonoObject));
352 * mono_check_corlib_version:
353 * Checks that the corlib that is loaded matches the version of this runtime.
354 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
355 * allocated string with the error otherwise.
358 mono_check_corlib_version (void)
360 int version = mono_get_corlib_version ();
361 if (version != MONO_CORLIB_VERSION)
362 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
364 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
365 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
366 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
367 if (native_offset != managed_offset)
368 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
375 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
376 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
379 mono_context_init (MonoDomain *domain)
382 mono_context_init_checked (domain, &error);
383 mono_error_cleanup (&error);
387 mono_context_init_checked (MonoDomain *domain, MonoError *error)
390 MonoAppContext *context;
394 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
395 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
396 return_if_nok (error);
398 context->domain_id = domain->domain_id;
399 context->context_id = 0;
400 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
401 domain->default_context = context;
405 * mono_runtime_cleanup:
406 * \param domain unused.
410 * This must not be called while there are still running threads executing
414 mono_runtime_cleanup (MonoDomain *domain)
416 mono_attach_cleanup ();
418 /* This ends up calling any pending pending (for at most 2 seconds) */
421 mono_thread_cleanup ();
423 #ifndef DISABLE_SOCKETS
424 mono_network_cleanup ();
426 mono_marshal_cleanup ();
428 mono_type_initialization_cleanup ();
430 mono_monitor_cleanup ();
433 static MonoDomainFunc quit_function = NULL;
436 * mono_install_runtime_cleanup:
439 mono_install_runtime_cleanup (MonoDomainFunc func)
441 quit_function = func;
450 if (quit_function != NULL)
451 quit_function (mono_get_root_domain (), NULL);
455 * mono_domain_create_appdomain:
456 * \param friendly_name The friendly name of the appdomain to create
457 * \param configuration_file The configuration file to initialize the appdomain with
458 * \returns a \c MonoDomain initialized with the appdomain
461 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
463 HANDLE_FUNCTION_ENTER ();
465 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
466 mono_error_cleanup (&error);
467 HANDLE_FUNCTION_RETURN_VAL (domain);
471 * mono_domain_create_appdomain_checked:
472 * \param friendly_name The friendly name of the appdomain to create
473 * \param configuration_file The configuration file to initialize the appdomain with
474 * \param error Set on error.
476 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
479 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
481 HANDLE_FUNCTION_ENTER ();
483 MonoDomain *result = NULL;
485 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
486 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
489 MonoStringHandle config_file;
490 if (configuration_file != NULL) {
491 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
495 config_file = MONO_HANDLE_NEW (MonoString, NULL);
497 MONO_HANDLE_SET (setup, configuration_file, config_file);
499 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
503 result = mono_domain_from_appdomain_handle (ad);
505 HANDLE_FUNCTION_RETURN_VAL (result);
509 * mono_domain_set_config:
510 * \param domain \c MonoDomain initialized with the appdomain we want to change
511 * \param base_dir new base directory for the appdomain
512 * \param config_file_name path to the new configuration for the app domain
514 * Used to set the system configuration for an appdomain
516 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
517 * Error Initializing the configuration system. ---> System.ArgumentException:
518 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
521 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
523 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
524 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
527 static MonoAppDomainSetupHandle
528 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
530 HANDLE_FUNCTION_ENTER ();
531 MonoDomain *caller_domain;
532 MonoClass *ads_class;
533 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
537 caller_domain = mono_domain_get ();
538 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
540 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
544 mono_domain_set_internal (domain);
546 #define XCOPY_FIELD(dst,field,src,error) \
548 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
549 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
550 if (!is_ok (error)) \
552 MONO_HANDLE_SET ((dst),field,copied_val); \
555 #define COPY_VAL(dst,field,type,src) \
557 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
560 XCOPY_FIELD (copy, application_base, setup, error);
561 XCOPY_FIELD (copy, application_name, setup, error);
562 XCOPY_FIELD (copy, cache_path, setup, error);
563 XCOPY_FIELD (copy, configuration_file, setup, error);
564 XCOPY_FIELD (copy, dynamic_base, setup, error);
565 XCOPY_FIELD (copy, license_file, setup, error);
566 XCOPY_FIELD (copy, private_bin_path, setup, error);
567 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
568 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
569 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
570 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
571 COPY_VAL (copy, path_changed, MonoBoolean, setup);
572 COPY_VAL (copy, loader_optimization, int, setup);
573 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
574 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
575 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
576 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
577 XCOPY_FIELD (copy, application_trust, setup, error);
578 XCOPY_FIELD (copy, configuration_bytes, setup, error);
579 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
584 mono_domain_set_internal (caller_domain);
586 MONO_HANDLE_ASSIGN (result, copy);
588 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
591 static MonoAppDomainHandle
592 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
594 HANDLE_FUNCTION_ENTER ();
595 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
601 adclass = mono_class_get_appdomain_class ();
603 /* FIXME: pin all those objects */
604 data = mono_domain_create();
606 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
609 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
610 data->domain = MONO_HANDLE_RAW (ad);
611 data->friendly_name = g_strdup (friendly_name);
613 mono_profiler_appdomain_name (data, data->friendly_name);
615 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
616 if (MONO_HANDLE_IS_NULL (app_base)) {
617 /* Inherit from the root domain since MS.NET does this */
618 MonoDomain *root = mono_get_root_domain ();
619 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
620 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
621 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
622 /* N.B. new string is in the new domain */
623 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
624 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);
625 mono_gchandle_free (gchandle);
626 if (!is_ok (error)) {
627 g_free (data->friendly_name);
630 MONO_HANDLE_SET (setup, application_base, s);
634 mono_context_init_checked (data, error);
638 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
639 if (!mono_error_ok (error)) {
640 g_free (data->friendly_name);
644 mono_domain_set_options_from_config (data);
645 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
647 #ifndef DISABLE_SHADOW_COPY
648 /*FIXME, guard this for when the debugger is not running */
649 char *shadow_location = get_shadow_assembly_location_base (data, error);
650 if (!mono_error_ok (error)) {
651 g_free (data->friendly_name);
655 g_free (shadow_location);
658 create_domain_objects (data);
660 MONO_HANDLE_ASSIGN (result, ad);
662 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
666 * mono_domain_has_type_resolve:
667 * \param domain application domain being looked up
669 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
672 mono_domain_has_type_resolve (MonoDomain *domain)
674 static MonoClassField *field = NULL;
678 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
682 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
686 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
691 * mono_domain_try_type_resolve:
692 * \param domain application domainwhere the name where the type is going to be resolved
693 * \param name the name of the type to resolve or NULL.
694 * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
696 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
697 * the assembly that matches name.
699 * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
701 * \returns A \c MonoReflectionAssembly or NULL if not found
703 MonoReflectionAssembly *
704 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
707 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
708 mono_error_cleanup (&error);
713 MonoReflectionAssembly *
714 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
716 static MonoMethod *method = NULL;
717 MonoReflectionAssembly *ret;
722 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
724 if (method == NULL) {
725 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
726 if (method == NULL) {
727 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
733 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
737 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
738 return_val_if_nok (error, NULL);
744 * mono_domain_owns_vtable_slot:
745 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
748 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
752 mono_domain_lock (domain);
753 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
754 mono_domain_unlock (domain);
760 * \param domain domain
761 * \param force force setting.
763 * Set the current appdomain to \p domain. If \p force is set, set it even
764 * if it is being unloaded.
766 * \returns TRUE on success; FALSE if the domain is unloaded
769 mono_domain_set (MonoDomain *domain, gboolean force)
771 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
774 mono_domain_set_internal (domain);
780 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
784 if (MONO_HANDLE_IS_NULL (name)) {
785 mono_error_set_argument_null (error, "name", "");
789 g_assert (!MONO_HANDLE_IS_NULL (ad));
790 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
793 char *str = mono_string_handle_to_utf8 (name, error);
794 return_val_if_nok (error, NULL_HANDLE);
796 mono_domain_lock (add);
798 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
800 if (!strcmp (str, "APPBASE"))
801 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
802 else if (!strcmp (str, "APP_CONFIG_FILE"))
803 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
804 else if (!strcmp (str, "DYNAMIC_BASE"))
805 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
806 else if (!strcmp (str, "APP_NAME"))
807 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
808 else if (!strcmp (str, "CACHE_BASE"))
809 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
810 else if (!strcmp (str, "PRIVATE_BINPATH"))
811 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
812 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
813 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
814 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
815 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
816 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
817 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
819 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
821 mono_domain_unlock (add);
824 return MONO_HANDLE_CAST (MonoObject, o);
828 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
832 if (MONO_HANDLE_IS_NULL (name)) {
833 mono_error_set_argument_null (error, "name", "");
837 g_assert (!MONO_HANDLE_IS_NULL (ad));
838 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
841 mono_domain_lock (add);
843 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
845 mono_domain_unlock (add);
848 MonoAppDomainSetupHandle
849 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
852 g_assert (!MONO_HANDLE_IS_NULL (ad));
853 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
856 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
860 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
863 g_assert (!MONO_HANDLE_IS_NULL (ad));
864 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
867 return mono_string_new_handle (domain, domain->friendly_name, error);
871 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
874 MonoDomain *add = mono_domain_get ();
876 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
880 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
883 MonoDomain *root = mono_get_root_domain ();
885 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
889 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
891 MonoDomain *domain = mono_domain_get ();
893 return domain->throw_unobserved_task_exceptions;
897 get_attribute_value (const gchar **attribute_names,
898 const gchar **attribute_values,
899 const char *att_name)
902 for (n = 0; attribute_names [n] != NULL; n++) {
903 if (strcmp (attribute_names [n], att_name) == 0)
904 return g_strdup (attribute_values [n]);
910 start_element (GMarkupParseContext *context,
911 const gchar *element_name,
912 const gchar **attribute_names,
913 const gchar **attribute_values,
917 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
919 if (strcmp (element_name, "runtime") == 0) {
920 runtime_config->runtime_count++;
924 if (strcmp (element_name, "assemblyBinding") == 0) {
925 runtime_config->assemblybinding_count++;
929 if (runtime_config->runtime_count != 1)
932 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
933 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
935 if (value && g_ascii_strcasecmp (value, "true") == 0)
936 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
939 if (runtime_config->assemblybinding_count != 1)
942 if (strcmp (element_name, "probing") != 0)
945 g_free (runtime_config->domain->private_bin_path);
946 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
947 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
948 g_free (runtime_config->domain->private_bin_path);
949 runtime_config->domain->private_bin_path = NULL;
955 end_element (GMarkupParseContext *context,
956 const gchar *element_name,
960 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
961 if (strcmp (element_name, "runtime") == 0)
962 runtime_config->runtime_count--;
963 else if (strcmp (element_name, "assemblyBinding") == 0)
964 runtime_config->assemblybinding_count--;
968 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
970 RuntimeConfig *state = (RuntimeConfig *)user_data;
972 const gchar *filename;
974 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
975 msg = error && error->message ? error->message : "";
976 g_warning ("Error parsing %s: %s", filename, msg);
979 static const GMarkupParser
989 mono_domain_set_options_from_config (MonoDomain *domain)
992 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
994 GMarkupParseContext *context;
995 RuntimeConfig runtime_config;
998 if (!domain || !domain->setup || !domain->setup->configuration_file)
1001 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1002 if (!mono_error_ok (&error)) {
1003 mono_error_cleanup (&error);
1007 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1008 if (!config_file_path)
1009 config_file_path = config_file_name;
1011 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1014 runtime_config.runtime_count = 0;
1015 runtime_config.assemblybinding_count = 0;
1016 runtime_config.domain = domain;
1017 runtime_config.filename = config_file_path;
1020 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1021 offset = 3; /* Skip UTF-8 BOM */
1023 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1024 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1025 g_markup_parse_context_end_parse (context, NULL);
1026 g_markup_parse_context_free (context);
1030 if (config_file_name != config_file_path)
1031 g_free (config_file_name);
1032 g_free (config_file_path);
1036 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1039 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1041 #ifdef DISABLE_APPDOMAINS
1042 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1046 fname = mono_string_handle_to_utf8 (friendly_name, error);
1047 return_val_if_nok (error, ad);
1048 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1055 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1057 HANDLE_FUNCTION_ENTER ();
1059 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1062 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1064 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1068 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1071 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1075 GPtrArray *assemblies;
1078 * Make a copy of the list of assemblies because we can't hold the assemblies
1079 * lock while creating objects etc.
1081 assemblies = g_ptr_array_new ();
1082 /* Need to skip internal assembly builders created by remoting */
1083 mono_domain_assemblies_lock (domain);
1084 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1085 ass = (MonoAssembly *)tmp->data;
1086 if (refonly != ass->ref_only)
1088 if (ass->corlib_internal)
1090 g_ptr_array_add (assemblies, ass);
1092 mono_domain_assemblies_unlock (domain);
1094 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1097 for (i = 0; i < assemblies->len; ++i) {
1098 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1103 g_ptr_array_free (assemblies, TRUE);
1108 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1110 HANDLE_FUNCTION_ENTER ();
1112 MonoAssembly *result = NULL;
1113 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1116 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1118 HANDLE_FUNCTION_RETURN_VAL (result);
1122 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1124 MonoAssembly *ret = NULL;
1126 MonoBoolean isrefonly;
1127 gpointer params [3];
1131 if (mono_runtime_get_no_exec ())
1134 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1136 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1137 g_assert (method != NULL);
1139 isrefonly = refonly ? 1 : 0;
1140 MonoReflectionAssemblyHandle requesting_handle;
1142 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1143 return_val_if_nok (error, ret);
1145 params [0] = MONO_HANDLE_RAW (fname);
1146 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1147 params [2] = &isrefonly;
1148 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1149 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1154 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1158 MonoAssembly *assembly;
1159 MonoDomain *domain = mono_domain_get ();
1162 aname_str = mono_stringify_assembly_name (aname);
1164 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1166 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1168 mono_error_cleanup (&error);
1174 * LOCKING: assumes assemblies_lock in the domain is already locked.
1177 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1181 gboolean destroy_ht = FALSE;
1183 if (!ass->aname.name)
1187 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1189 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1190 g_hash_table_insert (ht, tmp->data, tmp->data);
1194 /* FIXME: handle lazy loaded assemblies */
1196 if (!g_hash_table_lookup (ht, ass)) {
1197 mono_assembly_addref (ass);
1198 g_hash_table_insert (ht, ass, ass);
1199 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1200 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);
1203 if (ass->image->references) {
1204 for (i = 0; i < ass->image->nreferences; i++) {
1205 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1206 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1207 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1213 g_hash_table_destroy (ht);
1217 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1219 static MonoClassField *assembly_load_field;
1220 static MonoMethod *assembly_load_method;
1222 MonoDomain *domain = mono_domain_get ();
1224 gpointer load_value;
1227 if (!domain->domain)
1228 /* This can happen during startup */
1230 #ifdef ASSEMBLY_LOAD_DEBUG
1231 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1233 klass = domain->domain->mbr.obj.vtable->klass;
1235 mono_domain_assemblies_lock (domain);
1236 add_assemblies_to_domain (domain, assembly, NULL);
1237 mono_domain_assemblies_unlock (domain);
1239 if (assembly_load_field == NULL) {
1240 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1241 g_assert (assembly_load_field);
1244 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1245 if (load_value == NULL) {
1246 /* No events waiting to be triggered */
1250 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1251 mono_error_assert_ok (&error);
1253 if (assembly_load_method == NULL) {
1254 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1255 g_assert (assembly_load_method);
1258 *params = MONO_HANDLE_RAW(ref_assembly);
1260 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1261 mono_error_cleanup (&error);
1265 * LOCKING: Acquires the domain assemblies lock.
1268 set_domain_search_path (MonoDomain *domain)
1271 MonoAppDomainSetup *setup;
1273 gchar *search_path = NULL;
1276 gchar **pvt_split = NULL;
1277 GError *gerror = NULL;
1278 gint appbaselen = -1;
1281 * We use the low-level domain assemblies lock, since this is called from
1282 * assembly loads hooks, which means this thread might hold the loader lock.
1284 mono_domain_assemblies_lock (domain);
1286 if (!domain->setup) {
1287 mono_domain_assemblies_unlock (domain);
1291 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1292 mono_domain_assemblies_unlock (domain);
1295 setup = domain->setup;
1296 if (!setup->application_base) {
1297 mono_domain_assemblies_unlock (domain);
1298 return; /* Must set application base to get private path working */
1303 if (setup->private_bin_path) {
1304 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1305 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1306 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1307 mono_error_cleanup (&error);
1308 mono_domain_assemblies_unlock (domain);
1313 if (domain->private_bin_path) {
1314 if (search_path == NULL)
1315 search_path = domain->private_bin_path;
1317 gchar *tmp2 = search_path;
1318 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1325 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1326 * directories relative to ApplicationBase separated by semicolons (see
1327 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1328 * The loop below copes with the fact that some Unix applications may use ':' (or
1329 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1330 * ';' for the subsequent split.
1332 * The issue was reported in bug #81446
1335 #ifndef TARGET_WIN32
1338 slen = strlen (search_path);
1339 for (i = 0; i < slen; i++)
1340 if (search_path [i] == ':')
1341 search_path [i] = ';';
1344 pvt_split = g_strsplit (search_path, ";", 1000);
1345 g_free (search_path);
1346 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1351 g_strfreev (pvt_split);
1353 * Don't do this because the first time is called, the domain
1354 * setup is not finished.
1356 * domain->search_path = g_malloc (sizeof (char *));
1357 * domain->search_path [0] = NULL;
1359 mono_domain_assemblies_unlock (domain);
1363 if (domain->search_path)
1364 g_strfreev (domain->search_path);
1366 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1367 tmp [npaths] = NULL;
1369 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1370 if (!mono_error_ok (&error)) {
1371 mono_error_cleanup (&error);
1372 g_strfreev (pvt_split);
1375 mono_domain_assemblies_unlock (domain);
1379 domain->search_path = tmp;
1381 /* FIXME: is this needed? */
1382 if (strncmp (*tmp, "file://", 7) == 0) {
1388 uri = g_strdup_printf ("file:///%s", uri + 7);
1391 uri = mono_escape_uri_string (tmpuri);
1392 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1398 if (gerror != NULL) {
1399 g_warning ("%s\n", gerror->message);
1400 g_error_free (gerror);
1407 for (i = 1; pvt_split && i < npaths; i++) {
1408 if (g_path_is_absolute (pvt_split [i - 1])) {
1409 tmp [i] = g_strdup (pvt_split [i - 1]);
1411 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1414 if (strchr (tmp [i], '.')) {
1418 reduced = mono_path_canonicalize (tmp [i]);
1419 if (appbaselen == -1)
1420 appbaselen = strlen (tmp [0]);
1422 if (strncmp (tmp [0], reduced, appbaselen)) {
1425 tmp [i] = g_strdup ("");
1435 if (setup->private_bin_path_probe != NULL) {
1437 tmp [0] = g_strdup ("");
1440 domain->setup->path_changed = FALSE;
1442 g_strfreev (pvt_split);
1444 mono_domain_assemblies_unlock (domain);
1447 #ifdef DISABLE_SHADOW_COPY
1449 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1455 mono_make_shadow_copy (const char *filename, MonoError *error)
1458 return (char *) filename;
1462 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1464 guint16 *orig, *dest;
1465 gboolean copy_result;
1468 strcpy (src + srclen - tail_len, extension);
1470 if (IS_PORTABILITY_CASE) {
1471 gchar *file = mono_portability_find_file (src, TRUE);
1477 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1481 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1483 strcpy (target + targetlen - tail_len, extension);
1484 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1486 mono_w32file_delete (dest);
1488 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1490 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1491 * overwritten when updated in their original locations. */
1493 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1502 get_cstring_hash (const char *str)
1508 if (!str || !str [0])
1513 for (i = 0; i < len; i++) {
1514 h = (h << 5) - h + *p;
1522 * Returned memory is malloc'd. Called must free it
1525 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1527 MonoAppDomainSetup *setup;
1528 char *cache_path, *appname;
1534 setup = domain->setup;
1535 if (setup->cache_path != NULL && setup->application_name != NULL) {
1536 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1537 return_val_if_nok (error, NULL);
1539 #ifndef TARGET_WIN32
1542 for (i = strlen (cache_path) - 1; i >= 0; i--)
1543 if (cache_path [i] == '\\')
1544 cache_path [i] = '/';
1548 appname = mono_string_to_utf8_checked (setup->application_name, error);
1549 if (!mono_error_ok (error)) {
1550 g_free (cache_path);
1554 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1556 g_free (cache_path);
1558 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1559 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1566 get_shadow_assembly_location (const char *filename, MonoError *error)
1568 gint32 hash = 0, hash2 = 0;
1570 char path_hash [30];
1571 char *bname = g_path_get_basename (filename);
1572 char *dirname = g_path_get_dirname (filename);
1573 char *location, *tmploc;
1574 MonoDomain *domain = mono_domain_get ();
1578 hash = get_cstring_hash (bname);
1579 hash2 = get_cstring_hash (dirname);
1580 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1581 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1582 tmploc = get_shadow_assembly_location_base (domain, error);
1583 if (!mono_error_ok (error)) {
1589 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1597 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1599 struct stat sbuf_dest;
1601 gchar *real_src = mono_portability_find_file (src, TRUE);
1604 stat_src = (gchar*)src;
1606 stat_src = real_src;
1608 if (stat (stat_src, sbuf_src) == -1) {
1609 time_t tnow = time (NULL);
1614 memset (sbuf_src, 0, sizeof (*sbuf_src));
1615 sbuf_src->st_mtime = tnow;
1616 sbuf_src->st_atime = tnow;
1623 if (stat (dest, &sbuf_dest) == -1)
1626 if (sbuf_src->st_size == sbuf_dest.st_size &&
1627 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1634 shadow_copy_create_ini (const char *shadow, const char *filename)
1644 dir_name = g_path_get_dirname (shadow);
1645 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1647 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1652 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1657 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1659 if (handle == INVALID_HANDLE_VALUE) {
1663 full_path = mono_path_resolve_symlinks (filename);
1664 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1666 mono_w32file_close (handle);
1671 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1674 MonoAppDomainSetup *setup;
1677 gchar **directories;
1678 gchar *shadow_status_string;
1680 gboolean shadow_enabled;
1681 gboolean found = FALSE;
1686 setup = domain->setup;
1687 if (setup == NULL || setup->shadow_copy_files == NULL)
1690 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1691 if (!mono_error_ok (&error)) {
1692 mono_error_cleanup (&error);
1695 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1696 g_free (shadow_status_string);
1698 if (!shadow_enabled)
1701 if (setup->shadow_copy_directories == NULL)
1704 /* Is dir_name a shadow_copy destination already? */
1705 base_dir = get_shadow_assembly_location_base (domain, &error);
1706 if (!mono_error_ok (&error)) {
1707 mono_error_cleanup (&error);
1711 if (strstr (dir_name, base_dir)) {
1717 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1718 if (!mono_error_ok (&error)) {
1719 mono_error_cleanup (&error);
1723 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1724 dir_ptr = directories;
1726 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1732 g_strfreev (directories);
1738 This function raises exceptions so it can cause as sorts of nasty stuff if called
1739 while holding a lock.
1740 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1741 or NULL if source file not found.
1742 FIXME bubble up the error instead of raising it here
1745 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1748 gchar *sibling_source, *sibling_target;
1749 gint sibling_source_len, sibling_target_len;
1750 guint16 *orig, *dest;
1753 gboolean copy_result;
1754 struct stat src_sbuf;
1755 struct utimbuf utbuf;
1756 char *dir_name = g_path_get_dirname (filename);
1757 MonoDomain *domain = mono_domain_get ();
1761 error_init (oerror);
1763 set_domain_search_path (domain);
1765 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1767 return (char *) filename;
1770 /* Is dir_name a shadow_copy destination already? */
1771 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1772 if (!mono_error_ok (&error)) {
1773 mono_error_cleanup (&error);
1775 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1779 if (strstr (dir_name, shadow_dir)) {
1780 g_free (shadow_dir);
1782 return (char *) filename;
1784 g_free (shadow_dir);
1787 shadow = get_shadow_assembly_location (filename, &error);
1788 if (!mono_error_ok (&error)) {
1789 mono_error_cleanup (&error);
1790 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1794 if (g_ensure_directory_exists (shadow) == FALSE) {
1796 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1800 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1801 return (char*) shadow;
1803 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1804 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1805 mono_w32file_delete (dest);
1807 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1808 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1809 * and not have it runtime error" */
1810 attrs = mono_w32file_get_attributes (orig);
1811 if (attrs == INVALID_FILE_ATTRIBUTES) {
1813 return (char *)filename;
1816 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1818 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1819 * overwritten when updated in their original locations. */
1821 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1826 if (copy_result == FALSE) {
1829 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1830 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1831 return NULL; /* file not found, shadow copy failed */
1833 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1837 /* attempt to copy .mdb, .config if they exist */
1838 sibling_source = g_strconcat (filename, ".config", NULL);
1839 sibling_source_len = strlen (sibling_source);
1840 sibling_target = g_strconcat (shadow, ".config", NULL);
1841 sibling_target_len = strlen (sibling_target);
1843 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1845 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1847 g_free (sibling_source);
1848 g_free (sibling_target);
1852 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1856 /* Create a .ini file containing the original assembly location */
1857 if (!shadow_copy_create_ini (shadow, filename)) {
1859 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1863 utbuf.actime = src_sbuf.st_atime;
1864 utbuf.modtime = src_sbuf.st_mtime;
1865 utime (shadow, &utbuf);
1869 #endif /* DISABLE_SHADOW_COPY */
1872 * mono_domain_from_appdomain:
1875 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1877 HANDLE_FUNCTION_ENTER ();
1878 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1879 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1880 HANDLE_FUNCTION_RETURN_VAL (result);
1884 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1886 HANDLE_FUNCTION_ENTER ();
1887 MonoDomain *dom = NULL;
1888 if (MONO_HANDLE_IS_NULL (appdomain))
1891 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1892 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1893 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1895 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1897 dom = MONO_HANDLE_GETVAL (appdomain, data);
1900 HANDLE_FUNCTION_RETURN_VAL (dom);
1905 try_load_from (MonoAssembly **assembly,
1906 const gchar *path1, const gchar *path2,
1907 const gchar *path3, const gchar *path4,
1908 gboolean refonly, gboolean is_private,
1909 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1912 gboolean found = FALSE;
1915 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1917 if (IS_PORTABILITY_SET) {
1918 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1921 fullpath = new_fullpath;
1925 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1928 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1931 return (*assembly != NULL);
1934 static MonoAssembly *
1935 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1937 MonoAssembly *result = NULL;
1940 const gchar *local_culture;
1942 gboolean is_private = FALSE;
1944 if (!culture || *culture == '\0') {
1947 local_culture = culture;
1950 filename = g_strconcat (name, ".dll", NULL);
1951 len = strlen (filename);
1953 for (path = search_path; *path; path++) {
1954 if (**path == '\0') {
1956 continue; /* Ignore empty ApplicationBase */
1959 /* See test cases in bug #58992 and bug #57710 */
1960 /* 1st try: [culture]/[name].dll (culture may be empty) */
1961 strcpy (filename + len - 4, ".dll");
1962 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1965 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1966 strcpy (filename + len - 4, ".exe");
1967 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1970 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1971 strcpy (filename + len - 4, ".dll");
1972 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1975 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1976 strcpy (filename + len - 4, ".exe");
1977 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1986 * Try loading the assembly from ApplicationBase and PrivateBinPath
1987 * and then from assemblies_path if any.
1988 * LOCKING: This is called from the assembly loading code, which means the caller
1989 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1991 static MonoAssembly *
1992 mono_domain_assembly_preload (MonoAssemblyName *aname,
1993 gchar **assemblies_path,
1996 MonoDomain *domain = mono_domain_get ();
1997 MonoAssembly *result = NULL;
1998 gboolean refonly = GPOINTER_TO_UINT (user_data);
2000 set_domain_search_path (domain);
2002 if (domain->search_path && domain->search_path [0] != NULL) {
2003 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2004 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2005 for (int i = 0; domain->search_path [i]; i++) {
2006 const char *p = domain->search_path[i];
2007 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2009 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2011 result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2014 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2015 result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2022 * Check whenever a given assembly was already loaded in the current appdomain.
2024 static MonoAssembly *
2025 mono_domain_assembly_search (MonoAssemblyName *aname,
2028 MonoDomain *domain = mono_domain_get ();
2031 gboolean refonly = GPOINTER_TO_UINT (user_data);
2033 mono_domain_assemblies_lock (domain);
2034 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2035 ass = (MonoAssembly *)tmp->data;
2036 /* Dynamic assemblies can't match here in MS.NET */
2037 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2040 mono_domain_assemblies_unlock (domain);
2043 mono_domain_assemblies_unlock (domain);
2048 MonoReflectionAssemblyHandle
2049 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2052 MonoDomain *domain = mono_domain_get ();
2053 char *name, *filename;
2054 MonoImageOpenStatus status = MONO_IMAGE_OK;
2055 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2060 if (fname == NULL) {
2061 mono_error_set_argument_null (error, "assemblyFile", "");
2065 name = filename = mono_string_handle_to_utf8 (fname, error);
2069 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2072 if (status == MONO_IMAGE_IMAGE_INVALID)
2073 mono_error_set_bad_image_name (error, g_strdup (name), "");
2075 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2079 result = mono_assembly_get_object_handle (domain, ass, error);
2086 MonoReflectionAssemblyHandle
2087 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2088 MonoArrayHandle raw_assembly,
2089 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2090 MonoBoolean refonly,
2095 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2096 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2097 MonoImageOpenStatus status;
2098 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2100 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2101 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2102 if (!assembly_data) {
2103 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2107 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2108 memcpy (assembly_data, raw_data, raw_assembly_len);
2109 mono_gchandle_free (gchandle); /* unpin */
2110 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2112 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2115 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2119 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2120 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2121 uint32_t symbol_gchandle;
2122 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2123 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2124 mono_gchandle_free (symbol_gchandle);
2127 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2131 mono_image_close (image);
2132 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2136 refass = mono_assembly_get_object_handle (domain, ass, error);
2137 if (!MONO_HANDLE_IS_NULL(refass))
2138 MONO_HANDLE_SET (refass, evidence, evidence);
2142 MonoReflectionAssemblyHandle
2143 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2146 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2147 MonoImageOpenStatus status = MONO_IMAGE_OK;
2149 MonoAssemblyName aname;
2155 name = mono_string_handle_to_utf8 (assRef, error);
2158 parsed = mono_assembly_name_parse (name, &aname);
2162 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2163 /* This is a parse error... */
2165 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2169 refass = mono_assembly_get_object_handle (domain, assm, error);
2177 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2178 mono_assembly_name_free (&aname);
2181 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2183 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2192 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2196 MONO_HANDLE_SET (refass, evidence, evidence);
2200 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2204 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2207 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2209 if (NULL == domain) {
2210 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2214 if (domain == mono_get_root_domain ()) {
2215 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2220 * Unloading seems to cause problems when running NUnit/NAnt, hence
2223 if (g_hasenv ("MONO_NO_UNLOAD"))
2226 #ifdef __native_client__
2230 MonoException *exc = NULL;
2231 mono_domain_try_unload (domain, (MonoObject**)&exc);
2233 mono_error_set_exception_instance (error, exc);
2237 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2240 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2245 return mono_domain_is_unloading (domain);
2249 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2251 mono_unhandled_exception ((MonoObject*) exc);
2255 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2256 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2263 g_assert (!MONO_HANDLE_IS_NULL (refass));
2264 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2265 image = assembly->image;
2268 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2271 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2273 if (MONO_HANDLE_IS_NULL (args)) {
2274 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2275 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2276 mono_error_assert_ok (error);
2279 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2284 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2286 return ad->data->domain_id;
2290 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2293 MonoDomain *old_domain = mono_domain_get ();
2295 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2296 mono_error_set_appdomain_unloaded (error);
2297 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2300 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2304 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2306 MonoDomain *current_domain = mono_domain_get ();
2307 MonoDomain *domain = mono_domain_get_by_id (domainid);
2309 if (!domain || !mono_domain_set (domain, FALSE)) {
2310 mono_error_set_appdomain_unloaded (error);
2311 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2314 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2318 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2321 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2325 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2328 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2332 * Raise an exception to prevent the managed code from executing a pop
2335 mono_error_set_appdomain_unloaded (error);
2339 mono_thread_push_appdomain_ref (domain);
2343 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2346 mono_thread_pop_appdomain_ref ();
2349 MonoAppContextHandle
2350 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2353 return mono_context_get_handle ();
2356 MonoAppContextHandle
2357 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2360 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2363 MonoAppContextHandle
2364 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2367 MonoAppContextHandle old_context = mono_context_get_handle ();
2369 mono_context_set_handle (mc);
2375 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2378 MonoDomain* mono_root_domain = mono_get_root_domain ();
2379 mono_domain_lock (mono_root_domain);
2380 if (process_guid_set) {
2381 mono_domain_unlock (mono_root_domain);
2382 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2384 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2385 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2386 mono_gchandle_free (gchandle);
2387 process_guid_set = TRUE;
2388 mono_domain_unlock (mono_root_domain);
2393 * mono_domain_is_unloading:
2396 mono_domain_is_unloading (MonoDomain *domain)
2398 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2405 clear_cached_vtable (MonoVTable *vtable)
2407 MonoClass *klass = vtable->klass;
2408 MonoDomain *domain = vtable->domain;
2409 MonoClassRuntimeInfo *runtime_info;
2412 runtime_info = klass->runtime_info;
2413 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2414 runtime_info->domain_vtables [domain->domain_id] = NULL;
2415 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2416 mono_gc_free_fixed (data);
2419 static G_GNUC_UNUSED void
2420 zero_static_data (MonoVTable *vtable)
2422 MonoClass *klass = vtable->klass;
2425 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2426 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2429 typedef struct unload_data {
2432 char *failure_reason;
2437 unload_data_unref (unload_data *data)
2441 mono_atomic_load_acquire (count, gint32, &data->refcount);
2442 g_assert (count >= 1 && count <= 2);
2447 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2451 deregister_reflection_info_roots_from_list (MonoImage *image)
2453 GSList *list = image->reflection_info_unregister_classes;
2456 MonoClass *klass = (MonoClass *)list->data;
2458 mono_class_free_ref_info (klass);
2463 image->reflection_info_unregister_classes = NULL;
2467 deregister_reflection_info_roots (MonoDomain *domain)
2471 mono_domain_assemblies_lock (domain);
2472 for (list = domain->domain_assemblies; list; list = list->next) {
2473 MonoAssembly *assembly = (MonoAssembly *)list->data;
2474 MonoImage *image = assembly->image;
2478 * No need to take the image lock here since dynamic images are appdomain bound and
2479 * at this point the mutator is gone. Taking the image lock here would mean
2480 * promoting it from a simple lock to a complex lock, which we better avoid if
2483 if (image_is_dynamic (image))
2484 deregister_reflection_info_roots_from_list (image);
2486 for (i = 0; i < image->module_count; ++i) {
2487 MonoImage *module = image->modules [i];
2488 if (module && image_is_dynamic (module))
2489 deregister_reflection_info_roots_from_list (module);
2492 mono_domain_assemblies_unlock (domain);
2496 unload_thread_main (void *arg)
2499 unload_data *data = (unload_data*)arg;
2500 MonoDomain *domain = data->domain;
2501 MonoInternalThread *internal;
2504 internal = mono_thread_internal_current ();
2506 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2507 if (!is_ok (&error)) {
2508 data->failure_reason = g_strdup (mono_error_get_message (&error));
2509 mono_error_cleanup (&error);
2514 * FIXME: Abort our parent thread last, so we can return a failure
2515 * indication if aborting times out.
2517 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2518 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2522 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2523 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2527 /* Finalize all finalizable objects in the doomed appdomain */
2528 if (!mono_domain_finalize (domain, -1)) {
2529 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2533 /* Clear references to our vtables in class->runtime_info.
2534 * We also hold the loader lock because we're going to change
2535 * class->runtime_info.
2538 mono_loader_lock (); //FIXME why do we need the loader lock here?
2539 mono_domain_lock (domain);
2542 * We need to make sure that we don't have any remsets
2543 * pointing into static data of the to-be-freed domain because
2544 * at the next collections they would be invalid. So what we
2545 * do is we first zero all static data and then do a minor
2546 * collection. Because all references in the static data will
2547 * now be null we won't do any unnecessary copies and after
2548 * the collection there won't be any more remsets.
2550 for (i = 0; i < domain->class_vtable_array->len; ++i)
2551 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2552 mono_gc_collect (0);
2554 for (i = 0; i < domain->class_vtable_array->len; ++i)
2555 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2556 deregister_reflection_info_roots (domain);
2558 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2560 mono_domain_unlock (domain);
2561 mono_loader_unlock ();
2563 domain->state = MONO_APPDOMAIN_UNLOADED;
2565 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2567 /* remove from the handle table the items related to this domain */
2568 mono_gchandle_free_domain (domain);
2570 mono_domain_free (domain, FALSE);
2572 mono_gc_collect (mono_gc_max_generation ());
2574 mono_atomic_store_release (&data->done, TRUE);
2575 unload_data_unref (data);
2579 mono_atomic_store_release (&data->done, TRUE);
2580 unload_data_unref (data);
2585 * mono_domain_unload:
2586 * \param domain The domain to unload
2588 * Unloads an appdomain. Follows the process outlined in the comment
2589 * for \c mono_domain_try_unload.
2592 mono_domain_unload (MonoDomain *domain)
2594 MonoObject *exc = NULL;
2595 mono_domain_try_unload (domain, &exc);
2598 static MonoThreadInfoWaitRet
2599 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2601 MonoThreadInfoWaitRet result;
2604 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2611 * mono_domain_unload:
2612 * \param domain The domain to unload
2613 * \param exc Exception information
2615 * Unloads an appdomain. Follows the process outlined in:
2616 * http://blogs.gotdotnet.com/cbrumme
2618 * If doing things the 'right' way is too hard or complex, we do it the
2619 * 'simple' way, which means do everything needed to avoid crashes and
2620 * memory leaks, but not much else.
2622 * It is required to pass a valid reference to the exc argument, upon return
2623 * from this function *exc will be set to the exception thrown, if any.
2625 * If this method is not called from an icall (embedded scenario for instance),
2626 * it must not be called with any managed frames on the stack, since the unload
2627 * process could end up trying to abort the current thread.
2630 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2633 MonoThreadHandle *thread_handle;
2634 MonoAppDomainState prev_state;
2636 unload_data *thread_data;
2637 MonoInternalThread *internal;
2638 MonoDomain *caller_domain = mono_domain_get ();
2640 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2642 /* Atomically change our state to UNLOADING */
2643 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2644 MONO_APPDOMAIN_UNLOADING_START,
2645 MONO_APPDOMAIN_CREATED);
2646 if (prev_state != MONO_APPDOMAIN_CREATED) {
2647 switch (prev_state) {
2648 case MONO_APPDOMAIN_UNLOADING_START:
2649 case MONO_APPDOMAIN_UNLOADING:
2650 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2652 case MONO_APPDOMAIN_UNLOADED:
2653 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2656 g_warning ("Invalid appdomain state %d", prev_state);
2657 g_assert_not_reached ();
2661 mono_domain_set (domain, FALSE);
2662 /* Notify OnDomainUnload listeners */
2663 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2666 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2668 if (!mono_error_ok (&error)) {
2670 mono_error_cleanup (&error);
2672 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2676 /* Roll back the state change */
2677 domain->state = MONO_APPDOMAIN_CREATED;
2678 mono_domain_set (caller_domain, FALSE);
2681 mono_domain_set (caller_domain, FALSE);
2683 thread_data = g_new0 (unload_data, 1);
2684 thread_data->domain = domain;
2685 thread_data->failure_reason = NULL;
2686 thread_data->done = FALSE;
2687 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2689 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2690 domain->state = MONO_APPDOMAIN_UNLOADING;
2692 * First we create a separate thread for unloading, since
2693 * we might have to abort some threads, including the current one.
2695 * Have to attach to the runtime so shutdown can wait for this thread.
2697 * Force it to be attached to avoid racing during shutdown.
2699 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2700 mono_error_assert_ok (&error);
2702 thread_handle = mono_threads_open_thread_handle (internal->handle);
2704 /* Wait for the thread */
2705 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2706 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2707 /* The unload thread tries to abort us */
2708 /* The icall wrapper will execute the abort */
2709 mono_threads_close_thread_handle (thread_handle);
2710 unload_data_unref (thread_data);
2715 mono_threads_close_thread_handle (thread_handle);
2717 if (thread_data->failure_reason) {
2718 /* Roll back the state change */
2719 domain->state = MONO_APPDOMAIN_CREATED;
2721 g_warning ("%s", thread_data->failure_reason);
2723 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2725 g_free (thread_data->failure_reason);
2726 thread_data->failure_reason = NULL;
2729 unload_data_unref (thread_data);