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_RAISE (domain_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 MonoObject *exc = NULL;
1178 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_try_invoke (method, domain->domain, params, &exc, error));
1179 if (!is_ok (error) || exc != NULL) {
1181 mono_error_set_exception_instance (error, (MonoException*)exc);
1184 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1186 if (ret && !refonly && ret->ref_only) {
1187 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1188 mono_error_set_file_not_found (error, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1193 HANDLE_FUNCTION_RETURN_VAL (ret);
1197 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1201 MonoAssembly *assembly;
1202 MonoDomain *domain = mono_domain_get ();
1205 aname_str = mono_stringify_assembly_name (aname);
1207 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1209 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1211 mono_error_cleanup (&error);
1217 * LOCKING: assumes assemblies_lock in the domain is already locked.
1220 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1224 gboolean destroy_ht = FALSE;
1226 if (!ass->aname.name)
1230 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1232 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1233 g_hash_table_insert (ht, tmp->data, tmp->data);
1237 /* FIXME: handle lazy loaded assemblies */
1239 if (!g_hash_table_lookup (ht, ass)) {
1240 mono_assembly_addref (ass);
1241 g_hash_table_insert (ht, ass, ass);
1242 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1243 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);
1246 if (ass->image->references) {
1247 for (i = 0; i < ass->image->nreferences; i++) {
1248 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1249 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1250 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1256 g_hash_table_destroy (ht);
1260 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1262 HANDLE_FUNCTION_ENTER ();
1263 static MonoClassField *assembly_load_field;
1264 static MonoMethod *assembly_load_method;
1266 MonoDomain *domain = mono_domain_get ();
1268 gpointer load_value;
1271 if (!domain->domain)
1272 /* This can happen during startup */
1274 #ifdef ASSEMBLY_LOAD_DEBUG
1275 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1277 klass = domain->domain->mbr.obj.vtable->klass;
1279 mono_domain_assemblies_lock (domain);
1280 add_assemblies_to_domain (domain, assembly, NULL);
1281 mono_domain_assemblies_unlock (domain);
1283 if (assembly_load_field == NULL) {
1284 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1285 g_assert (assembly_load_field);
1288 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1289 if (load_value == NULL) {
1290 /* No events waiting to be triggered */
1294 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1295 mono_error_assert_ok (&error);
1297 if (assembly_load_method == NULL) {
1298 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1299 g_assert (assembly_load_method);
1302 *params = MONO_HANDLE_RAW(ref_assembly);
1304 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1305 mono_error_cleanup (&error);
1307 HANDLE_FUNCTION_RETURN ();
1311 * LOCKING: Acquires the domain assemblies lock.
1314 set_domain_search_path (MonoDomain *domain)
1317 MonoAppDomainSetup *setup;
1319 gchar *search_path = NULL;
1322 gchar **pvt_split = NULL;
1323 GError *gerror = NULL;
1324 gint appbaselen = -1;
1327 * We use the low-level domain assemblies lock, since this is called from
1328 * assembly loads hooks, which means this thread might hold the loader lock.
1330 mono_domain_assemblies_lock (domain);
1332 if (!domain->setup) {
1333 mono_domain_assemblies_unlock (domain);
1337 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1338 mono_domain_assemblies_unlock (domain);
1341 setup = domain->setup;
1342 if (!setup->application_base) {
1343 mono_domain_assemblies_unlock (domain);
1344 return; /* Must set application base to get private path working */
1349 if (setup->private_bin_path) {
1350 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1351 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1352 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1353 mono_error_cleanup (&error);
1354 mono_domain_assemblies_unlock (domain);
1359 if (domain->private_bin_path) {
1360 if (search_path == NULL)
1361 search_path = domain->private_bin_path;
1363 gchar *tmp2 = search_path;
1364 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1371 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1372 * directories relative to ApplicationBase separated by semicolons (see
1373 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1374 * The loop below copes with the fact that some Unix applications may use ':' (or
1375 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1376 * ';' for the subsequent split.
1378 * The issue was reported in bug #81446
1381 #ifndef TARGET_WIN32
1384 slen = strlen (search_path);
1385 for (i = 0; i < slen; i++)
1386 if (search_path [i] == ':')
1387 search_path [i] = ';';
1390 pvt_split = g_strsplit (search_path, ";", 1000);
1391 g_free (search_path);
1392 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1397 g_strfreev (pvt_split);
1399 * Don't do this because the first time is called, the domain
1400 * setup is not finished.
1402 * domain->search_path = g_malloc (sizeof (char *));
1403 * domain->search_path [0] = NULL;
1405 mono_domain_assemblies_unlock (domain);
1409 if (domain->search_path)
1410 g_strfreev (domain->search_path);
1412 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1413 tmp [npaths] = NULL;
1415 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1416 if (!mono_error_ok (&error)) {
1417 mono_error_cleanup (&error);
1418 g_strfreev (pvt_split);
1421 mono_domain_assemblies_unlock (domain);
1425 domain->search_path = tmp;
1427 /* FIXME: is this needed? */
1428 if (strncmp (*tmp, "file://", 7) == 0) {
1434 uri = g_strdup_printf ("file:///%s", uri + 7);
1437 uri = mono_escape_uri_string (tmpuri);
1438 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1444 if (gerror != NULL) {
1445 g_warning ("%s\n", gerror->message);
1446 g_error_free (gerror);
1453 for (i = 1; pvt_split && i < npaths; i++) {
1454 if (g_path_is_absolute (pvt_split [i - 1])) {
1455 tmp [i] = g_strdup (pvt_split [i - 1]);
1457 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1460 if (strchr (tmp [i], '.')) {
1464 reduced = mono_path_canonicalize (tmp [i]);
1465 if (appbaselen == -1)
1466 appbaselen = strlen (tmp [0]);
1468 if (strncmp (tmp [0], reduced, appbaselen)) {
1471 tmp [i] = g_strdup ("");
1481 if (setup->private_bin_path_probe != NULL) {
1483 tmp [0] = g_strdup ("");
1486 domain->setup->path_changed = FALSE;
1488 g_strfreev (pvt_split);
1490 mono_domain_assemblies_unlock (domain);
1493 #ifdef DISABLE_SHADOW_COPY
1495 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1501 mono_make_shadow_copy (const char *filename, MonoError *error)
1504 return (char *) filename;
1508 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1510 guint16 *orig, *dest;
1511 gboolean copy_result;
1514 strcpy (src + srclen - tail_len, extension);
1516 if (IS_PORTABILITY_CASE) {
1517 gchar *file = mono_portability_find_file (src, TRUE);
1523 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1527 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1529 strcpy (target + targetlen - tail_len, extension);
1530 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1532 mono_w32file_delete (dest);
1534 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1536 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1537 * overwritten when updated in their original locations. */
1539 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1548 get_cstring_hash (const char *str)
1554 if (!str || !str [0])
1559 for (i = 0; i < len; i++) {
1560 h = (h << 5) - h + *p;
1568 * Returned memory is malloc'd. Called must free it
1571 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1573 MonoAppDomainSetup *setup;
1574 char *cache_path, *appname;
1580 setup = domain->setup;
1581 if (setup->cache_path != NULL && setup->application_name != NULL) {
1582 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1583 return_val_if_nok (error, NULL);
1585 #ifndef TARGET_WIN32
1588 for (i = strlen (cache_path) - 1; i >= 0; i--)
1589 if (cache_path [i] == '\\')
1590 cache_path [i] = '/';
1594 appname = mono_string_to_utf8_checked (setup->application_name, error);
1595 if (!mono_error_ok (error)) {
1596 g_free (cache_path);
1600 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1602 g_free (cache_path);
1604 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1605 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1612 get_shadow_assembly_location (const char *filename, MonoError *error)
1614 gint32 hash = 0, hash2 = 0;
1616 char path_hash [30];
1617 char *bname = g_path_get_basename (filename);
1618 char *dirname = g_path_get_dirname (filename);
1619 char *location, *tmploc;
1620 MonoDomain *domain = mono_domain_get ();
1624 hash = get_cstring_hash (bname);
1625 hash2 = get_cstring_hash (dirname);
1626 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1627 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1628 tmploc = get_shadow_assembly_location_base (domain, error);
1629 if (!mono_error_ok (error)) {
1635 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1643 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1645 struct stat sbuf_dest;
1647 gchar *real_src = mono_portability_find_file (src, TRUE);
1650 stat_src = (gchar*)src;
1652 stat_src = real_src;
1654 if (stat (stat_src, sbuf_src) == -1) {
1655 time_t tnow = time (NULL);
1660 memset (sbuf_src, 0, sizeof (*sbuf_src));
1661 sbuf_src->st_mtime = tnow;
1662 sbuf_src->st_atime = tnow;
1669 if (stat (dest, &sbuf_dest) == -1)
1672 if (sbuf_src->st_size == sbuf_dest.st_size &&
1673 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1680 shadow_copy_create_ini (const char *shadow, const char *filename)
1690 dir_name = g_path_get_dirname (shadow);
1691 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1693 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1698 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1703 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1705 if (handle == INVALID_HANDLE_VALUE) {
1709 full_path = mono_path_resolve_symlinks (filename);
1710 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1712 mono_w32file_close (handle);
1717 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1720 MonoAppDomainSetup *setup;
1723 gchar **directories;
1724 gchar *shadow_status_string;
1726 gboolean shadow_enabled;
1727 gboolean found = FALSE;
1732 setup = domain->setup;
1733 if (setup == NULL || setup->shadow_copy_files == NULL)
1736 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1737 if (!mono_error_ok (&error)) {
1738 mono_error_cleanup (&error);
1741 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1742 g_free (shadow_status_string);
1744 if (!shadow_enabled)
1747 if (setup->shadow_copy_directories == NULL)
1750 /* Is dir_name a shadow_copy destination already? */
1751 base_dir = get_shadow_assembly_location_base (domain, &error);
1752 if (!mono_error_ok (&error)) {
1753 mono_error_cleanup (&error);
1757 if (strstr (dir_name, base_dir)) {
1763 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1764 if (!mono_error_ok (&error)) {
1765 mono_error_cleanup (&error);
1769 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1770 dir_ptr = directories;
1772 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1778 g_strfreev (directories);
1784 This function raises exceptions so it can cause as sorts of nasty stuff if called
1785 while holding a lock.
1786 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1787 or NULL if source file not found.
1788 FIXME bubble up the error instead of raising it here
1791 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1794 gchar *sibling_source, *sibling_target;
1795 gint sibling_source_len, sibling_target_len;
1796 guint16 *orig, *dest;
1799 gboolean copy_result;
1800 struct stat src_sbuf;
1801 struct utimbuf utbuf;
1802 char *dir_name = g_path_get_dirname (filename);
1803 MonoDomain *domain = mono_domain_get ();
1807 error_init (oerror);
1809 set_domain_search_path (domain);
1811 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1813 return (char *) filename;
1816 /* Is dir_name a shadow_copy destination already? */
1817 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1818 if (!mono_error_ok (&error)) {
1819 mono_error_cleanup (&error);
1821 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1825 if (strstr (dir_name, shadow_dir)) {
1826 g_free (shadow_dir);
1828 return (char *) filename;
1830 g_free (shadow_dir);
1833 shadow = get_shadow_assembly_location (filename, &error);
1834 if (!mono_error_ok (&error)) {
1835 mono_error_cleanup (&error);
1836 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1840 if (g_ensure_directory_exists (shadow) == FALSE) {
1842 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1846 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1847 return (char*) shadow;
1849 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1850 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1851 mono_w32file_delete (dest);
1853 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1854 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1855 * and not have it runtime error" */
1856 attrs = mono_w32file_get_attributes (orig);
1857 if (attrs == INVALID_FILE_ATTRIBUTES) {
1859 return (char *)filename;
1862 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1864 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1865 * overwritten when updated in their original locations. */
1867 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1872 if (copy_result == FALSE) {
1875 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1876 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1877 return NULL; /* file not found, shadow copy failed */
1879 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1883 /* attempt to copy .mdb, .config if they exist */
1884 sibling_source = g_strconcat (filename, ".config", NULL);
1885 sibling_source_len = strlen (sibling_source);
1886 sibling_target = g_strconcat (shadow, ".config", NULL);
1887 sibling_target_len = strlen (sibling_target);
1889 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1891 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1893 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1895 g_free (sibling_source);
1896 g_free (sibling_target);
1900 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1904 /* Create a .ini file containing the original assembly location */
1905 if (!shadow_copy_create_ini (shadow, filename)) {
1907 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1911 utbuf.actime = src_sbuf.st_atime;
1912 utbuf.modtime = src_sbuf.st_mtime;
1913 utime (shadow, &utbuf);
1917 #endif /* DISABLE_SHADOW_COPY */
1920 * mono_domain_from_appdomain:
1923 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1925 HANDLE_FUNCTION_ENTER ();
1926 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1927 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1928 HANDLE_FUNCTION_RETURN_VAL (result);
1932 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1934 HANDLE_FUNCTION_ENTER ();
1935 MonoDomain *dom = NULL;
1936 if (MONO_HANDLE_IS_NULL (appdomain))
1939 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1940 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1941 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1943 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1945 dom = MONO_HANDLE_GETVAL (appdomain, data);
1948 HANDLE_FUNCTION_RETURN_VAL (dom);
1953 try_load_from (MonoAssembly **assembly,
1954 const gchar *path1, const gchar *path2,
1955 const gchar *path3, const gchar *path4,
1956 gboolean refonly, gboolean is_private,
1957 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1960 gboolean found = FALSE;
1963 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1965 if (IS_PORTABILITY_SET) {
1966 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1969 fullpath = new_fullpath;
1973 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1976 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1979 return (*assembly != NULL);
1982 static MonoAssembly *
1983 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1985 MonoAssembly *result = NULL;
1988 const gchar *local_culture;
1990 gboolean is_private = FALSE;
1992 if (!culture || *culture == '\0') {
1995 local_culture = culture;
1998 filename = g_strconcat (name, ".dll", NULL);
1999 len = strlen (filename);
2001 for (path = search_path; *path; path++) {
2002 if (**path == '\0') {
2004 continue; /* Ignore empty ApplicationBase */
2007 /* See test cases in bug #58992 and bug #57710 */
2008 /* 1st try: [culture]/[name].dll (culture may be empty) */
2009 strcpy (filename + len - 4, ".dll");
2010 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2013 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2014 strcpy (filename + len - 4, ".exe");
2015 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
2018 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2019 strcpy (filename + len - 4, ".dll");
2020 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2023 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2024 strcpy (filename + len - 4, ".exe");
2025 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2034 * Try loading the assembly from ApplicationBase and PrivateBinPath
2035 * and then from assemblies_path if any.
2036 * LOCKING: This is called from the assembly loading code, which means the caller
2037 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2039 static MonoAssembly *
2040 mono_domain_assembly_preload (MonoAssemblyName *aname,
2041 gchar **assemblies_path,
2044 MonoDomain *domain = mono_domain_get ();
2045 MonoAssembly *result = NULL;
2046 gboolean refonly = GPOINTER_TO_UINT (user_data);
2048 set_domain_search_path (domain);
2050 MonoAssemblyCandidatePredicate predicate = NULL;
2051 void* predicate_ud = NULL;
2052 #if !defined(DISABLE_DESKTOP_LOADER)
2053 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2054 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2055 predicate_ud = aname;
2058 if (domain->search_path && domain->search_path [0] != NULL) {
2059 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2060 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2061 for (int i = 0; domain->search_path [i]; i++) {
2062 const char *p = domain->search_path[i];
2063 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2065 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2067 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2070 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2071 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2078 * Check whenever a given assembly was already loaded in the current appdomain.
2080 static MonoAssembly *
2081 mono_domain_assembly_search (MonoAssemblyName *aname,
2084 MonoDomain *domain = mono_domain_get ();
2087 gboolean refonly = GPOINTER_TO_UINT (user_data);
2089 mono_domain_assemblies_lock (domain);
2090 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2091 ass = (MonoAssembly *)tmp->data;
2092 /* Dynamic assemblies can't match here in MS.NET */
2093 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2096 mono_domain_assemblies_unlock (domain);
2099 mono_domain_assemblies_unlock (domain);
2104 MonoReflectionAssemblyHandle
2105 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2108 MonoDomain *domain = mono_domain_get ();
2109 char *name, *filename;
2110 MonoImageOpenStatus status = MONO_IMAGE_OK;
2111 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2116 if (fname == NULL) {
2117 mono_error_set_argument_null (error, "assemblyFile", "");
2121 name = filename = mono_string_handle_to_utf8 (fname, error);
2125 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2128 if (status == MONO_IMAGE_IMAGE_INVALID)
2129 mono_error_set_bad_image_name (error, g_strdup (name), "");
2131 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2135 result = mono_assembly_get_object_handle (domain, ass, error);
2142 MonoReflectionAssemblyHandle
2143 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2144 MonoArrayHandle raw_assembly,
2145 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2146 MonoBoolean refonly,
2151 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2152 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2153 MonoImageOpenStatus status;
2154 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2156 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2157 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2158 if (!assembly_data) {
2159 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2163 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2164 memcpy (assembly_data, raw_data, raw_assembly_len);
2165 mono_gchandle_free (gchandle); /* unpin */
2166 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2168 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2171 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2175 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2176 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2177 uint32_t symbol_gchandle;
2178 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2179 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2180 mono_gchandle_free (symbol_gchandle);
2183 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2187 mono_image_close (image);
2188 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2192 refass = mono_assembly_get_object_handle (domain, ass, error);
2193 if (!MONO_HANDLE_IS_NULL(refass))
2194 MONO_HANDLE_SET (refass, evidence, evidence);
2198 MonoReflectionAssemblyHandle
2199 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2202 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2203 MonoImageOpenStatus status = MONO_IMAGE_OK;
2205 MonoAssemblyName aname;
2211 name = mono_string_handle_to_utf8 (assRef, error);
2214 parsed = mono_assembly_name_parse (name, &aname);
2218 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2219 /* This is a parse error... */
2221 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2225 refass = mono_assembly_get_object_handle (domain, assm, error);
2233 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2234 mono_assembly_name_free (&aname);
2237 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2239 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2248 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2252 MONO_HANDLE_SET (refass, evidence, evidence);
2256 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2260 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2263 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2265 if (NULL == domain) {
2266 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2270 if (domain == mono_get_root_domain ()) {
2271 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2276 * Unloading seems to cause problems when running NUnit/NAnt, hence
2279 if (g_hasenv ("MONO_NO_UNLOAD"))
2282 MonoException *exc = NULL;
2283 mono_domain_try_unload (domain, (MonoObject**)&exc);
2285 mono_error_set_exception_instance (error, exc);
2289 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2292 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2297 return mono_domain_is_unloading (domain);
2301 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2304 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2305 mono_error_assert_ok (error);
2309 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2310 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2317 g_assert (!MONO_HANDLE_IS_NULL (refass));
2318 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2319 image = assembly->image;
2322 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2325 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2327 if (MONO_HANDLE_IS_NULL (args)) {
2328 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2329 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2330 mono_error_assert_ok (error);
2333 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2338 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2340 return ad->data->domain_id;
2344 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2347 MonoDomain *old_domain = mono_domain_get ();
2349 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2350 mono_error_set_appdomain_unloaded (error);
2351 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2354 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2358 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2360 MonoDomain *current_domain = mono_domain_get ();
2361 MonoDomain *domain = mono_domain_get_by_id (domainid);
2363 if (!domain || !mono_domain_set (domain, FALSE)) {
2364 mono_error_set_appdomain_unloaded (error);
2365 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2368 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2372 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2375 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2379 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2382 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2386 * Raise an exception to prevent the managed code from executing a pop
2389 mono_error_set_appdomain_unloaded (error);
2393 mono_thread_push_appdomain_ref (domain);
2397 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2400 mono_thread_pop_appdomain_ref ();
2403 MonoAppContextHandle
2404 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2407 return mono_context_get_handle ();
2410 MonoAppContextHandle
2411 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2414 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2417 MonoAppContextHandle
2418 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2421 MonoAppContextHandle old_context = mono_context_get_handle ();
2423 mono_context_set_handle (mc);
2429 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2432 MonoDomain* mono_root_domain = mono_get_root_domain ();
2433 mono_domain_lock (mono_root_domain);
2434 if (process_guid_set) {
2435 mono_domain_unlock (mono_root_domain);
2436 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2438 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2439 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2440 mono_gchandle_free (gchandle);
2441 process_guid_set = TRUE;
2442 mono_domain_unlock (mono_root_domain);
2447 * mono_domain_is_unloading:
2450 mono_domain_is_unloading (MonoDomain *domain)
2452 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2459 clear_cached_vtable (MonoVTable *vtable)
2461 MonoClass *klass = vtable->klass;
2462 MonoDomain *domain = vtable->domain;
2463 MonoClassRuntimeInfo *runtime_info;
2466 runtime_info = klass->runtime_info;
2467 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2468 runtime_info->domain_vtables [domain->domain_id] = NULL;
2469 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2470 mono_gc_free_fixed (data);
2473 static G_GNUC_UNUSED void
2474 zero_static_data (MonoVTable *vtable)
2476 MonoClass *klass = vtable->klass;
2479 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2480 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2483 typedef struct unload_data {
2486 char *failure_reason;
2491 unload_data_unref (unload_data *data)
2495 mono_atomic_load_acquire (count, gint32, &data->refcount);
2496 g_assert (count >= 1 && count <= 2);
2501 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2505 deregister_reflection_info_roots_from_list (MonoImage *image)
2507 GSList *list = image->reflection_info_unregister_classes;
2510 MonoClass *klass = (MonoClass *)list->data;
2512 mono_class_free_ref_info (klass);
2517 image->reflection_info_unregister_classes = NULL;
2521 deregister_reflection_info_roots (MonoDomain *domain)
2525 mono_domain_assemblies_lock (domain);
2526 for (list = domain->domain_assemblies; list; list = list->next) {
2527 MonoAssembly *assembly = (MonoAssembly *)list->data;
2528 MonoImage *image = assembly->image;
2532 * No need to take the image lock here since dynamic images are appdomain bound and
2533 * at this point the mutator is gone. Taking the image lock here would mean
2534 * promoting it from a simple lock to a complex lock, which we better avoid if
2537 if (image_is_dynamic (image))
2538 deregister_reflection_info_roots_from_list (image);
2540 for (i = 0; i < image->module_count; ++i) {
2541 MonoImage *module = image->modules [i];
2542 if (module && image_is_dynamic (module))
2543 deregister_reflection_info_roots_from_list (module);
2546 mono_domain_assemblies_unlock (domain);
2550 unload_thread_main (void *arg)
2553 unload_data *data = (unload_data*)arg;
2554 MonoDomain *domain = data->domain;
2555 MonoInternalThread *internal;
2558 internal = mono_thread_internal_current ();
2560 MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", &error);
2562 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, &error);
2563 if (!is_ok (&error)) {
2564 data->failure_reason = g_strdup (mono_error_get_message (&error));
2565 mono_error_cleanup (&error);
2570 * FIXME: Abort our parent thread last, so we can return a failure
2571 * indication if aborting times out.
2573 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2574 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2578 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2579 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2583 /* Finalize all finalizable objects in the doomed appdomain */
2584 if (!mono_domain_finalize (domain, -1)) {
2585 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2589 /* Clear references to our vtables in class->runtime_info.
2590 * We also hold the loader lock because we're going to change
2591 * class->runtime_info.
2594 mono_loader_lock (); //FIXME why do we need the loader lock here?
2595 mono_domain_lock (domain);
2597 * We need to make sure that we don't have any remsets
2598 * pointing into static data of the to-be-freed domain because
2599 * at the next collections they would be invalid. So what we
2600 * do is we first zero all static data and then do a minor
2601 * collection. Because all references in the static data will
2602 * now be null we won't do any unnecessary copies and after
2603 * the collection there won't be any more remsets.
2605 for (i = 0; i < domain->class_vtable_array->len; ++i)
2606 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2607 mono_gc_collect (0);
2608 for (i = 0; i < domain->class_vtable_array->len; ++i)
2609 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2610 deregister_reflection_info_roots (domain);
2612 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2614 mono_domain_unlock (domain);
2615 mono_loader_unlock ();
2617 domain->state = MONO_APPDOMAIN_UNLOADED;
2619 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2621 /* remove from the handle table the items related to this domain */
2622 mono_gchandle_free_domain (domain);
2624 mono_domain_free (domain, FALSE);
2626 mono_gc_collect (mono_gc_max_generation ());
2628 mono_atomic_store_release (&data->done, TRUE);
2629 unload_data_unref (data);
2633 mono_atomic_store_release (&data->done, TRUE);
2634 unload_data_unref (data);
2639 * mono_domain_unload:
2640 * \param domain The domain to unload
2642 * Unloads an appdomain. Follows the process outlined in the comment
2643 * for \c mono_domain_try_unload.
2646 mono_domain_unload (MonoDomain *domain)
2648 MonoObject *exc = NULL;
2649 mono_domain_try_unload (domain, &exc);
2652 static MonoThreadInfoWaitRet
2653 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2655 MonoThreadInfoWaitRet result;
2658 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2665 * mono_domain_unload:
2666 * \param domain The domain to unload
2667 * \param exc Exception information
2669 * Unloads an appdomain. Follows the process outlined in:
2670 * http://blogs.gotdotnet.com/cbrumme
2672 * If doing things the 'right' way is too hard or complex, we do it the
2673 * 'simple' way, which means do everything needed to avoid crashes and
2674 * memory leaks, but not much else.
2676 * It is required to pass a valid reference to the exc argument, upon return
2677 * from this function *exc will be set to the exception thrown, if any.
2679 * If this method is not called from an icall (embedded scenario for instance),
2680 * it must not be called with any managed frames on the stack, since the unload
2681 * process could end up trying to abort the current thread.
2684 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2687 MonoThreadHandle *thread_handle;
2688 MonoAppDomainState prev_state;
2690 unload_data *thread_data;
2691 MonoInternalThread *internal;
2692 MonoDomain *caller_domain = mono_domain_get ();
2694 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2696 /* Atomically change our state to UNLOADING */
2697 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2698 MONO_APPDOMAIN_UNLOADING_START,
2699 MONO_APPDOMAIN_CREATED);
2700 if (prev_state != MONO_APPDOMAIN_CREATED) {
2701 switch (prev_state) {
2702 case MONO_APPDOMAIN_UNLOADING_START:
2703 case MONO_APPDOMAIN_UNLOADING:
2704 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2706 case MONO_APPDOMAIN_UNLOADED:
2707 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2710 g_warning ("Invalid appdomain state %d", prev_state);
2711 g_assert_not_reached ();
2715 mono_domain_set (domain, FALSE);
2716 /* Notify OnDomainUnload listeners */
2717 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2720 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2722 if (!mono_error_ok (&error)) {
2724 mono_error_cleanup (&error);
2726 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2730 /* Roll back the state change */
2731 domain->state = MONO_APPDOMAIN_CREATED;
2732 mono_domain_set (caller_domain, FALSE);
2735 mono_domain_set (caller_domain, FALSE);
2737 thread_data = g_new0 (unload_data, 1);
2738 thread_data->domain = domain;
2739 thread_data->failure_reason = NULL;
2740 thread_data->done = FALSE;
2741 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2743 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2744 domain->state = MONO_APPDOMAIN_UNLOADING;
2746 * First we create a separate thread for unloading, since
2747 * we might have to abort some threads, including the current one.
2749 * Have to attach to the runtime so shutdown can wait for this thread.
2751 * Force it to be attached to avoid racing during shutdown.
2753 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2754 mono_error_assert_ok (&error);
2756 thread_handle = mono_threads_open_thread_handle (internal->handle);
2758 /* Wait for the thread */
2759 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2760 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2761 /* The unload thread tries to abort us */
2762 /* The icall wrapper will execute the abort */
2763 mono_threads_close_thread_handle (thread_handle);
2764 unload_data_unref (thread_data);
2769 mono_threads_close_thread_handle (thread_handle);
2771 if (thread_data->failure_reason) {
2772 /* Roll back the state change */
2773 domain->state = MONO_APPDOMAIN_CREATED;
2775 g_warning ("%s", thread_data->failure_reason);
2777 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2779 g_free (thread_data->failure_reason);
2780 thread_data->failure_reason = NULL;
2783 unload_data_unref (thread_data);