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_new_checked (domain, "", &error);
196 mono_error_assert_ok (&error);
197 empty_str = mono_string_intern_checked (empty_str, &error);
198 mono_error_assert_ok (&error);
199 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
200 domain->empty_string = empty_str;
203 * Create an instance early since we can't do it when there is no memory.
205 arg = mono_string_new_checked (domain, "Out of memory", &error);
206 mono_error_assert_ok (&error);
207 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
208 mono_error_assert_ok (&error);
211 * These two are needed because the signal handlers might be executing on
212 * an alternate stack, and Boehm GC can't handle that.
214 arg = mono_string_new_checked (domain, "A null value was found where an object instance was required", &error);
215 mono_error_assert_ok (&error);
216 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
217 mono_error_assert_ok (&error);
218 arg = mono_string_new_checked (domain, "The requested operation caused a stack overflow.", &error);
219 mono_error_assert_ok (&error);
220 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
221 mono_error_assert_ok (&error);
223 /*The ephemeron tombstone i*/
224 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
225 mono_error_assert_ok (&error);
227 if (domain != old_domain) {
228 mono_thread_pop_appdomain_ref ();
229 mono_domain_set_internal_with_options (old_domain, FALSE);
233 * This class is used during exception handling, so initialize it here, to prevent
234 * stack overflows while handling stack overflows.
236 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
241 * \param domain domain returned by \c mono_init
243 * Initialize the core AppDomain: this function will run also some
244 * IL initialization code, so it needs the execution engine to be fully
247 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
248 * we know the \c entry_assembly.
252 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
255 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
256 mono_error_cleanup (&error);
260 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
262 MonoAppDomainSetup *setup;
268 mono_portability_helpers_init ();
270 mono_gc_base_init ();
271 mono_monitor_init ();
272 mono_marshal_init ();
274 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
275 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
276 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
277 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
278 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
279 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
280 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
282 mono_thread_init (start_cb, attach_cb);
284 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
285 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
286 return_if_nok (error);
288 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
290 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
291 return_if_nok (error);
295 domain->setup = setup;
297 mono_thread_attach (domain);
299 mono_type_initialization_init ();
301 if (!mono_runtime_get_no_exec ())
302 create_domain_objects (domain);
304 /* GC init has to happen after thread init */
307 /* contexts use GC handles, so they must be initialized after the GC */
308 mono_context_init_checked (domain, error);
309 return_if_nok (error);
310 mono_context_set_default_context (domain);
312 #ifndef DISABLE_SOCKETS
313 mono_network_init ();
316 mono_console_init ();
319 mono_locks_tracer_init ();
321 /* mscorlib is loaded before we install the load hook */
322 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
328 mono_context_set_default_context (MonoDomain *domain)
330 HANDLE_FUNCTION_ENTER ();
331 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
332 HANDLE_FUNCTION_RETURN ();
337 mono_get_corlib_version (void)
341 MonoClassField *field;
344 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
345 mono_class_init (klass);
346 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
349 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
351 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
352 mono_error_assert_ok (&error);
353 return *(gint32*)((gchar*)value + sizeof (MonoObject));
357 * mono_check_corlib_version:
358 * Checks that the corlib that is loaded matches the version of this runtime.
359 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
360 * allocated string with the error otherwise.
363 mono_check_corlib_version (void)
365 int version = mono_get_corlib_version ();
366 if (version != MONO_CORLIB_VERSION)
367 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
369 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
370 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
371 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
372 if (native_offset != managed_offset)
373 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
380 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
381 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
384 mono_context_init (MonoDomain *domain)
387 mono_context_init_checked (domain, &error);
388 mono_error_cleanup (&error);
392 mono_context_init_checked (MonoDomain *domain, MonoError *error)
395 MonoAppContext *context;
399 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
400 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
401 return_if_nok (error);
403 context->domain_id = domain->domain_id;
404 context->context_id = 0;
405 mono_threads_register_app_context (context, error);
406 mono_error_assert_ok (error);
407 domain->default_context = context;
411 * mono_runtime_cleanup:
412 * \param domain unused.
416 * This must not be called while there are still running threads executing
420 mono_runtime_cleanup (MonoDomain *domain)
422 mono_attach_cleanup ();
424 /* This ends up calling any pending pending (for at most 2 seconds) */
427 mono_thread_cleanup ();
429 #ifndef DISABLE_SOCKETS
430 mono_network_cleanup ();
432 mono_marshal_cleanup ();
434 mono_type_initialization_cleanup ();
436 mono_monitor_cleanup ();
439 static MonoDomainFunc quit_function = NULL;
442 * mono_install_runtime_cleanup:
445 mono_install_runtime_cleanup (MonoDomainFunc func)
447 quit_function = func;
456 if (quit_function != NULL)
457 quit_function (mono_get_root_domain (), NULL);
461 * mono_domain_create_appdomain:
462 * \param friendly_name The friendly name of the appdomain to create
463 * \param configuration_file The configuration file to initialize the appdomain with
464 * \returns a \c MonoDomain initialized with the appdomain
467 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
469 HANDLE_FUNCTION_ENTER ();
471 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
472 mono_error_cleanup (&error);
473 HANDLE_FUNCTION_RETURN_VAL (domain);
477 * mono_domain_create_appdomain_checked:
478 * \param friendly_name The friendly name of the appdomain to create
479 * \param configuration_file The configuration file to initialize the appdomain with
480 * \param error Set on error.
482 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
485 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
487 HANDLE_FUNCTION_ENTER ();
489 MonoDomain *result = NULL;
491 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
492 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
495 MonoStringHandle config_file;
496 if (configuration_file != NULL) {
497 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
501 config_file = MONO_HANDLE_NEW (MonoString, NULL);
503 MONO_HANDLE_SET (setup, configuration_file, config_file);
505 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
509 result = mono_domain_from_appdomain_handle (ad);
511 HANDLE_FUNCTION_RETURN_VAL (result);
515 * mono_domain_set_config:
516 * \param domain \c MonoDomain initialized with the appdomain we want to change
517 * \param base_dir new base directory for the appdomain
518 * \param config_file_name path to the new configuration for the app domain
520 * Used to set the system configuration for an appdomain
522 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
523 * Error Initializing the configuration system. ---> System.ArgumentException:
524 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
527 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
529 HANDLE_FUNCTION_ENTER ();
531 mono_domain_set_config_checked (domain, base_dir, config_file_name, &error);
532 mono_error_cleanup (&error);
533 HANDLE_FUNCTION_RETURN ();
537 mono_domain_set_config_checked (MonoDomain *domain, const char *base_dir, const char *config_file_name, MonoError *error)
540 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
541 MonoStringHandle base_dir_str = mono_string_new_handle (domain, base_dir, error);
544 MONO_HANDLE_SET (setup, application_base, base_dir_str);
545 MonoStringHandle config_file_name_str = mono_string_new_handle (domain, config_file_name, error);
548 MONO_HANDLE_SET (setup, configuration_file, config_file_name_str);
550 return is_ok (error);
553 static MonoAppDomainSetupHandle
554 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
556 HANDLE_FUNCTION_ENTER ();
557 MonoDomain *caller_domain;
558 MonoClass *ads_class;
559 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
563 caller_domain = mono_domain_get ();
564 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
566 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
570 mono_domain_set_internal (domain);
572 #define XCOPY_FIELD(dst,field,src,error) \
574 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
575 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
576 if (!is_ok (error)) \
578 MONO_HANDLE_SET ((dst),field,copied_val); \
581 #define COPY_VAL(dst,field,type,src) \
583 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
586 XCOPY_FIELD (copy, application_base, setup, error);
587 XCOPY_FIELD (copy, application_name, setup, error);
588 XCOPY_FIELD (copy, cache_path, setup, error);
589 XCOPY_FIELD (copy, configuration_file, setup, error);
590 XCOPY_FIELD (copy, dynamic_base, setup, error);
591 XCOPY_FIELD (copy, license_file, setup, error);
592 XCOPY_FIELD (copy, private_bin_path, setup, error);
593 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
594 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
595 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
596 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
597 COPY_VAL (copy, path_changed, MonoBoolean, setup);
598 COPY_VAL (copy, loader_optimization, int, setup);
599 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
600 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
601 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
602 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
603 XCOPY_FIELD (copy, application_trust, setup, error);
604 XCOPY_FIELD (copy, configuration_bytes, setup, error);
605 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
610 mono_domain_set_internal (caller_domain);
612 MONO_HANDLE_ASSIGN (result, copy);
614 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
617 static MonoAppDomainHandle
618 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
620 HANDLE_FUNCTION_ENTER ();
621 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
627 adclass = mono_class_get_appdomain_class ();
629 /* FIXME: pin all those objects */
630 data = mono_domain_create();
632 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
635 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
636 data->domain = MONO_HANDLE_RAW (ad);
637 data->friendly_name = g_strdup (friendly_name);
639 mono_profiler_appdomain_name (data, data->friendly_name);
641 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
642 if (MONO_HANDLE_IS_NULL (app_base)) {
643 /* Inherit from the root domain since MS.NET does this */
644 MonoDomain *root = mono_get_root_domain ();
645 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
646 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
647 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
648 /* N.B. new string is in the new domain */
649 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
650 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);
651 mono_gchandle_free (gchandle);
652 if (!is_ok (error)) {
653 g_free (data->friendly_name);
656 MONO_HANDLE_SET (setup, application_base, s);
660 mono_context_init_checked (data, error);
664 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
665 if (!mono_error_ok (error)) {
666 g_free (data->friendly_name);
670 mono_domain_set_options_from_config (data);
671 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
673 #ifndef DISABLE_SHADOW_COPY
674 /*FIXME, guard this for when the debugger is not running */
675 char *shadow_location = get_shadow_assembly_location_base (data, error);
676 if (!mono_error_ok (error)) {
677 g_free (data->friendly_name);
681 g_free (shadow_location);
684 create_domain_objects (data);
686 MONO_HANDLE_ASSIGN (result, ad);
688 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
692 * mono_domain_has_type_resolve:
693 * \param domain application domain being looked up
695 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
698 mono_domain_has_type_resolve (MonoDomain *domain)
700 static MonoClassField *field = NULL;
704 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
708 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
712 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
717 * mono_domain_try_type_resolve:
718 * \param domain application domainwhere the name where the type is going to be resolved
719 * \param name the name of the type to resolve or NULL.
720 * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
722 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
723 * the assembly that matches name.
725 * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
727 * \returns A \c MonoReflectionAssembly or NULL if not found
729 MonoReflectionAssembly *
730 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
733 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
734 mono_error_cleanup (&error);
739 MonoReflectionAssembly *
740 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
742 static MonoMethod *method = NULL;
743 MonoReflectionAssembly *ret;
748 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
750 if (method == NULL) {
751 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
752 if (method == NULL) {
753 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
759 *params = (MonoObject*)mono_string_new_checked (mono_domain_get (), name, error);
760 return_val_if_nok (error, NULL);
764 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
765 return_val_if_nok (error, NULL);
771 * mono_domain_owns_vtable_slot:
772 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
775 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
779 mono_domain_lock (domain);
780 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
781 mono_domain_unlock (domain);
787 * \param domain domain
788 * \param force force setting.
790 * Set the current appdomain to \p domain. If \p force is set, set it even
791 * if it is being unloaded.
793 * \returns TRUE on success; FALSE if the domain is unloaded
796 mono_domain_set (MonoDomain *domain, gboolean force)
798 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
801 mono_domain_set_internal (domain);
807 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
811 if (MONO_HANDLE_IS_NULL (name)) {
812 mono_error_set_argument_null (error, "name", "");
816 g_assert (!MONO_HANDLE_IS_NULL (ad));
817 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
820 char *str = mono_string_handle_to_utf8 (name, error);
821 return_val_if_nok (error, NULL_HANDLE);
823 mono_domain_lock (add);
825 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
827 if (!strcmp (str, "APPBASE"))
828 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
829 else if (!strcmp (str, "APP_CONFIG_FILE"))
830 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
831 else if (!strcmp (str, "DYNAMIC_BASE"))
832 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
833 else if (!strcmp (str, "APP_NAME"))
834 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
835 else if (!strcmp (str, "CACHE_BASE"))
836 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
837 else if (!strcmp (str, "PRIVATE_BINPATH"))
838 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
839 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
840 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
841 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
842 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
843 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
844 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
846 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
848 mono_domain_unlock (add);
851 return MONO_HANDLE_CAST (MonoObject, o);
855 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
859 if (MONO_HANDLE_IS_NULL (name)) {
860 mono_error_set_argument_null (error, "name", "");
864 g_assert (!MONO_HANDLE_IS_NULL (ad));
865 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
868 mono_domain_lock (add);
870 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
872 mono_domain_unlock (add);
875 MonoAppDomainSetupHandle
876 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
879 g_assert (!MONO_HANDLE_IS_NULL (ad));
880 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
883 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
887 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
890 g_assert (!MONO_HANDLE_IS_NULL (ad));
891 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
894 return mono_string_new_handle (domain, domain->friendly_name, error);
898 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
901 MonoDomain *add = mono_domain_get ();
903 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
907 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
910 MonoDomain *root = mono_get_root_domain ();
912 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
916 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
918 MonoDomain *domain = mono_domain_get ();
920 return domain->throw_unobserved_task_exceptions;
924 get_attribute_value (const gchar **attribute_names,
925 const gchar **attribute_values,
926 const char *att_name)
929 for (n = 0; attribute_names [n] != NULL; n++) {
930 if (strcmp (attribute_names [n], att_name) == 0)
931 return g_strdup (attribute_values [n]);
937 start_element (GMarkupParseContext *context,
938 const gchar *element_name,
939 const gchar **attribute_names,
940 const gchar **attribute_values,
944 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
946 if (strcmp (element_name, "runtime") == 0) {
947 runtime_config->runtime_count++;
951 if (strcmp (element_name, "assemblyBinding") == 0) {
952 runtime_config->assemblybinding_count++;
956 if (runtime_config->runtime_count != 1)
959 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
960 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
962 if (value && g_ascii_strcasecmp (value, "true") == 0)
963 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
966 if (runtime_config->assemblybinding_count != 1)
969 if (strcmp (element_name, "probing") != 0)
972 g_free (runtime_config->domain->private_bin_path);
973 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
974 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
975 g_free (runtime_config->domain->private_bin_path);
976 runtime_config->domain->private_bin_path = NULL;
982 end_element (GMarkupParseContext *context,
983 const gchar *element_name,
987 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
988 if (strcmp (element_name, "runtime") == 0)
989 runtime_config->runtime_count--;
990 else if (strcmp (element_name, "assemblyBinding") == 0)
991 runtime_config->assemblybinding_count--;
995 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
997 RuntimeConfig *state = (RuntimeConfig *)user_data;
999 const gchar *filename;
1001 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1002 msg = error && error->message ? error->message : "";
1003 g_warning ("Error parsing %s: %s", filename, msg);
1006 static const GMarkupParser
1016 mono_domain_set_options_from_config (MonoDomain *domain)
1019 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1021 GMarkupParseContext *context;
1022 RuntimeConfig runtime_config;
1025 if (!domain || !domain->setup || !domain->setup->configuration_file)
1028 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1029 if (!mono_error_ok (&error)) {
1030 mono_error_cleanup (&error);
1034 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1035 if (!config_file_path)
1036 config_file_path = config_file_name;
1038 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1041 runtime_config.runtime_count = 0;
1042 runtime_config.assemblybinding_count = 0;
1043 runtime_config.domain = domain;
1044 runtime_config.filename = config_file_path;
1047 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1048 offset = 3; /* Skip UTF-8 BOM */
1050 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1051 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1052 g_markup_parse_context_end_parse (context, NULL);
1053 g_markup_parse_context_free (context);
1057 if (config_file_name != config_file_path)
1058 g_free (config_file_name);
1059 g_free (config_file_path);
1063 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1066 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1068 #ifdef DISABLE_APPDOMAINS
1069 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1073 fname = mono_string_handle_to_utf8 (friendly_name, error);
1074 return_val_if_nok (error, ad);
1075 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1082 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1084 HANDLE_FUNCTION_ENTER ();
1086 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1089 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1091 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1095 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1098 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1102 GPtrArray *assemblies;
1105 * Make a copy of the list of assemblies because we can't hold the assemblies
1106 * lock while creating objects etc.
1108 assemblies = g_ptr_array_new ();
1109 /* Need to skip internal assembly builders created by remoting */
1110 mono_domain_assemblies_lock (domain);
1111 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1112 ass = (MonoAssembly *)tmp->data;
1113 if (refonly != ass->ref_only)
1115 if (ass->corlib_internal)
1117 g_ptr_array_add (assemblies, ass);
1119 mono_domain_assemblies_unlock (domain);
1121 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1124 for (i = 0; i < assemblies->len; ++i) {
1125 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1130 g_ptr_array_free (assemblies, TRUE);
1135 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1137 HANDLE_FUNCTION_ENTER ();
1139 MonoAssembly *result = NULL;
1140 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1143 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1145 HANDLE_FUNCTION_RETURN_VAL (result);
1149 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1151 HANDLE_FUNCTION_ENTER ();
1152 MonoAssembly *ret = NULL;
1154 MonoBoolean isrefonly;
1155 gpointer params [3];
1159 if (mono_runtime_get_no_exec ())
1162 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1164 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1165 g_assert (method != NULL);
1167 isrefonly = refonly ? 1 : 0;
1168 MonoReflectionAssemblyHandle requesting_handle;
1170 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1174 params [0] = MONO_HANDLE_RAW (fname);
1175 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1176 params [2] = &isrefonly;
1177 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1178 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1180 HANDLE_FUNCTION_RETURN_VAL (ret);
1184 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1188 MonoAssembly *assembly;
1189 MonoDomain *domain = mono_domain_get ();
1192 aname_str = mono_stringify_assembly_name (aname);
1194 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1196 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1198 mono_error_cleanup (&error);
1204 * LOCKING: assumes assemblies_lock in the domain is already locked.
1207 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1211 gboolean destroy_ht = FALSE;
1213 if (!ass->aname.name)
1217 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1219 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1220 g_hash_table_insert (ht, tmp->data, tmp->data);
1224 /* FIXME: handle lazy loaded assemblies */
1226 if (!g_hash_table_lookup (ht, ass)) {
1227 mono_assembly_addref (ass);
1228 g_hash_table_insert (ht, ass, ass);
1229 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1230 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);
1233 if (ass->image->references) {
1234 for (i = 0; i < ass->image->nreferences; i++) {
1235 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1236 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1237 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1243 g_hash_table_destroy (ht);
1247 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1249 HANDLE_FUNCTION_ENTER ();
1250 static MonoClassField *assembly_load_field;
1251 static MonoMethod *assembly_load_method;
1253 MonoDomain *domain = mono_domain_get ();
1255 gpointer load_value;
1258 if (!domain->domain)
1259 /* This can happen during startup */
1261 #ifdef ASSEMBLY_LOAD_DEBUG
1262 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1264 klass = domain->domain->mbr.obj.vtable->klass;
1266 mono_domain_assemblies_lock (domain);
1267 add_assemblies_to_domain (domain, assembly, NULL);
1268 mono_domain_assemblies_unlock (domain);
1270 if (assembly_load_field == NULL) {
1271 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1272 g_assert (assembly_load_field);
1275 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1276 if (load_value == NULL) {
1277 /* No events waiting to be triggered */
1281 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1282 mono_error_assert_ok (&error);
1284 if (assembly_load_method == NULL) {
1285 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1286 g_assert (assembly_load_method);
1289 *params = MONO_HANDLE_RAW(ref_assembly);
1291 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1292 mono_error_cleanup (&error);
1294 HANDLE_FUNCTION_RETURN ();
1298 * LOCKING: Acquires the domain assemblies lock.
1301 set_domain_search_path (MonoDomain *domain)
1304 MonoAppDomainSetup *setup;
1306 gchar *search_path = NULL;
1309 gchar **pvt_split = NULL;
1310 GError *gerror = NULL;
1311 gint appbaselen = -1;
1314 * We use the low-level domain assemblies lock, since this is called from
1315 * assembly loads hooks, which means this thread might hold the loader lock.
1317 mono_domain_assemblies_lock (domain);
1319 if (!domain->setup) {
1320 mono_domain_assemblies_unlock (domain);
1324 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1325 mono_domain_assemblies_unlock (domain);
1328 setup = domain->setup;
1329 if (!setup->application_base) {
1330 mono_domain_assemblies_unlock (domain);
1331 return; /* Must set application base to get private path working */
1336 if (setup->private_bin_path) {
1337 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1338 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1339 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1340 mono_error_cleanup (&error);
1341 mono_domain_assemblies_unlock (domain);
1346 if (domain->private_bin_path) {
1347 if (search_path == NULL)
1348 search_path = domain->private_bin_path;
1350 gchar *tmp2 = search_path;
1351 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1358 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1359 * directories relative to ApplicationBase separated by semicolons (see
1360 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1361 * The loop below copes with the fact that some Unix applications may use ':' (or
1362 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1363 * ';' for the subsequent split.
1365 * The issue was reported in bug #81446
1368 #ifndef TARGET_WIN32
1371 slen = strlen (search_path);
1372 for (i = 0; i < slen; i++)
1373 if (search_path [i] == ':')
1374 search_path [i] = ';';
1377 pvt_split = g_strsplit (search_path, ";", 1000);
1378 g_free (search_path);
1379 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1384 g_strfreev (pvt_split);
1386 * Don't do this because the first time is called, the domain
1387 * setup is not finished.
1389 * domain->search_path = g_malloc (sizeof (char *));
1390 * domain->search_path [0] = NULL;
1392 mono_domain_assemblies_unlock (domain);
1396 if (domain->search_path)
1397 g_strfreev (domain->search_path);
1399 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1400 tmp [npaths] = NULL;
1402 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1403 if (!mono_error_ok (&error)) {
1404 mono_error_cleanup (&error);
1405 g_strfreev (pvt_split);
1408 mono_domain_assemblies_unlock (domain);
1412 domain->search_path = tmp;
1414 /* FIXME: is this needed? */
1415 if (strncmp (*tmp, "file://", 7) == 0) {
1421 uri = g_strdup_printf ("file:///%s", uri + 7);
1424 uri = mono_escape_uri_string (tmpuri);
1425 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1431 if (gerror != NULL) {
1432 g_warning ("%s\n", gerror->message);
1433 g_error_free (gerror);
1440 for (i = 1; pvt_split && i < npaths; i++) {
1441 if (g_path_is_absolute (pvt_split [i - 1])) {
1442 tmp [i] = g_strdup (pvt_split [i - 1]);
1444 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1447 if (strchr (tmp [i], '.')) {
1451 reduced = mono_path_canonicalize (tmp [i]);
1452 if (appbaselen == -1)
1453 appbaselen = strlen (tmp [0]);
1455 if (strncmp (tmp [0], reduced, appbaselen)) {
1458 tmp [i] = g_strdup ("");
1468 if (setup->private_bin_path_probe != NULL) {
1470 tmp [0] = g_strdup ("");
1473 domain->setup->path_changed = FALSE;
1475 g_strfreev (pvt_split);
1477 mono_domain_assemblies_unlock (domain);
1480 #ifdef DISABLE_SHADOW_COPY
1482 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1488 mono_make_shadow_copy (const char *filename, MonoError *error)
1491 return (char *) filename;
1495 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1497 guint16 *orig, *dest;
1498 gboolean copy_result;
1501 strcpy (src + srclen - tail_len, extension);
1503 if (IS_PORTABILITY_CASE) {
1504 gchar *file = mono_portability_find_file (src, TRUE);
1510 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1514 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1516 strcpy (target + targetlen - tail_len, extension);
1517 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1519 mono_w32file_delete (dest);
1521 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1523 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1524 * overwritten when updated in their original locations. */
1526 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1535 get_cstring_hash (const char *str)
1541 if (!str || !str [0])
1546 for (i = 0; i < len; i++) {
1547 h = (h << 5) - h + *p;
1555 * Returned memory is malloc'd. Called must free it
1558 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1560 MonoAppDomainSetup *setup;
1561 char *cache_path, *appname;
1567 setup = domain->setup;
1568 if (setup->cache_path != NULL && setup->application_name != NULL) {
1569 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1570 return_val_if_nok (error, NULL);
1572 #ifndef TARGET_WIN32
1575 for (i = strlen (cache_path) - 1; i >= 0; i--)
1576 if (cache_path [i] == '\\')
1577 cache_path [i] = '/';
1581 appname = mono_string_to_utf8_checked (setup->application_name, error);
1582 if (!mono_error_ok (error)) {
1583 g_free (cache_path);
1587 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1589 g_free (cache_path);
1591 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1592 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1599 get_shadow_assembly_location (const char *filename, MonoError *error)
1601 gint32 hash = 0, hash2 = 0;
1603 char path_hash [30];
1604 char *bname = g_path_get_basename (filename);
1605 char *dirname = g_path_get_dirname (filename);
1606 char *location, *tmploc;
1607 MonoDomain *domain = mono_domain_get ();
1611 hash = get_cstring_hash (bname);
1612 hash2 = get_cstring_hash (dirname);
1613 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1614 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1615 tmploc = get_shadow_assembly_location_base (domain, error);
1616 if (!mono_error_ok (error)) {
1622 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1630 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1632 struct stat sbuf_dest;
1634 gchar *real_src = mono_portability_find_file (src, TRUE);
1637 stat_src = (gchar*)src;
1639 stat_src = real_src;
1641 if (stat (stat_src, sbuf_src) == -1) {
1642 time_t tnow = time (NULL);
1647 memset (sbuf_src, 0, sizeof (*sbuf_src));
1648 sbuf_src->st_mtime = tnow;
1649 sbuf_src->st_atime = tnow;
1656 if (stat (dest, &sbuf_dest) == -1)
1659 if (sbuf_src->st_size == sbuf_dest.st_size &&
1660 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1667 shadow_copy_create_ini (const char *shadow, const char *filename)
1677 dir_name = g_path_get_dirname (shadow);
1678 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1680 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1685 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1690 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1692 if (handle == INVALID_HANDLE_VALUE) {
1696 full_path = mono_path_resolve_symlinks (filename);
1697 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1699 mono_w32file_close (handle);
1704 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1707 MonoAppDomainSetup *setup;
1710 gchar **directories;
1711 gchar *shadow_status_string;
1713 gboolean shadow_enabled;
1714 gboolean found = FALSE;
1719 setup = domain->setup;
1720 if (setup == NULL || setup->shadow_copy_files == NULL)
1723 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1724 if (!mono_error_ok (&error)) {
1725 mono_error_cleanup (&error);
1728 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1729 g_free (shadow_status_string);
1731 if (!shadow_enabled)
1734 if (setup->shadow_copy_directories == NULL)
1737 /* Is dir_name a shadow_copy destination already? */
1738 base_dir = get_shadow_assembly_location_base (domain, &error);
1739 if (!mono_error_ok (&error)) {
1740 mono_error_cleanup (&error);
1744 if (strstr (dir_name, base_dir)) {
1750 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1751 if (!mono_error_ok (&error)) {
1752 mono_error_cleanup (&error);
1756 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1757 dir_ptr = directories;
1759 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1765 g_strfreev (directories);
1771 This function raises exceptions so it can cause as sorts of nasty stuff if called
1772 while holding a lock.
1773 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1774 or NULL if source file not found.
1775 FIXME bubble up the error instead of raising it here
1778 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1781 gchar *sibling_source, *sibling_target;
1782 gint sibling_source_len, sibling_target_len;
1783 guint16 *orig, *dest;
1786 gboolean copy_result;
1787 struct stat src_sbuf;
1788 struct utimbuf utbuf;
1789 char *dir_name = g_path_get_dirname (filename);
1790 MonoDomain *domain = mono_domain_get ();
1794 error_init (oerror);
1796 set_domain_search_path (domain);
1798 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1800 return (char *) filename;
1803 /* Is dir_name a shadow_copy destination already? */
1804 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1805 if (!mono_error_ok (&error)) {
1806 mono_error_cleanup (&error);
1808 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1812 if (strstr (dir_name, shadow_dir)) {
1813 g_free (shadow_dir);
1815 return (char *) filename;
1817 g_free (shadow_dir);
1820 shadow = get_shadow_assembly_location (filename, &error);
1821 if (!mono_error_ok (&error)) {
1822 mono_error_cleanup (&error);
1823 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1827 if (g_ensure_directory_exists (shadow) == FALSE) {
1829 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1833 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1834 return (char*) shadow;
1836 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1837 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1838 mono_w32file_delete (dest);
1840 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1841 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1842 * and not have it runtime error" */
1843 attrs = mono_w32file_get_attributes (orig);
1844 if (attrs == INVALID_FILE_ATTRIBUTES) {
1846 return (char *)filename;
1849 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1851 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1852 * overwritten when updated in their original locations. */
1854 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1859 if (copy_result == FALSE) {
1862 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1863 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1864 return NULL; /* file not found, shadow copy failed */
1866 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1870 /* attempt to copy .mdb, .config if they exist */
1871 sibling_source = g_strconcat (filename, ".config", NULL);
1872 sibling_source_len = strlen (sibling_source);
1873 sibling_target = g_strconcat (shadow, ".config", NULL);
1874 sibling_target_len = strlen (sibling_target);
1876 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1878 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1880 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1882 g_free (sibling_source);
1883 g_free (sibling_target);
1887 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1891 /* Create a .ini file containing the original assembly location */
1892 if (!shadow_copy_create_ini (shadow, filename)) {
1894 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1898 utbuf.actime = src_sbuf.st_atime;
1899 utbuf.modtime = src_sbuf.st_mtime;
1900 utime (shadow, &utbuf);
1904 #endif /* DISABLE_SHADOW_COPY */
1907 * mono_domain_from_appdomain:
1910 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1912 HANDLE_FUNCTION_ENTER ();
1913 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1914 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1915 HANDLE_FUNCTION_RETURN_VAL (result);
1919 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1921 HANDLE_FUNCTION_ENTER ();
1922 MonoDomain *dom = NULL;
1923 if (MONO_HANDLE_IS_NULL (appdomain))
1926 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1927 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1928 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1930 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1932 dom = MONO_HANDLE_GETVAL (appdomain, data);
1935 HANDLE_FUNCTION_RETURN_VAL (dom);
1940 try_load_from (MonoAssembly **assembly,
1941 const gchar *path1, const gchar *path2,
1942 const gchar *path3, const gchar *path4,
1943 gboolean refonly, gboolean is_private,
1944 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1947 gboolean found = FALSE;
1950 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1952 if (IS_PORTABILITY_SET) {
1953 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1956 fullpath = new_fullpath;
1960 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1963 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1966 return (*assembly != NULL);
1969 static MonoAssembly *
1970 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1972 MonoAssembly *result = NULL;
1975 const gchar *local_culture;
1977 gboolean is_private = FALSE;
1979 if (!culture || *culture == '\0') {
1982 local_culture = culture;
1985 filename = g_strconcat (name, ".dll", NULL);
1986 len = strlen (filename);
1988 for (path = search_path; *path; path++) {
1989 if (**path == '\0') {
1991 continue; /* Ignore empty ApplicationBase */
1994 /* See test cases in bug #58992 and bug #57710 */
1995 /* 1st try: [culture]/[name].dll (culture may be empty) */
1996 strcpy (filename + len - 4, ".dll");
1997 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2000 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2001 strcpy (filename + len - 4, ".exe");
2002 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2005 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2006 strcpy (filename + len - 4, ".dll");
2007 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2010 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2011 strcpy (filename + len - 4, ".exe");
2012 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2021 * Try loading the assembly from ApplicationBase and PrivateBinPath
2022 * and then from assemblies_path if any.
2023 * LOCKING: This is called from the assembly loading code, which means the caller
2024 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2026 static MonoAssembly *
2027 mono_domain_assembly_preload (MonoAssemblyName *aname,
2028 gchar **assemblies_path,
2031 MonoDomain *domain = mono_domain_get ();
2032 MonoAssembly *result = NULL;
2033 gboolean refonly = GPOINTER_TO_UINT (user_data);
2035 set_domain_search_path (domain);
2037 MonoAssemblyCandidatePredicate predicate = NULL;
2038 void* predicate_ud = NULL;
2039 #if !defined(DISABLE_DESKTOP_LOADER)
2040 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2041 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2042 predicate_ud = aname;
2045 if (domain->search_path && domain->search_path [0] != NULL) {
2046 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2047 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2048 for (int i = 0; domain->search_path [i]; i++) {
2049 const char *p = domain->search_path[i];
2050 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2052 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2054 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2057 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2058 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2065 * Check whenever a given assembly was already loaded in the current appdomain.
2067 static MonoAssembly *
2068 mono_domain_assembly_search (MonoAssemblyName *aname,
2071 MonoDomain *domain = mono_domain_get ();
2074 gboolean refonly = GPOINTER_TO_UINT (user_data);
2076 mono_domain_assemblies_lock (domain);
2077 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2078 ass = (MonoAssembly *)tmp->data;
2079 /* Dynamic assemblies can't match here in MS.NET */
2080 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2083 mono_domain_assemblies_unlock (domain);
2086 mono_domain_assemblies_unlock (domain);
2091 MonoReflectionAssemblyHandle
2092 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2095 MonoDomain *domain = mono_domain_get ();
2096 char *name, *filename;
2097 MonoImageOpenStatus status = MONO_IMAGE_OK;
2098 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2103 if (fname == NULL) {
2104 mono_error_set_argument_null (error, "assemblyFile", "");
2108 name = filename = mono_string_handle_to_utf8 (fname, error);
2112 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2115 if (status == MONO_IMAGE_IMAGE_INVALID)
2116 mono_error_set_bad_image_name (error, g_strdup (name), "");
2118 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2122 result = mono_assembly_get_object_handle (domain, ass, error);
2129 MonoReflectionAssemblyHandle
2130 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2131 MonoArrayHandle raw_assembly,
2132 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2133 MonoBoolean refonly,
2138 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2139 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2140 MonoImageOpenStatus status;
2141 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2143 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2144 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2145 if (!assembly_data) {
2146 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2150 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2151 memcpy (assembly_data, raw_data, raw_assembly_len);
2152 mono_gchandle_free (gchandle); /* unpin */
2153 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2155 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2158 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2162 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2163 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2164 uint32_t symbol_gchandle;
2165 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2166 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2167 mono_gchandle_free (symbol_gchandle);
2170 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2174 mono_image_close (image);
2175 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2179 refass = mono_assembly_get_object_handle (domain, ass, error);
2180 if (!MONO_HANDLE_IS_NULL(refass))
2181 MONO_HANDLE_SET (refass, evidence, evidence);
2185 MonoReflectionAssemblyHandle
2186 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2189 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2190 MonoImageOpenStatus status = MONO_IMAGE_OK;
2192 MonoAssemblyName aname;
2198 name = mono_string_handle_to_utf8 (assRef, error);
2201 parsed = mono_assembly_name_parse (name, &aname);
2205 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2206 /* This is a parse error... */
2208 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2212 refass = mono_assembly_get_object_handle (domain, assm, error);
2220 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2221 mono_assembly_name_free (&aname);
2224 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2226 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2235 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2239 MONO_HANDLE_SET (refass, evidence, evidence);
2243 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2247 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2250 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2252 if (NULL == domain) {
2253 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2257 if (domain == mono_get_root_domain ()) {
2258 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2263 * Unloading seems to cause problems when running NUnit/NAnt, hence
2266 if (g_hasenv ("MONO_NO_UNLOAD"))
2269 #ifdef __native_client__
2273 MonoException *exc = NULL;
2274 mono_domain_try_unload (domain, (MonoObject**)&exc);
2276 mono_error_set_exception_instance (error, exc);
2280 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2283 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2288 return mono_domain_is_unloading (domain);
2292 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2295 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2296 mono_error_assert_ok (error);
2300 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2301 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2308 g_assert (!MONO_HANDLE_IS_NULL (refass));
2309 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2310 image = assembly->image;
2313 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2316 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2318 if (MONO_HANDLE_IS_NULL (args)) {
2319 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2320 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2321 mono_error_assert_ok (error);
2324 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2329 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2331 return ad->data->domain_id;
2335 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2338 MonoDomain *old_domain = mono_domain_get ();
2340 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2341 mono_error_set_appdomain_unloaded (error);
2342 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2345 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2349 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2351 MonoDomain *current_domain = mono_domain_get ();
2352 MonoDomain *domain = mono_domain_get_by_id (domainid);
2354 if (!domain || !mono_domain_set (domain, FALSE)) {
2355 mono_error_set_appdomain_unloaded (error);
2356 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2359 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2363 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2366 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2370 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2373 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2377 * Raise an exception to prevent the managed code from executing a pop
2380 mono_error_set_appdomain_unloaded (error);
2384 mono_thread_push_appdomain_ref (domain);
2388 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2391 mono_thread_pop_appdomain_ref ();
2394 MonoAppContextHandle
2395 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2398 return mono_context_get_handle ();
2401 MonoAppContextHandle
2402 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2405 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2408 MonoAppContextHandle
2409 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2412 MonoAppContextHandle old_context = mono_context_get_handle ();
2414 mono_context_set_handle (mc);
2420 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2423 MonoDomain* mono_root_domain = mono_get_root_domain ();
2424 mono_domain_lock (mono_root_domain);
2425 if (process_guid_set) {
2426 mono_domain_unlock (mono_root_domain);
2427 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2429 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2430 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2431 mono_gchandle_free (gchandle);
2432 process_guid_set = TRUE;
2433 mono_domain_unlock (mono_root_domain);
2438 * mono_domain_is_unloading:
2441 mono_domain_is_unloading (MonoDomain *domain)
2443 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2450 clear_cached_vtable (MonoVTable *vtable)
2452 MonoClass *klass = vtable->klass;
2453 MonoDomain *domain = vtable->domain;
2454 MonoClassRuntimeInfo *runtime_info;
2457 runtime_info = klass->runtime_info;
2458 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2459 runtime_info->domain_vtables [domain->domain_id] = NULL;
2460 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2461 mono_gc_free_fixed (data);
2464 static G_GNUC_UNUSED void
2465 zero_static_data (MonoVTable *vtable)
2467 MonoClass *klass = vtable->klass;
2470 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2471 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2474 typedef struct unload_data {
2477 char *failure_reason;
2482 unload_data_unref (unload_data *data)
2486 mono_atomic_load_acquire (count, gint32, &data->refcount);
2487 g_assert (count >= 1 && count <= 2);
2492 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2496 deregister_reflection_info_roots_from_list (MonoImage *image)
2498 GSList *list = image->reflection_info_unregister_classes;
2501 MonoClass *klass = (MonoClass *)list->data;
2503 mono_class_free_ref_info (klass);
2508 image->reflection_info_unregister_classes = NULL;
2512 deregister_reflection_info_roots (MonoDomain *domain)
2516 mono_domain_assemblies_lock (domain);
2517 for (list = domain->domain_assemblies; list; list = list->next) {
2518 MonoAssembly *assembly = (MonoAssembly *)list->data;
2519 MonoImage *image = assembly->image;
2523 * No need to take the image lock here since dynamic images are appdomain bound and
2524 * at this point the mutator is gone. Taking the image lock here would mean
2525 * promoting it from a simple lock to a complex lock, which we better avoid if
2528 if (image_is_dynamic (image))
2529 deregister_reflection_info_roots_from_list (image);
2531 for (i = 0; i < image->module_count; ++i) {
2532 MonoImage *module = image->modules [i];
2533 if (module && image_is_dynamic (module))
2534 deregister_reflection_info_roots_from_list (module);
2537 mono_domain_assemblies_unlock (domain);
2541 unload_thread_main (void *arg)
2544 unload_data *data = (unload_data*)arg;
2545 MonoDomain *domain = data->domain;
2546 MonoInternalThread *internal;
2549 internal = mono_thread_internal_current ();
2551 MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", &error);
2553 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, &error);
2554 if (!is_ok (&error)) {
2555 data->failure_reason = g_strdup (mono_error_get_message (&error));
2556 mono_error_cleanup (&error);
2561 * FIXME: Abort our parent thread last, so we can return a failure
2562 * indication if aborting times out.
2564 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2565 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2569 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2570 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2574 /* Finalize all finalizable objects in the doomed appdomain */
2575 if (!mono_domain_finalize (domain, -1)) {
2576 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2580 /* Clear references to our vtables in class->runtime_info.
2581 * We also hold the loader lock because we're going to change
2582 * class->runtime_info.
2585 mono_loader_lock (); //FIXME why do we need the loader lock here?
2586 mono_domain_lock (domain);
2589 * We need to make sure that we don't have any remsets
2590 * pointing into static data of the to-be-freed domain because
2591 * at the next collections they would be invalid. So what we
2592 * do is we first zero all static data and then do a minor
2593 * collection. Because all references in the static data will
2594 * now be null we won't do any unnecessary copies and after
2595 * the collection there won't be any more remsets.
2597 for (i = 0; i < domain->class_vtable_array->len; ++i)
2598 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2599 mono_gc_collect (0);
2601 for (i = 0; i < domain->class_vtable_array->len; ++i)
2602 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2603 deregister_reflection_info_roots (domain);
2605 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2607 mono_domain_unlock (domain);
2608 mono_loader_unlock ();
2610 domain->state = MONO_APPDOMAIN_UNLOADED;
2612 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2614 /* remove from the handle table the items related to this domain */
2615 mono_gchandle_free_domain (domain);
2617 mono_domain_free (domain, FALSE);
2619 mono_gc_collect (mono_gc_max_generation ());
2621 mono_atomic_store_release (&data->done, TRUE);
2622 unload_data_unref (data);
2626 mono_atomic_store_release (&data->done, TRUE);
2627 unload_data_unref (data);
2632 * mono_domain_unload:
2633 * \param domain The domain to unload
2635 * Unloads an appdomain. Follows the process outlined in the comment
2636 * for \c mono_domain_try_unload.
2639 mono_domain_unload (MonoDomain *domain)
2641 MonoObject *exc = NULL;
2642 mono_domain_try_unload (domain, &exc);
2645 static MonoThreadInfoWaitRet
2646 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2648 MonoThreadInfoWaitRet result;
2651 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2658 * mono_domain_unload:
2659 * \param domain The domain to unload
2660 * \param exc Exception information
2662 * Unloads an appdomain. Follows the process outlined in:
2663 * http://blogs.gotdotnet.com/cbrumme
2665 * If doing things the 'right' way is too hard or complex, we do it the
2666 * 'simple' way, which means do everything needed to avoid crashes and
2667 * memory leaks, but not much else.
2669 * It is required to pass a valid reference to the exc argument, upon return
2670 * from this function *exc will be set to the exception thrown, if any.
2672 * If this method is not called from an icall (embedded scenario for instance),
2673 * it must not be called with any managed frames on the stack, since the unload
2674 * process could end up trying to abort the current thread.
2677 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2680 MonoThreadHandle *thread_handle;
2681 MonoAppDomainState prev_state;
2683 unload_data *thread_data;
2684 MonoInternalThread *internal;
2685 MonoDomain *caller_domain = mono_domain_get ();
2687 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2689 /* Atomically change our state to UNLOADING */
2690 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2691 MONO_APPDOMAIN_UNLOADING_START,
2692 MONO_APPDOMAIN_CREATED);
2693 if (prev_state != MONO_APPDOMAIN_CREATED) {
2694 switch (prev_state) {
2695 case MONO_APPDOMAIN_UNLOADING_START:
2696 case MONO_APPDOMAIN_UNLOADING:
2697 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2699 case MONO_APPDOMAIN_UNLOADED:
2700 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2703 g_warning ("Invalid appdomain state %d", prev_state);
2704 g_assert_not_reached ();
2708 mono_domain_set (domain, FALSE);
2709 /* Notify OnDomainUnload listeners */
2710 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2713 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2715 if (!mono_error_ok (&error)) {
2717 mono_error_cleanup (&error);
2719 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2723 /* Roll back the state change */
2724 domain->state = MONO_APPDOMAIN_CREATED;
2725 mono_domain_set (caller_domain, FALSE);
2728 mono_domain_set (caller_domain, FALSE);
2730 thread_data = g_new0 (unload_data, 1);
2731 thread_data->domain = domain;
2732 thread_data->failure_reason = NULL;
2733 thread_data->done = FALSE;
2734 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2736 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2737 domain->state = MONO_APPDOMAIN_UNLOADING;
2739 * First we create a separate thread for unloading, since
2740 * we might have to abort some threads, including the current one.
2742 * Have to attach to the runtime so shutdown can wait for this thread.
2744 * Force it to be attached to avoid racing during shutdown.
2746 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2747 mono_error_assert_ok (&error);
2749 thread_handle = mono_threads_open_thread_handle (internal->handle);
2751 /* Wait for the thread */
2752 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2753 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2754 /* The unload thread tries to abort us */
2755 /* The icall wrapper will execute the abort */
2756 mono_threads_close_thread_handle (thread_handle);
2757 unload_data_unref (thread_data);
2762 mono_threads_close_thread_handle (thread_handle);
2764 if (thread_data->failure_reason) {
2765 /* Roll back the state change */
2766 domain->state = MONO_APPDOMAIN_CREATED;
2768 g_warning ("%s", thread_data->failure_reason);
2770 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2772 g_free (thread_data->failure_reason);
2773 thread_data->failure_reason = NULL;
2776 unload_data_unref (thread_data);