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 if (ret && !refonly && ret->ref_only) {
1181 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1182 mono_error_set_file_not_found (error, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1187 HANDLE_FUNCTION_RETURN_VAL (ret);
1191 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1195 MonoAssembly *assembly;
1196 MonoDomain *domain = mono_domain_get ();
1199 aname_str = mono_stringify_assembly_name (aname);
1201 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1203 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1205 mono_error_cleanup (&error);
1211 * LOCKING: assumes assemblies_lock in the domain is already locked.
1214 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1218 gboolean destroy_ht = FALSE;
1220 if (!ass->aname.name)
1224 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1226 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1227 g_hash_table_insert (ht, tmp->data, tmp->data);
1231 /* FIXME: handle lazy loaded assemblies */
1233 if (!g_hash_table_lookup (ht, ass)) {
1234 mono_assembly_addref (ass);
1235 g_hash_table_insert (ht, ass, ass);
1236 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1237 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);
1240 if (ass->image->references) {
1241 for (i = 0; i < ass->image->nreferences; i++) {
1242 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1243 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1244 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1250 g_hash_table_destroy (ht);
1254 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1256 HANDLE_FUNCTION_ENTER ();
1257 static MonoClassField *assembly_load_field;
1258 static MonoMethod *assembly_load_method;
1260 MonoDomain *domain = mono_domain_get ();
1262 gpointer load_value;
1265 if (!domain->domain)
1266 /* This can happen during startup */
1268 #ifdef ASSEMBLY_LOAD_DEBUG
1269 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1271 klass = domain->domain->mbr.obj.vtable->klass;
1273 mono_domain_assemblies_lock (domain);
1274 add_assemblies_to_domain (domain, assembly, NULL);
1275 mono_domain_assemblies_unlock (domain);
1277 if (assembly_load_field == NULL) {
1278 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1279 g_assert (assembly_load_field);
1282 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1283 if (load_value == NULL) {
1284 /* No events waiting to be triggered */
1288 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1289 mono_error_assert_ok (&error);
1291 if (assembly_load_method == NULL) {
1292 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1293 g_assert (assembly_load_method);
1296 *params = MONO_HANDLE_RAW(ref_assembly);
1298 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1299 mono_error_cleanup (&error);
1301 HANDLE_FUNCTION_RETURN ();
1305 * LOCKING: Acquires the domain assemblies lock.
1308 set_domain_search_path (MonoDomain *domain)
1311 MonoAppDomainSetup *setup;
1313 gchar *search_path = NULL;
1316 gchar **pvt_split = NULL;
1317 GError *gerror = NULL;
1318 gint appbaselen = -1;
1321 * We use the low-level domain assemblies lock, since this is called from
1322 * assembly loads hooks, which means this thread might hold the loader lock.
1324 mono_domain_assemblies_lock (domain);
1326 if (!domain->setup) {
1327 mono_domain_assemblies_unlock (domain);
1331 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1332 mono_domain_assemblies_unlock (domain);
1335 setup = domain->setup;
1336 if (!setup->application_base) {
1337 mono_domain_assemblies_unlock (domain);
1338 return; /* Must set application base to get private path working */
1343 if (setup->private_bin_path) {
1344 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1345 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1346 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1347 mono_error_cleanup (&error);
1348 mono_domain_assemblies_unlock (domain);
1353 if (domain->private_bin_path) {
1354 if (search_path == NULL)
1355 search_path = domain->private_bin_path;
1357 gchar *tmp2 = search_path;
1358 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1365 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1366 * directories relative to ApplicationBase separated by semicolons (see
1367 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1368 * The loop below copes with the fact that some Unix applications may use ':' (or
1369 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1370 * ';' for the subsequent split.
1372 * The issue was reported in bug #81446
1375 #ifndef TARGET_WIN32
1378 slen = strlen (search_path);
1379 for (i = 0; i < slen; i++)
1380 if (search_path [i] == ':')
1381 search_path [i] = ';';
1384 pvt_split = g_strsplit (search_path, ";", 1000);
1385 g_free (search_path);
1386 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1391 g_strfreev (pvt_split);
1393 * Don't do this because the first time is called, the domain
1394 * setup is not finished.
1396 * domain->search_path = g_malloc (sizeof (char *));
1397 * domain->search_path [0] = NULL;
1399 mono_domain_assemblies_unlock (domain);
1403 if (domain->search_path)
1404 g_strfreev (domain->search_path);
1406 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1407 tmp [npaths] = NULL;
1409 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1410 if (!mono_error_ok (&error)) {
1411 mono_error_cleanup (&error);
1412 g_strfreev (pvt_split);
1415 mono_domain_assemblies_unlock (domain);
1419 domain->search_path = tmp;
1421 /* FIXME: is this needed? */
1422 if (strncmp (*tmp, "file://", 7) == 0) {
1428 uri = g_strdup_printf ("file:///%s", uri + 7);
1431 uri = mono_escape_uri_string (tmpuri);
1432 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1438 if (gerror != NULL) {
1439 g_warning ("%s\n", gerror->message);
1440 g_error_free (gerror);
1447 for (i = 1; pvt_split && i < npaths; i++) {
1448 if (g_path_is_absolute (pvt_split [i - 1])) {
1449 tmp [i] = g_strdup (pvt_split [i - 1]);
1451 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1454 if (strchr (tmp [i], '.')) {
1458 reduced = mono_path_canonicalize (tmp [i]);
1459 if (appbaselen == -1)
1460 appbaselen = strlen (tmp [0]);
1462 if (strncmp (tmp [0], reduced, appbaselen)) {
1465 tmp [i] = g_strdup ("");
1475 if (setup->private_bin_path_probe != NULL) {
1477 tmp [0] = g_strdup ("");
1480 domain->setup->path_changed = FALSE;
1482 g_strfreev (pvt_split);
1484 mono_domain_assemblies_unlock (domain);
1487 #ifdef DISABLE_SHADOW_COPY
1489 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1495 mono_make_shadow_copy (const char *filename, MonoError *error)
1498 return (char *) filename;
1502 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1504 guint16 *orig, *dest;
1505 gboolean copy_result;
1508 strcpy (src + srclen - tail_len, extension);
1510 if (IS_PORTABILITY_CASE) {
1511 gchar *file = mono_portability_find_file (src, TRUE);
1517 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1521 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1523 strcpy (target + targetlen - tail_len, extension);
1524 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1526 mono_w32file_delete (dest);
1528 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1530 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1531 * overwritten when updated in their original locations. */
1533 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1542 get_cstring_hash (const char *str)
1548 if (!str || !str [0])
1553 for (i = 0; i < len; i++) {
1554 h = (h << 5) - h + *p;
1562 * Returned memory is malloc'd. Called must free it
1565 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1567 MonoAppDomainSetup *setup;
1568 char *cache_path, *appname;
1574 setup = domain->setup;
1575 if (setup->cache_path != NULL && setup->application_name != NULL) {
1576 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1577 return_val_if_nok (error, NULL);
1579 #ifndef TARGET_WIN32
1582 for (i = strlen (cache_path) - 1; i >= 0; i--)
1583 if (cache_path [i] == '\\')
1584 cache_path [i] = '/';
1588 appname = mono_string_to_utf8_checked (setup->application_name, error);
1589 if (!mono_error_ok (error)) {
1590 g_free (cache_path);
1594 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1596 g_free (cache_path);
1598 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1599 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1606 get_shadow_assembly_location (const char *filename, MonoError *error)
1608 gint32 hash = 0, hash2 = 0;
1610 char path_hash [30];
1611 char *bname = g_path_get_basename (filename);
1612 char *dirname = g_path_get_dirname (filename);
1613 char *location, *tmploc;
1614 MonoDomain *domain = mono_domain_get ();
1618 hash = get_cstring_hash (bname);
1619 hash2 = get_cstring_hash (dirname);
1620 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1621 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1622 tmploc = get_shadow_assembly_location_base (domain, error);
1623 if (!mono_error_ok (error)) {
1629 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1637 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1639 struct stat sbuf_dest;
1641 gchar *real_src = mono_portability_find_file (src, TRUE);
1644 stat_src = (gchar*)src;
1646 stat_src = real_src;
1648 if (stat (stat_src, sbuf_src) == -1) {
1649 time_t tnow = time (NULL);
1654 memset (sbuf_src, 0, sizeof (*sbuf_src));
1655 sbuf_src->st_mtime = tnow;
1656 sbuf_src->st_atime = tnow;
1663 if (stat (dest, &sbuf_dest) == -1)
1666 if (sbuf_src->st_size == sbuf_dest.st_size &&
1667 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1674 shadow_copy_create_ini (const char *shadow, const char *filename)
1684 dir_name = g_path_get_dirname (shadow);
1685 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1687 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1692 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1697 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1699 if (handle == INVALID_HANDLE_VALUE) {
1703 full_path = mono_path_resolve_symlinks (filename);
1704 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1706 mono_w32file_close (handle);
1711 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1714 MonoAppDomainSetup *setup;
1717 gchar **directories;
1718 gchar *shadow_status_string;
1720 gboolean shadow_enabled;
1721 gboolean found = FALSE;
1726 setup = domain->setup;
1727 if (setup == NULL || setup->shadow_copy_files == NULL)
1730 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1731 if (!mono_error_ok (&error)) {
1732 mono_error_cleanup (&error);
1735 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1736 g_free (shadow_status_string);
1738 if (!shadow_enabled)
1741 if (setup->shadow_copy_directories == NULL)
1744 /* Is dir_name a shadow_copy destination already? */
1745 base_dir = get_shadow_assembly_location_base (domain, &error);
1746 if (!mono_error_ok (&error)) {
1747 mono_error_cleanup (&error);
1751 if (strstr (dir_name, base_dir)) {
1757 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1758 if (!mono_error_ok (&error)) {
1759 mono_error_cleanup (&error);
1763 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1764 dir_ptr = directories;
1766 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1772 g_strfreev (directories);
1778 This function raises exceptions so it can cause as sorts of nasty stuff if called
1779 while holding a lock.
1780 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1781 or NULL if source file not found.
1782 FIXME bubble up the error instead of raising it here
1785 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1788 gchar *sibling_source, *sibling_target;
1789 gint sibling_source_len, sibling_target_len;
1790 guint16 *orig, *dest;
1793 gboolean copy_result;
1794 struct stat src_sbuf;
1795 struct utimbuf utbuf;
1796 char *dir_name = g_path_get_dirname (filename);
1797 MonoDomain *domain = mono_domain_get ();
1801 error_init (oerror);
1803 set_domain_search_path (domain);
1805 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1807 return (char *) filename;
1810 /* Is dir_name a shadow_copy destination already? */
1811 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1812 if (!mono_error_ok (&error)) {
1813 mono_error_cleanup (&error);
1815 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1819 if (strstr (dir_name, shadow_dir)) {
1820 g_free (shadow_dir);
1822 return (char *) filename;
1824 g_free (shadow_dir);
1827 shadow = get_shadow_assembly_location (filename, &error);
1828 if (!mono_error_ok (&error)) {
1829 mono_error_cleanup (&error);
1830 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1834 if (g_ensure_directory_exists (shadow) == FALSE) {
1836 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1840 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1841 return (char*) shadow;
1843 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1844 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1845 mono_w32file_delete (dest);
1847 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1848 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1849 * and not have it runtime error" */
1850 attrs = mono_w32file_get_attributes (orig);
1851 if (attrs == INVALID_FILE_ATTRIBUTES) {
1853 return (char *)filename;
1856 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1858 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1859 * overwritten when updated in their original locations. */
1861 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1866 if (copy_result == FALSE) {
1869 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1870 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1871 return NULL; /* file not found, shadow copy failed */
1873 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1877 /* attempt to copy .mdb, .config if they exist */
1878 sibling_source = g_strconcat (filename, ".config", NULL);
1879 sibling_source_len = strlen (sibling_source);
1880 sibling_target = g_strconcat (shadow, ".config", NULL);
1881 sibling_target_len = strlen (sibling_target);
1883 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1885 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1887 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1889 g_free (sibling_source);
1890 g_free (sibling_target);
1894 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1898 /* Create a .ini file containing the original assembly location */
1899 if (!shadow_copy_create_ini (shadow, filename)) {
1901 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1905 utbuf.actime = src_sbuf.st_atime;
1906 utbuf.modtime = src_sbuf.st_mtime;
1907 utime (shadow, &utbuf);
1911 #endif /* DISABLE_SHADOW_COPY */
1914 * mono_domain_from_appdomain:
1917 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1919 HANDLE_FUNCTION_ENTER ();
1920 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1921 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1922 HANDLE_FUNCTION_RETURN_VAL (result);
1926 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1928 HANDLE_FUNCTION_ENTER ();
1929 MonoDomain *dom = NULL;
1930 if (MONO_HANDLE_IS_NULL (appdomain))
1933 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1934 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1935 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1937 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1939 dom = MONO_HANDLE_GETVAL (appdomain, data);
1942 HANDLE_FUNCTION_RETURN_VAL (dom);
1947 try_load_from (MonoAssembly **assembly,
1948 const gchar *path1, const gchar *path2,
1949 const gchar *path3, const gchar *path4,
1950 gboolean refonly, gboolean is_private,
1951 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1954 gboolean found = FALSE;
1957 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1959 if (IS_PORTABILITY_SET) {
1960 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1963 fullpath = new_fullpath;
1967 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1970 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1973 return (*assembly != NULL);
1976 static MonoAssembly *
1977 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1979 MonoAssembly *result = NULL;
1982 const gchar *local_culture;
1984 gboolean is_private = FALSE;
1986 if (!culture || *culture == '\0') {
1989 local_culture = culture;
1992 filename = g_strconcat (name, ".dll", NULL);
1993 len = strlen (filename);
1995 for (path = search_path; *path; path++) {
1996 if (**path == '\0') {
1998 continue; /* Ignore empty ApplicationBase */
2001 /* See test cases in bug #58992 and bug #57710 */
2002 /* 1st try: [culture]/[name].dll (culture may be empty) */
2003 strcpy (filename + len - 4, ".dll");
2004 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2007 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2008 strcpy (filename + len - 4, ".exe");
2009 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2012 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2013 strcpy (filename + len - 4, ".dll");
2014 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2017 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2018 strcpy (filename + len - 4, ".exe");
2019 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2028 * Try loading the assembly from ApplicationBase and PrivateBinPath
2029 * and then from assemblies_path if any.
2030 * LOCKING: This is called from the assembly loading code, which means the caller
2031 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2033 static MonoAssembly *
2034 mono_domain_assembly_preload (MonoAssemblyName *aname,
2035 gchar **assemblies_path,
2038 MonoDomain *domain = mono_domain_get ();
2039 MonoAssembly *result = NULL;
2040 gboolean refonly = GPOINTER_TO_UINT (user_data);
2042 set_domain_search_path (domain);
2044 MonoAssemblyCandidatePredicate predicate = NULL;
2045 void* predicate_ud = NULL;
2046 #if !defined(DISABLE_DESKTOP_LOADER)
2047 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2048 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2049 predicate_ud = aname;
2052 if (domain->search_path && domain->search_path [0] != NULL) {
2053 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2054 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2055 for (int i = 0; domain->search_path [i]; i++) {
2056 const char *p = domain->search_path[i];
2057 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2059 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2061 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2064 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2065 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2072 * Check whenever a given assembly was already loaded in the current appdomain.
2074 static MonoAssembly *
2075 mono_domain_assembly_search (MonoAssemblyName *aname,
2078 MonoDomain *domain = mono_domain_get ();
2081 gboolean refonly = GPOINTER_TO_UINT (user_data);
2083 mono_domain_assemblies_lock (domain);
2084 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2085 ass = (MonoAssembly *)tmp->data;
2086 /* Dynamic assemblies can't match here in MS.NET */
2087 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2090 mono_domain_assemblies_unlock (domain);
2093 mono_domain_assemblies_unlock (domain);
2098 MonoReflectionAssemblyHandle
2099 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2102 MonoDomain *domain = mono_domain_get ();
2103 char *name, *filename;
2104 MonoImageOpenStatus status = MONO_IMAGE_OK;
2105 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2110 if (fname == NULL) {
2111 mono_error_set_argument_null (error, "assemblyFile", "");
2115 name = filename = mono_string_handle_to_utf8 (fname, error);
2119 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2122 if (status == MONO_IMAGE_IMAGE_INVALID)
2123 mono_error_set_bad_image_name (error, g_strdup (name), "");
2125 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2129 result = mono_assembly_get_object_handle (domain, ass, error);
2136 MonoReflectionAssemblyHandle
2137 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2138 MonoArrayHandle raw_assembly,
2139 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2140 MonoBoolean refonly,
2145 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2146 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2147 MonoImageOpenStatus status;
2148 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2150 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2151 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2152 if (!assembly_data) {
2153 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2157 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2158 memcpy (assembly_data, raw_data, raw_assembly_len);
2159 mono_gchandle_free (gchandle); /* unpin */
2160 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2162 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2165 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2169 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2170 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2171 uint32_t symbol_gchandle;
2172 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2173 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2174 mono_gchandle_free (symbol_gchandle);
2177 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2181 mono_image_close (image);
2182 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2186 refass = mono_assembly_get_object_handle (domain, ass, error);
2187 if (!MONO_HANDLE_IS_NULL(refass))
2188 MONO_HANDLE_SET (refass, evidence, evidence);
2192 MonoReflectionAssemblyHandle
2193 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2196 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2197 MonoImageOpenStatus status = MONO_IMAGE_OK;
2199 MonoAssemblyName aname;
2205 name = mono_string_handle_to_utf8 (assRef, error);
2208 parsed = mono_assembly_name_parse (name, &aname);
2212 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2213 /* This is a parse error... */
2215 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2219 refass = mono_assembly_get_object_handle (domain, assm, error);
2227 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2228 mono_assembly_name_free (&aname);
2231 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2233 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2242 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2246 MONO_HANDLE_SET (refass, evidence, evidence);
2250 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2254 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2257 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2259 if (NULL == domain) {
2260 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2264 if (domain == mono_get_root_domain ()) {
2265 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2270 * Unloading seems to cause problems when running NUnit/NAnt, hence
2273 if (g_hasenv ("MONO_NO_UNLOAD"))
2276 MonoException *exc = NULL;
2277 mono_domain_try_unload (domain, (MonoObject**)&exc);
2279 mono_error_set_exception_instance (error, exc);
2283 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2286 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2291 return mono_domain_is_unloading (domain);
2295 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2298 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2299 mono_error_assert_ok (error);
2303 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2304 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2311 g_assert (!MONO_HANDLE_IS_NULL (refass));
2312 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2313 image = assembly->image;
2316 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2319 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2321 if (MONO_HANDLE_IS_NULL (args)) {
2322 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2323 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2324 mono_error_assert_ok (error);
2327 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2332 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2334 return ad->data->domain_id;
2338 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2341 MonoDomain *old_domain = mono_domain_get ();
2343 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2344 mono_error_set_appdomain_unloaded (error);
2345 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2348 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2352 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2354 MonoDomain *current_domain = mono_domain_get ();
2355 MonoDomain *domain = mono_domain_get_by_id (domainid);
2357 if (!domain || !mono_domain_set (domain, FALSE)) {
2358 mono_error_set_appdomain_unloaded (error);
2359 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2362 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2366 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2369 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2373 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2376 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2380 * Raise an exception to prevent the managed code from executing a pop
2383 mono_error_set_appdomain_unloaded (error);
2387 mono_thread_push_appdomain_ref (domain);
2391 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2394 mono_thread_pop_appdomain_ref ();
2397 MonoAppContextHandle
2398 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2401 return mono_context_get_handle ();
2404 MonoAppContextHandle
2405 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2408 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2411 MonoAppContextHandle
2412 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2415 MonoAppContextHandle old_context = mono_context_get_handle ();
2417 mono_context_set_handle (mc);
2423 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2426 MonoDomain* mono_root_domain = mono_get_root_domain ();
2427 mono_domain_lock (mono_root_domain);
2428 if (process_guid_set) {
2429 mono_domain_unlock (mono_root_domain);
2430 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2432 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2433 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2434 mono_gchandle_free (gchandle);
2435 process_guid_set = TRUE;
2436 mono_domain_unlock (mono_root_domain);
2441 * mono_domain_is_unloading:
2444 mono_domain_is_unloading (MonoDomain *domain)
2446 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2453 clear_cached_vtable (MonoVTable *vtable)
2455 MonoClass *klass = vtable->klass;
2456 MonoDomain *domain = vtable->domain;
2457 MonoClassRuntimeInfo *runtime_info;
2460 runtime_info = klass->runtime_info;
2461 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2462 runtime_info->domain_vtables [domain->domain_id] = NULL;
2463 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2464 mono_gc_free_fixed (data);
2467 static G_GNUC_UNUSED void
2468 zero_static_data (MonoVTable *vtable)
2470 MonoClass *klass = vtable->klass;
2473 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2474 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2477 typedef struct unload_data {
2480 char *failure_reason;
2485 unload_data_unref (unload_data *data)
2489 mono_atomic_load_acquire (count, gint32, &data->refcount);
2490 g_assert (count >= 1 && count <= 2);
2495 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2499 deregister_reflection_info_roots_from_list (MonoImage *image)
2501 GSList *list = image->reflection_info_unregister_classes;
2504 MonoClass *klass = (MonoClass *)list->data;
2506 mono_class_free_ref_info (klass);
2511 image->reflection_info_unregister_classes = NULL;
2515 deregister_reflection_info_roots (MonoDomain *domain)
2519 mono_domain_assemblies_lock (domain);
2520 for (list = domain->domain_assemblies; list; list = list->next) {
2521 MonoAssembly *assembly = (MonoAssembly *)list->data;
2522 MonoImage *image = assembly->image;
2526 * No need to take the image lock here since dynamic images are appdomain bound and
2527 * at this point the mutator is gone. Taking the image lock here would mean
2528 * promoting it from a simple lock to a complex lock, which we better avoid if
2531 if (image_is_dynamic (image))
2532 deregister_reflection_info_roots_from_list (image);
2534 for (i = 0; i < image->module_count; ++i) {
2535 MonoImage *module = image->modules [i];
2536 if (module && image_is_dynamic (module))
2537 deregister_reflection_info_roots_from_list (module);
2540 mono_domain_assemblies_unlock (domain);
2544 unload_thread_main (void *arg)
2547 unload_data *data = (unload_data*)arg;
2548 MonoDomain *domain = data->domain;
2549 MonoInternalThread *internal;
2552 internal = mono_thread_internal_current ();
2554 MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", &error);
2556 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, &error);
2557 if (!is_ok (&error)) {
2558 data->failure_reason = g_strdup (mono_error_get_message (&error));
2559 mono_error_cleanup (&error);
2564 * FIXME: Abort our parent thread last, so we can return a failure
2565 * indication if aborting times out.
2567 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2568 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2572 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2573 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2577 /* Finalize all finalizable objects in the doomed appdomain */
2578 if (!mono_domain_finalize (domain, -1)) {
2579 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2583 /* Clear references to our vtables in class->runtime_info.
2584 * We also hold the loader lock because we're going to change
2585 * class->runtime_info.
2588 mono_loader_lock (); //FIXME why do we need the loader lock here?
2589 mono_domain_lock (domain);
2592 * We need to make sure that we don't have any remsets
2593 * pointing into static data of the to-be-freed domain because
2594 * at the next collections they would be invalid. So what we
2595 * do is we first zero all static data and then do a minor
2596 * collection. Because all references in the static data will
2597 * now be null we won't do any unnecessary copies and after
2598 * the collection there won't be any more remsets.
2600 for (i = 0; i < domain->class_vtable_array->len; ++i)
2601 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2602 mono_gc_collect (0);
2604 for (i = 0; i < domain->class_vtable_array->len; ++i)
2605 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2606 deregister_reflection_info_roots (domain);
2608 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2610 mono_domain_unlock (domain);
2611 mono_loader_unlock ();
2613 domain->state = MONO_APPDOMAIN_UNLOADED;
2615 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2617 /* remove from the handle table the items related to this domain */
2618 mono_gchandle_free_domain (domain);
2620 mono_domain_free (domain, FALSE);
2622 mono_gc_collect (mono_gc_max_generation ());
2624 mono_atomic_store_release (&data->done, TRUE);
2625 unload_data_unref (data);
2629 mono_atomic_store_release (&data->done, TRUE);
2630 unload_data_unref (data);
2635 * mono_domain_unload:
2636 * \param domain The domain to unload
2638 * Unloads an appdomain. Follows the process outlined in the comment
2639 * for \c mono_domain_try_unload.
2642 mono_domain_unload (MonoDomain *domain)
2644 MonoObject *exc = NULL;
2645 mono_domain_try_unload (domain, &exc);
2648 static MonoThreadInfoWaitRet
2649 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2651 MonoThreadInfoWaitRet result;
2654 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2661 * mono_domain_unload:
2662 * \param domain The domain to unload
2663 * \param exc Exception information
2665 * Unloads an appdomain. Follows the process outlined in:
2666 * http://blogs.gotdotnet.com/cbrumme
2668 * If doing things the 'right' way is too hard or complex, we do it the
2669 * 'simple' way, which means do everything needed to avoid crashes and
2670 * memory leaks, but not much else.
2672 * It is required to pass a valid reference to the exc argument, upon return
2673 * from this function *exc will be set to the exception thrown, if any.
2675 * If this method is not called from an icall (embedded scenario for instance),
2676 * it must not be called with any managed frames on the stack, since the unload
2677 * process could end up trying to abort the current thread.
2680 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2683 MonoThreadHandle *thread_handle;
2684 MonoAppDomainState prev_state;
2686 unload_data *thread_data;
2687 MonoInternalThread *internal;
2688 MonoDomain *caller_domain = mono_domain_get ();
2690 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2692 /* Atomically change our state to UNLOADING */
2693 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2694 MONO_APPDOMAIN_UNLOADING_START,
2695 MONO_APPDOMAIN_CREATED);
2696 if (prev_state != MONO_APPDOMAIN_CREATED) {
2697 switch (prev_state) {
2698 case MONO_APPDOMAIN_UNLOADING_START:
2699 case MONO_APPDOMAIN_UNLOADING:
2700 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2702 case MONO_APPDOMAIN_UNLOADED:
2703 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2706 g_warning ("Invalid appdomain state %d", prev_state);
2707 g_assert_not_reached ();
2711 mono_domain_set (domain, FALSE);
2712 /* Notify OnDomainUnload listeners */
2713 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2716 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2718 if (!mono_error_ok (&error)) {
2720 mono_error_cleanup (&error);
2722 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2726 /* Roll back the state change */
2727 domain->state = MONO_APPDOMAIN_CREATED;
2728 mono_domain_set (caller_domain, FALSE);
2731 mono_domain_set (caller_domain, FALSE);
2733 thread_data = g_new0 (unload_data, 1);
2734 thread_data->domain = domain;
2735 thread_data->failure_reason = NULL;
2736 thread_data->done = FALSE;
2737 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2739 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2740 domain->state = MONO_APPDOMAIN_UNLOADING;
2742 * First we create a separate thread for unloading, since
2743 * we might have to abort some threads, including the current one.
2745 * Have to attach to the runtime so shutdown can wait for this thread.
2747 * Force it to be attached to avoid racing during shutdown.
2749 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2750 mono_error_assert_ok (&error);
2752 thread_handle = mono_threads_open_thread_handle (internal->handle);
2754 /* Wait for the thread */
2755 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2756 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2757 /* The unload thread tries to abort us */
2758 /* The icall wrapper will execute the abort */
2759 mono_threads_close_thread_handle (thread_handle);
2760 unload_data_unref (thread_data);
2765 mono_threads_close_thread_handle (thread_handle);
2767 if (thread_data->failure_reason) {
2768 /* Roll back the state change */
2769 domain->state = MONO_APPDOMAIN_CREATED;
2771 g_warning ("%s", thread_data->failure_reason);
2773 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2775 g_free (thread_data->failure_reason);
2776 thread_data->failure_reason = NULL;
2779 unload_data_unref (thread_data);