6 * Dietmar Maurer (dietmar@ximian.com)
8 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2012 Xamarin Inc
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #undef ASSEMBLY_LOAD_DEBUG
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_TIME_H
32 #ifdef HAVE_SYS_UTIME_H
33 #include <sys/utime.h>
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/domain-internals.h>
41 #include "mono/metadata/metadata-internals.h"
42 #include <mono/metadata/assembly-internals.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/exception-internals.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/marshal-internals.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
82 int assemblybinding_count;
87 static gunichar2 process_guid [36];
88 static gboolean process_guid_set = FALSE;
90 static gboolean no_exec = FALSE;
93 mono_domain_assembly_preload (MonoAssemblyName *aname,
94 gchar **assemblies_path,
98 mono_domain_assembly_search (MonoAssemblyName *aname,
102 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
105 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
107 static MonoAppDomainHandle
108 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
111 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
115 mono_context_set_default_context (MonoDomain *domain);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
125 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
128 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
131 mono_error_set_appdomain_unloaded (MonoError *error)
133 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
137 mono_install_runtime_load (MonoLoadFunc func)
139 load_function = func;
143 mono_runtime_load (const char *filename, const char *runtime_version)
145 g_assert (load_function);
146 return load_function (filename, runtime_version);
150 * mono_runtime_set_no_exec:
152 * Instructs the runtime to operate in static mode, i.e. avoid/do not
153 * allow managed code execution. This is useful for running the AOT
154 * compiler on platforms which allow full-aot execution only. This
155 * should be called before mono_runtime_init ().
158 mono_runtime_set_no_exec (gboolean val)
164 * mono_runtime_get_no_exec:
166 * If true, then the runtime will not allow managed code execution.
169 mono_runtime_get_no_exec (void)
175 create_domain_objects (MonoDomain *domain)
178 MonoDomain *old_domain = mono_domain_get ();
180 MonoVTable *string_vt;
181 MonoClassField *string_empty_fld;
183 if (domain != old_domain) {
184 mono_thread_push_appdomain_ref (domain);
185 mono_domain_set_internal_with_options (domain, FALSE);
189 * Initialize String.Empty. This enables the removal of
190 * the static cctor of the String class.
192 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
193 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
194 g_assert (string_empty_fld);
195 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
196 mono_error_assert_ok (&error);
197 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
198 domain->empty_string = empty_str;
201 * Create an instance early since we can't do it when there is no memory.
203 arg = mono_string_new (domain, "Out of memory");
204 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
205 mono_error_assert_ok (&error);
208 * These two are needed because the signal handlers might be executing on
209 * an alternate stack, and Boehm GC can't handle that.
211 arg = mono_string_new (domain, "A null value was found where an object instance was required");
212 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
213 mono_error_assert_ok (&error);
214 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
215 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
216 mono_error_assert_ok (&error);
218 /*The ephemeron tombstone i*/
219 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
220 mono_error_assert_ok (&error);
222 if (domain != old_domain) {
223 mono_thread_pop_appdomain_ref ();
224 mono_domain_set_internal_with_options (old_domain, FALSE);
228 * This class is used during exception handling, so initialize it here, to prevent
229 * stack overflows while handling stack overflows.
231 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
236 * \param domain domain returned by \c mono_init
238 * Initialize the core AppDomain: this function will run also some
239 * IL initialization code, so it needs the execution engine to be fully
242 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
243 * we know the \c entry_assembly.
247 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
250 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
251 mono_error_cleanup (&error);
255 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
257 MonoAppDomainSetup *setup;
263 mono_portability_helpers_init ();
265 mono_gc_base_init ();
266 mono_monitor_init ();
267 mono_marshal_init ();
269 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
270 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
271 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
272 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
273 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
274 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
275 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
277 mono_thread_init (start_cb, attach_cb);
279 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
280 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
281 return_if_nok (error);
283 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
285 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
286 return_if_nok (error);
290 domain->setup = setup;
292 mono_thread_attach (domain);
294 mono_type_initialization_init ();
296 if (!mono_runtime_get_no_exec ())
297 create_domain_objects (domain);
299 /* GC init has to happen after thread init */
302 /* contexts use GC handles, so they must be initialized after the GC */
303 mono_context_init_checked (domain, error);
304 return_if_nok (error);
305 mono_context_set_default_context (domain);
307 #ifndef DISABLE_SOCKETS
308 mono_network_init ();
311 mono_console_init ();
314 mono_locks_tracer_init ();
316 /* mscorlib is loaded before we install the load hook */
317 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
323 mono_context_set_default_context (MonoDomain *domain)
325 HANDLE_FUNCTION_ENTER ();
326 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
327 HANDLE_FUNCTION_RETURN ();
332 mono_get_corlib_version (void)
336 MonoClassField *field;
339 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
340 mono_class_init (klass);
341 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
344 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
346 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
347 mono_error_assert_ok (&error);
348 return *(gint32*)((gchar*)value + sizeof (MonoObject));
352 * mono_check_corlib_version:
353 * Checks that the corlib that is loaded matches the version of this runtime.
354 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
355 * allocated string with the error otherwise.
358 mono_check_corlib_version (void)
360 int version = mono_get_corlib_version ();
361 if (version != MONO_CORLIB_VERSION)
362 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
364 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
365 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
366 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
367 if (native_offset != managed_offset)
368 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
375 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
376 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
379 mono_context_init (MonoDomain *domain)
382 mono_context_init_checked (domain, &error);
383 mono_error_cleanup (&error);
387 mono_context_init_checked (MonoDomain *domain, MonoError *error)
390 MonoAppContext *context;
394 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
395 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
396 return_if_nok (error);
398 context->domain_id = domain->domain_id;
399 context->context_id = 0;
400 mono_threads_register_app_context (context, error);
401 mono_error_assert_ok (error);
402 domain->default_context = context;
406 * mono_runtime_cleanup:
407 * \param domain unused.
411 * This must not be called while there are still running threads executing
415 mono_runtime_cleanup (MonoDomain *domain)
417 mono_attach_cleanup ();
419 /* This ends up calling any pending pending (for at most 2 seconds) */
422 mono_thread_cleanup ();
424 #ifndef DISABLE_SOCKETS
425 mono_network_cleanup ();
427 mono_marshal_cleanup ();
429 mono_type_initialization_cleanup ();
431 mono_monitor_cleanup ();
434 static MonoDomainFunc quit_function = NULL;
437 * mono_install_runtime_cleanup:
440 mono_install_runtime_cleanup (MonoDomainFunc func)
442 quit_function = func;
451 if (quit_function != NULL)
452 quit_function (mono_get_root_domain (), NULL);
456 * mono_domain_create_appdomain:
457 * \param friendly_name The friendly name of the appdomain to create
458 * \param configuration_file The configuration file to initialize the appdomain with
459 * \returns a \c MonoDomain initialized with the appdomain
462 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
464 HANDLE_FUNCTION_ENTER ();
466 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
467 mono_error_cleanup (&error);
468 HANDLE_FUNCTION_RETURN_VAL (domain);
472 * mono_domain_create_appdomain_checked:
473 * \param friendly_name The friendly name of the appdomain to create
474 * \param configuration_file The configuration file to initialize the appdomain with
475 * \param error Set on error.
477 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
480 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
482 HANDLE_FUNCTION_ENTER ();
484 MonoDomain *result = NULL;
486 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
487 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
490 MonoStringHandle config_file;
491 if (configuration_file != NULL) {
492 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
496 config_file = MONO_HANDLE_NEW (MonoString, NULL);
498 MONO_HANDLE_SET (setup, configuration_file, config_file);
500 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
504 result = mono_domain_from_appdomain_handle (ad);
506 HANDLE_FUNCTION_RETURN_VAL (result);
510 * mono_domain_set_config:
511 * \param domain \c MonoDomain initialized with the appdomain we want to change
512 * \param base_dir new base directory for the appdomain
513 * \param config_file_name path to the new configuration for the app domain
515 * Used to set the system configuration for an appdomain
517 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
518 * Error Initializing the configuration system. ---> System.ArgumentException:
519 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
522 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
524 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
525 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
528 static MonoAppDomainSetupHandle
529 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
531 HANDLE_FUNCTION_ENTER ();
532 MonoDomain *caller_domain;
533 MonoClass *ads_class;
534 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
538 caller_domain = mono_domain_get ();
539 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
541 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
545 mono_domain_set_internal (domain);
547 #define XCOPY_FIELD(dst,field,src,error) \
549 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
550 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
551 if (!is_ok (error)) \
553 MONO_HANDLE_SET ((dst),field,copied_val); \
556 #define COPY_VAL(dst,field,type,src) \
558 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
561 XCOPY_FIELD (copy, application_base, setup, error);
562 XCOPY_FIELD (copy, application_name, setup, error);
563 XCOPY_FIELD (copy, cache_path, setup, error);
564 XCOPY_FIELD (copy, configuration_file, setup, error);
565 XCOPY_FIELD (copy, dynamic_base, setup, error);
566 XCOPY_FIELD (copy, license_file, setup, error);
567 XCOPY_FIELD (copy, private_bin_path, setup, error);
568 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
569 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
570 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
571 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
572 COPY_VAL (copy, path_changed, MonoBoolean, setup);
573 COPY_VAL (copy, loader_optimization, int, setup);
574 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
575 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
576 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
577 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
578 XCOPY_FIELD (copy, application_trust, setup, error);
579 XCOPY_FIELD (copy, configuration_bytes, setup, error);
580 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
585 mono_domain_set_internal (caller_domain);
587 MONO_HANDLE_ASSIGN (result, copy);
589 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
592 static MonoAppDomainHandle
593 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
595 HANDLE_FUNCTION_ENTER ();
596 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
602 adclass = mono_class_get_appdomain_class ();
604 /* FIXME: pin all those objects */
605 data = mono_domain_create();
607 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
610 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
611 data->domain = MONO_HANDLE_RAW (ad);
612 data->friendly_name = g_strdup (friendly_name);
614 mono_profiler_appdomain_name (data, data->friendly_name);
616 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
617 if (MONO_HANDLE_IS_NULL (app_base)) {
618 /* Inherit from the root domain since MS.NET does this */
619 MonoDomain *root = mono_get_root_domain ();
620 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
621 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
622 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
623 /* N.B. new string is in the new domain */
624 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
625 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);
626 mono_gchandle_free (gchandle);
627 if (!is_ok (error)) {
628 g_free (data->friendly_name);
631 MONO_HANDLE_SET (setup, application_base, s);
635 mono_context_init_checked (data, error);
639 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
640 if (!mono_error_ok (error)) {
641 g_free (data->friendly_name);
645 mono_domain_set_options_from_config (data);
646 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
648 #ifndef DISABLE_SHADOW_COPY
649 /*FIXME, guard this for when the debugger is not running */
650 char *shadow_location = get_shadow_assembly_location_base (data, error);
651 if (!mono_error_ok (error)) {
652 g_free (data->friendly_name);
656 g_free (shadow_location);
659 create_domain_objects (data);
661 MONO_HANDLE_ASSIGN (result, ad);
663 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
667 * mono_domain_has_type_resolve:
668 * \param domain application domain being looked up
670 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
673 mono_domain_has_type_resolve (MonoDomain *domain)
675 static MonoClassField *field = NULL;
679 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
683 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
687 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
692 * mono_domain_try_type_resolve:
693 * \param domain application domainwhere the name where the type is going to be resolved
694 * \param name the name of the type to resolve or NULL.
695 * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
697 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
698 * the assembly that matches name.
700 * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
702 * \returns A \c MonoReflectionAssembly or NULL if not found
704 MonoReflectionAssembly *
705 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
708 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
709 mono_error_cleanup (&error);
714 MonoReflectionAssembly *
715 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
717 static MonoMethod *method = NULL;
718 MonoReflectionAssembly *ret;
723 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
725 if (method == NULL) {
726 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
727 if (method == NULL) {
728 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
734 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
738 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
739 return_val_if_nok (error, NULL);
745 * mono_domain_owns_vtable_slot:
746 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
749 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
753 mono_domain_lock (domain);
754 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
755 mono_domain_unlock (domain);
761 * \param domain domain
762 * \param force force setting.
764 * Set the current appdomain to \p domain. If \p force is set, set it even
765 * if it is being unloaded.
767 * \returns TRUE on success; FALSE if the domain is unloaded
770 mono_domain_set (MonoDomain *domain, gboolean force)
772 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
775 mono_domain_set_internal (domain);
781 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
785 if (MONO_HANDLE_IS_NULL (name)) {
786 mono_error_set_argument_null (error, "name", "");
790 g_assert (!MONO_HANDLE_IS_NULL (ad));
791 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
794 char *str = mono_string_handle_to_utf8 (name, error);
795 return_val_if_nok (error, NULL_HANDLE);
797 mono_domain_lock (add);
799 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
801 if (!strcmp (str, "APPBASE"))
802 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
803 else if (!strcmp (str, "APP_CONFIG_FILE"))
804 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
805 else if (!strcmp (str, "DYNAMIC_BASE"))
806 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
807 else if (!strcmp (str, "APP_NAME"))
808 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
809 else if (!strcmp (str, "CACHE_BASE"))
810 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
811 else if (!strcmp (str, "PRIVATE_BINPATH"))
812 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
813 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
814 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
815 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
816 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
817 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
818 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
820 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
822 mono_domain_unlock (add);
825 return MONO_HANDLE_CAST (MonoObject, o);
829 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
833 if (MONO_HANDLE_IS_NULL (name)) {
834 mono_error_set_argument_null (error, "name", "");
838 g_assert (!MONO_HANDLE_IS_NULL (ad));
839 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
842 mono_domain_lock (add);
844 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
846 mono_domain_unlock (add);
849 MonoAppDomainSetupHandle
850 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
853 g_assert (!MONO_HANDLE_IS_NULL (ad));
854 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
857 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
861 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
864 g_assert (!MONO_HANDLE_IS_NULL (ad));
865 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
868 return mono_string_new_handle (domain, domain->friendly_name, error);
872 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
875 MonoDomain *add = mono_domain_get ();
877 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
881 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
884 MonoDomain *root = mono_get_root_domain ();
886 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
890 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
892 MonoDomain *domain = mono_domain_get ();
894 return domain->throw_unobserved_task_exceptions;
898 get_attribute_value (const gchar **attribute_names,
899 const gchar **attribute_values,
900 const char *att_name)
903 for (n = 0; attribute_names [n] != NULL; n++) {
904 if (strcmp (attribute_names [n], att_name) == 0)
905 return g_strdup (attribute_values [n]);
911 start_element (GMarkupParseContext *context,
912 const gchar *element_name,
913 const gchar **attribute_names,
914 const gchar **attribute_values,
918 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
920 if (strcmp (element_name, "runtime") == 0) {
921 runtime_config->runtime_count++;
925 if (strcmp (element_name, "assemblyBinding") == 0) {
926 runtime_config->assemblybinding_count++;
930 if (runtime_config->runtime_count != 1)
933 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
934 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
936 if (value && g_ascii_strcasecmp (value, "true") == 0)
937 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
940 if (runtime_config->assemblybinding_count != 1)
943 if (strcmp (element_name, "probing") != 0)
946 g_free (runtime_config->domain->private_bin_path);
947 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
948 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
949 g_free (runtime_config->domain->private_bin_path);
950 runtime_config->domain->private_bin_path = NULL;
956 end_element (GMarkupParseContext *context,
957 const gchar *element_name,
961 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
962 if (strcmp (element_name, "runtime") == 0)
963 runtime_config->runtime_count--;
964 else if (strcmp (element_name, "assemblyBinding") == 0)
965 runtime_config->assemblybinding_count--;
969 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
971 RuntimeConfig *state = (RuntimeConfig *)user_data;
973 const gchar *filename;
975 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
976 msg = error && error->message ? error->message : "";
977 g_warning ("Error parsing %s: %s", filename, msg);
980 static const GMarkupParser
990 mono_domain_set_options_from_config (MonoDomain *domain)
993 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
995 GMarkupParseContext *context;
996 RuntimeConfig runtime_config;
999 if (!domain || !domain->setup || !domain->setup->configuration_file)
1002 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1003 if (!mono_error_ok (&error)) {
1004 mono_error_cleanup (&error);
1008 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1009 if (!config_file_path)
1010 config_file_path = config_file_name;
1012 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1015 runtime_config.runtime_count = 0;
1016 runtime_config.assemblybinding_count = 0;
1017 runtime_config.domain = domain;
1018 runtime_config.filename = config_file_path;
1021 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1022 offset = 3; /* Skip UTF-8 BOM */
1024 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1025 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1026 g_markup_parse_context_end_parse (context, NULL);
1027 g_markup_parse_context_free (context);
1031 if (config_file_name != config_file_path)
1032 g_free (config_file_name);
1033 g_free (config_file_path);
1037 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1040 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1042 #ifdef DISABLE_APPDOMAINS
1043 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1047 fname = mono_string_handle_to_utf8 (friendly_name, error);
1048 return_val_if_nok (error, ad);
1049 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1056 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1058 HANDLE_FUNCTION_ENTER ();
1060 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1063 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1065 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1069 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1072 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1076 GPtrArray *assemblies;
1079 * Make a copy of the list of assemblies because we can't hold the assemblies
1080 * lock while creating objects etc.
1082 assemblies = g_ptr_array_new ();
1083 /* Need to skip internal assembly builders created by remoting */
1084 mono_domain_assemblies_lock (domain);
1085 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1086 ass = (MonoAssembly *)tmp->data;
1087 if (refonly != ass->ref_only)
1089 if (ass->corlib_internal)
1091 g_ptr_array_add (assemblies, ass);
1093 mono_domain_assemblies_unlock (domain);
1095 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1098 for (i = 0; i < assemblies->len; ++i) {
1099 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1104 g_ptr_array_free (assemblies, TRUE);
1109 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1111 HANDLE_FUNCTION_ENTER ();
1113 MonoAssembly *result = NULL;
1114 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1117 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1119 HANDLE_FUNCTION_RETURN_VAL (result);
1123 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1125 MonoAssembly *ret = NULL;
1127 MonoBoolean isrefonly;
1128 gpointer params [3];
1132 if (mono_runtime_get_no_exec ())
1135 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1137 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1138 g_assert (method != NULL);
1140 isrefonly = refonly ? 1 : 0;
1141 MonoReflectionAssemblyHandle requesting_handle;
1143 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1144 return_val_if_nok (error, ret);
1146 params [0] = MONO_HANDLE_RAW (fname);
1147 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1148 params [2] = &isrefonly;
1149 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1150 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1155 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1159 MonoAssembly *assembly;
1160 MonoDomain *domain = mono_domain_get ();
1163 aname_str = mono_stringify_assembly_name (aname);
1165 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1167 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1169 mono_error_cleanup (&error);
1175 * LOCKING: assumes assemblies_lock in the domain is already locked.
1178 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1182 gboolean destroy_ht = FALSE;
1184 if (!ass->aname.name)
1188 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1190 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1191 g_hash_table_insert (ht, tmp->data, tmp->data);
1195 /* FIXME: handle lazy loaded assemblies */
1197 if (!g_hash_table_lookup (ht, ass)) {
1198 mono_assembly_addref (ass);
1199 g_hash_table_insert (ht, ass, ass);
1200 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1201 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);
1204 if (ass->image->references) {
1205 for (i = 0; i < ass->image->nreferences; i++) {
1206 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1207 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1208 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1214 g_hash_table_destroy (ht);
1218 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1220 static MonoClassField *assembly_load_field;
1221 static MonoMethod *assembly_load_method;
1223 MonoDomain *domain = mono_domain_get ();
1225 gpointer load_value;
1228 if (!domain->domain)
1229 /* This can happen during startup */
1231 #ifdef ASSEMBLY_LOAD_DEBUG
1232 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1234 klass = domain->domain->mbr.obj.vtable->klass;
1236 mono_domain_assemblies_lock (domain);
1237 add_assemblies_to_domain (domain, assembly, NULL);
1238 mono_domain_assemblies_unlock (domain);
1240 if (assembly_load_field == NULL) {
1241 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1242 g_assert (assembly_load_field);
1245 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1246 if (load_value == NULL) {
1247 /* No events waiting to be triggered */
1251 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1252 mono_error_assert_ok (&error);
1254 if (assembly_load_method == NULL) {
1255 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1256 g_assert (assembly_load_method);
1259 *params = MONO_HANDLE_RAW(ref_assembly);
1261 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1262 mono_error_cleanup (&error);
1266 * LOCKING: Acquires the domain assemblies lock.
1269 set_domain_search_path (MonoDomain *domain)
1272 MonoAppDomainSetup *setup;
1274 gchar *search_path = NULL;
1277 gchar **pvt_split = NULL;
1278 GError *gerror = NULL;
1279 gint appbaselen = -1;
1282 * We use the low-level domain assemblies lock, since this is called from
1283 * assembly loads hooks, which means this thread might hold the loader lock.
1285 mono_domain_assemblies_lock (domain);
1287 if (!domain->setup) {
1288 mono_domain_assemblies_unlock (domain);
1292 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1293 mono_domain_assemblies_unlock (domain);
1296 setup = domain->setup;
1297 if (!setup->application_base) {
1298 mono_domain_assemblies_unlock (domain);
1299 return; /* Must set application base to get private path working */
1304 if (setup->private_bin_path) {
1305 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1306 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1307 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1308 mono_error_cleanup (&error);
1309 mono_domain_assemblies_unlock (domain);
1314 if (domain->private_bin_path) {
1315 if (search_path == NULL)
1316 search_path = domain->private_bin_path;
1318 gchar *tmp2 = search_path;
1319 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1326 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1327 * directories relative to ApplicationBase separated by semicolons (see
1328 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1329 * The loop below copes with the fact that some Unix applications may use ':' (or
1330 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1331 * ';' for the subsequent split.
1333 * The issue was reported in bug #81446
1336 #ifndef TARGET_WIN32
1339 slen = strlen (search_path);
1340 for (i = 0; i < slen; i++)
1341 if (search_path [i] == ':')
1342 search_path [i] = ';';
1345 pvt_split = g_strsplit (search_path, ";", 1000);
1346 g_free (search_path);
1347 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1352 g_strfreev (pvt_split);
1354 * Don't do this because the first time is called, the domain
1355 * setup is not finished.
1357 * domain->search_path = g_malloc (sizeof (char *));
1358 * domain->search_path [0] = NULL;
1360 mono_domain_assemblies_unlock (domain);
1364 if (domain->search_path)
1365 g_strfreev (domain->search_path);
1367 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1368 tmp [npaths] = NULL;
1370 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1371 if (!mono_error_ok (&error)) {
1372 mono_error_cleanup (&error);
1373 g_strfreev (pvt_split);
1376 mono_domain_assemblies_unlock (domain);
1380 domain->search_path = tmp;
1382 /* FIXME: is this needed? */
1383 if (strncmp (*tmp, "file://", 7) == 0) {
1389 uri = g_strdup_printf ("file:///%s", uri + 7);
1392 uri = mono_escape_uri_string (tmpuri);
1393 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1399 if (gerror != NULL) {
1400 g_warning ("%s\n", gerror->message);
1401 g_error_free (gerror);
1408 for (i = 1; pvt_split && i < npaths; i++) {
1409 if (g_path_is_absolute (pvt_split [i - 1])) {
1410 tmp [i] = g_strdup (pvt_split [i - 1]);
1412 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1415 if (strchr (tmp [i], '.')) {
1419 reduced = mono_path_canonicalize (tmp [i]);
1420 if (appbaselen == -1)
1421 appbaselen = strlen (tmp [0]);
1423 if (strncmp (tmp [0], reduced, appbaselen)) {
1426 tmp [i] = g_strdup ("");
1436 if (setup->private_bin_path_probe != NULL) {
1438 tmp [0] = g_strdup ("");
1441 domain->setup->path_changed = FALSE;
1443 g_strfreev (pvt_split);
1445 mono_domain_assemblies_unlock (domain);
1448 #ifdef DISABLE_SHADOW_COPY
1450 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1456 mono_make_shadow_copy (const char *filename, MonoError *error)
1459 return (char *) filename;
1463 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1465 guint16 *orig, *dest;
1466 gboolean copy_result;
1469 strcpy (src + srclen - tail_len, extension);
1471 if (IS_PORTABILITY_CASE) {
1472 gchar *file = mono_portability_find_file (src, TRUE);
1478 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1482 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1484 strcpy (target + targetlen - tail_len, extension);
1485 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1487 mono_w32file_delete (dest);
1489 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1491 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1492 * overwritten when updated in their original locations. */
1494 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1503 get_cstring_hash (const char *str)
1509 if (!str || !str [0])
1514 for (i = 0; i < len; i++) {
1515 h = (h << 5) - h + *p;
1523 * Returned memory is malloc'd. Called must free it
1526 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1528 MonoAppDomainSetup *setup;
1529 char *cache_path, *appname;
1535 setup = domain->setup;
1536 if (setup->cache_path != NULL && setup->application_name != NULL) {
1537 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1538 return_val_if_nok (error, NULL);
1540 #ifndef TARGET_WIN32
1543 for (i = strlen (cache_path) - 1; i >= 0; i--)
1544 if (cache_path [i] == '\\')
1545 cache_path [i] = '/';
1549 appname = mono_string_to_utf8_checked (setup->application_name, error);
1550 if (!mono_error_ok (error)) {
1551 g_free (cache_path);
1555 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1557 g_free (cache_path);
1559 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1560 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1567 get_shadow_assembly_location (const char *filename, MonoError *error)
1569 gint32 hash = 0, hash2 = 0;
1571 char path_hash [30];
1572 char *bname = g_path_get_basename (filename);
1573 char *dirname = g_path_get_dirname (filename);
1574 char *location, *tmploc;
1575 MonoDomain *domain = mono_domain_get ();
1579 hash = get_cstring_hash (bname);
1580 hash2 = get_cstring_hash (dirname);
1581 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1582 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1583 tmploc = get_shadow_assembly_location_base (domain, error);
1584 if (!mono_error_ok (error)) {
1590 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1598 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1600 struct stat sbuf_dest;
1602 gchar *real_src = mono_portability_find_file (src, TRUE);
1605 stat_src = (gchar*)src;
1607 stat_src = real_src;
1609 if (stat (stat_src, sbuf_src) == -1) {
1610 time_t tnow = time (NULL);
1615 memset (sbuf_src, 0, sizeof (*sbuf_src));
1616 sbuf_src->st_mtime = tnow;
1617 sbuf_src->st_atime = tnow;
1624 if (stat (dest, &sbuf_dest) == -1)
1627 if (sbuf_src->st_size == sbuf_dest.st_size &&
1628 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1635 shadow_copy_create_ini (const char *shadow, const char *filename)
1645 dir_name = g_path_get_dirname (shadow);
1646 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1648 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1653 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1658 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1660 if (handle == INVALID_HANDLE_VALUE) {
1664 full_path = mono_path_resolve_symlinks (filename);
1665 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1667 mono_w32file_close (handle);
1672 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1675 MonoAppDomainSetup *setup;
1678 gchar **directories;
1679 gchar *shadow_status_string;
1681 gboolean shadow_enabled;
1682 gboolean found = FALSE;
1687 setup = domain->setup;
1688 if (setup == NULL || setup->shadow_copy_files == NULL)
1691 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1692 if (!mono_error_ok (&error)) {
1693 mono_error_cleanup (&error);
1696 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1697 g_free (shadow_status_string);
1699 if (!shadow_enabled)
1702 if (setup->shadow_copy_directories == NULL)
1705 /* Is dir_name a shadow_copy destination already? */
1706 base_dir = get_shadow_assembly_location_base (domain, &error);
1707 if (!mono_error_ok (&error)) {
1708 mono_error_cleanup (&error);
1712 if (strstr (dir_name, base_dir)) {
1718 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1719 if (!mono_error_ok (&error)) {
1720 mono_error_cleanup (&error);
1724 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1725 dir_ptr = directories;
1727 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1733 g_strfreev (directories);
1739 This function raises exceptions so it can cause as sorts of nasty stuff if called
1740 while holding a lock.
1741 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1742 or NULL if source file not found.
1743 FIXME bubble up the error instead of raising it here
1746 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1749 gchar *sibling_source, *sibling_target;
1750 gint sibling_source_len, sibling_target_len;
1751 guint16 *orig, *dest;
1754 gboolean copy_result;
1755 struct stat src_sbuf;
1756 struct utimbuf utbuf;
1757 char *dir_name = g_path_get_dirname (filename);
1758 MonoDomain *domain = mono_domain_get ();
1762 error_init (oerror);
1764 set_domain_search_path (domain);
1766 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1768 return (char *) filename;
1771 /* Is dir_name a shadow_copy destination already? */
1772 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1773 if (!mono_error_ok (&error)) {
1774 mono_error_cleanup (&error);
1776 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1780 if (strstr (dir_name, shadow_dir)) {
1781 g_free (shadow_dir);
1783 return (char *) filename;
1785 g_free (shadow_dir);
1788 shadow = get_shadow_assembly_location (filename, &error);
1789 if (!mono_error_ok (&error)) {
1790 mono_error_cleanup (&error);
1791 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1795 if (g_ensure_directory_exists (shadow) == FALSE) {
1797 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1801 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1802 return (char*) shadow;
1804 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1805 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1806 mono_w32file_delete (dest);
1808 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1809 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1810 * and not have it runtime error" */
1811 attrs = mono_w32file_get_attributes (orig);
1812 if (attrs == INVALID_FILE_ATTRIBUTES) {
1814 return (char *)filename;
1817 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1819 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1820 * overwritten when updated in their original locations. */
1822 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1827 if (copy_result == FALSE) {
1830 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1831 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1832 return NULL; /* file not found, shadow copy failed */
1834 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1838 /* attempt to copy .mdb, .config if they exist */
1839 sibling_source = g_strconcat (filename, ".config", NULL);
1840 sibling_source_len = strlen (sibling_source);
1841 sibling_target = g_strconcat (shadow, ".config", NULL);
1842 sibling_target_len = strlen (sibling_target);
1844 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1846 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1848 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1850 g_free (sibling_source);
1851 g_free (sibling_target);
1855 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1859 /* Create a .ini file containing the original assembly location */
1860 if (!shadow_copy_create_ini (shadow, filename)) {
1862 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1866 utbuf.actime = src_sbuf.st_atime;
1867 utbuf.modtime = src_sbuf.st_mtime;
1868 utime (shadow, &utbuf);
1872 #endif /* DISABLE_SHADOW_COPY */
1875 * mono_domain_from_appdomain:
1878 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1880 HANDLE_FUNCTION_ENTER ();
1881 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1882 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1883 HANDLE_FUNCTION_RETURN_VAL (result);
1887 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1889 HANDLE_FUNCTION_ENTER ();
1890 MonoDomain *dom = NULL;
1891 if (MONO_HANDLE_IS_NULL (appdomain))
1894 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1895 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1896 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1898 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1900 dom = MONO_HANDLE_GETVAL (appdomain, data);
1903 HANDLE_FUNCTION_RETURN_VAL (dom);
1908 try_load_from (MonoAssembly **assembly,
1909 const gchar *path1, const gchar *path2,
1910 const gchar *path3, const gchar *path4,
1911 gboolean refonly, gboolean is_private,
1912 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1915 gboolean found = FALSE;
1918 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1920 if (IS_PORTABILITY_SET) {
1921 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1924 fullpath = new_fullpath;
1928 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1931 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1934 return (*assembly != NULL);
1937 static MonoAssembly *
1938 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1940 MonoAssembly *result = NULL;
1943 const gchar *local_culture;
1945 gboolean is_private = FALSE;
1947 if (!culture || *culture == '\0') {
1950 local_culture = culture;
1953 filename = g_strconcat (name, ".dll", NULL);
1954 len = strlen (filename);
1956 for (path = search_path; *path; path++) {
1957 if (**path == '\0') {
1959 continue; /* Ignore empty ApplicationBase */
1962 /* See test cases in bug #58992 and bug #57710 */
1963 /* 1st try: [culture]/[name].dll (culture may be empty) */
1964 strcpy (filename + len - 4, ".dll");
1965 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1968 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1969 strcpy (filename + len - 4, ".exe");
1970 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1973 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1974 strcpy (filename + len - 4, ".dll");
1975 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1978 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1979 strcpy (filename + len - 4, ".exe");
1980 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1989 * Try loading the assembly from ApplicationBase and PrivateBinPath
1990 * and then from assemblies_path if any.
1991 * LOCKING: This is called from the assembly loading code, which means the caller
1992 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1994 static MonoAssembly *
1995 mono_domain_assembly_preload (MonoAssemblyName *aname,
1996 gchar **assemblies_path,
1999 MonoDomain *domain = mono_domain_get ();
2000 MonoAssembly *result = NULL;
2001 gboolean refonly = GPOINTER_TO_UINT (user_data);
2003 set_domain_search_path (domain);
2005 MonoAssemblyCandidatePredicate predicate = NULL;
2006 void* predicate_ud = NULL;
2007 #if !defined(DISABLE_STRICT_STRONG_NAMES)
2008 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2009 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2010 predicate_ud = aname;
2013 if (domain->search_path && domain->search_path [0] != NULL) {
2014 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2015 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2016 for (int i = 0; domain->search_path [i]; i++) {
2017 const char *p = domain->search_path[i];
2018 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2020 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2022 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2025 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2026 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2033 * Check whenever a given assembly was already loaded in the current appdomain.
2035 static MonoAssembly *
2036 mono_domain_assembly_search (MonoAssemblyName *aname,
2039 MonoDomain *domain = mono_domain_get ();
2042 gboolean refonly = GPOINTER_TO_UINT (user_data);
2044 mono_domain_assemblies_lock (domain);
2045 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2046 ass = (MonoAssembly *)tmp->data;
2047 /* Dynamic assemblies can't match here in MS.NET */
2048 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2051 mono_domain_assemblies_unlock (domain);
2054 mono_domain_assemblies_unlock (domain);
2059 MonoReflectionAssemblyHandle
2060 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2063 MonoDomain *domain = mono_domain_get ();
2064 char *name, *filename;
2065 MonoImageOpenStatus status = MONO_IMAGE_OK;
2066 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2071 if (fname == NULL) {
2072 mono_error_set_argument_null (error, "assemblyFile", "");
2076 name = filename = mono_string_handle_to_utf8 (fname, error);
2080 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2083 if (status == MONO_IMAGE_IMAGE_INVALID)
2084 mono_error_set_bad_image_name (error, g_strdup (name), "");
2086 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2090 result = mono_assembly_get_object_handle (domain, ass, error);
2097 MonoReflectionAssemblyHandle
2098 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2099 MonoArrayHandle raw_assembly,
2100 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2101 MonoBoolean refonly,
2106 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2107 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2108 MonoImageOpenStatus status;
2109 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2111 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2112 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2113 if (!assembly_data) {
2114 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2118 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2119 memcpy (assembly_data, raw_data, raw_assembly_len);
2120 mono_gchandle_free (gchandle); /* unpin */
2121 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2123 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2126 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2130 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2131 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2132 uint32_t symbol_gchandle;
2133 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2134 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2135 mono_gchandle_free (symbol_gchandle);
2138 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2142 mono_image_close (image);
2143 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2147 refass = mono_assembly_get_object_handle (domain, ass, error);
2148 if (!MONO_HANDLE_IS_NULL(refass))
2149 MONO_HANDLE_SET (refass, evidence, evidence);
2153 MonoReflectionAssemblyHandle
2154 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2157 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2158 MonoImageOpenStatus status = MONO_IMAGE_OK;
2160 MonoAssemblyName aname;
2166 name = mono_string_handle_to_utf8 (assRef, error);
2169 parsed = mono_assembly_name_parse (name, &aname);
2173 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2174 /* This is a parse error... */
2176 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2180 refass = mono_assembly_get_object_handle (domain, assm, error);
2188 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2189 mono_assembly_name_free (&aname);
2192 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2194 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2203 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2207 MONO_HANDLE_SET (refass, evidence, evidence);
2211 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2215 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2218 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2220 if (NULL == domain) {
2221 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2225 if (domain == mono_get_root_domain ()) {
2226 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2231 * Unloading seems to cause problems when running NUnit/NAnt, hence
2234 if (g_hasenv ("MONO_NO_UNLOAD"))
2237 #ifdef __native_client__
2241 MonoException *exc = NULL;
2242 mono_domain_try_unload (domain, (MonoObject**)&exc);
2244 mono_error_set_exception_instance (error, exc);
2248 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2251 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2256 return mono_domain_is_unloading (domain);
2260 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2263 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2264 mono_error_assert_ok (error);
2268 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2269 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2276 g_assert (!MONO_HANDLE_IS_NULL (refass));
2277 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2278 image = assembly->image;
2281 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2284 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2286 if (MONO_HANDLE_IS_NULL (args)) {
2287 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2288 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2289 mono_error_assert_ok (error);
2292 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2297 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2299 return ad->data->domain_id;
2303 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2306 MonoDomain *old_domain = mono_domain_get ();
2308 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2309 mono_error_set_appdomain_unloaded (error);
2310 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2313 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2317 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2319 MonoDomain *current_domain = mono_domain_get ();
2320 MonoDomain *domain = mono_domain_get_by_id (domainid);
2322 if (!domain || !mono_domain_set (domain, FALSE)) {
2323 mono_error_set_appdomain_unloaded (error);
2324 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2327 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2331 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2334 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2338 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2341 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2345 * Raise an exception to prevent the managed code from executing a pop
2348 mono_error_set_appdomain_unloaded (error);
2352 mono_thread_push_appdomain_ref (domain);
2356 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2359 mono_thread_pop_appdomain_ref ();
2362 MonoAppContextHandle
2363 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2366 return mono_context_get_handle ();
2369 MonoAppContextHandle
2370 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2373 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2376 MonoAppContextHandle
2377 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2380 MonoAppContextHandle old_context = mono_context_get_handle ();
2382 mono_context_set_handle (mc);
2388 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2391 MonoDomain* mono_root_domain = mono_get_root_domain ();
2392 mono_domain_lock (mono_root_domain);
2393 if (process_guid_set) {
2394 mono_domain_unlock (mono_root_domain);
2395 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2397 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2398 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2399 mono_gchandle_free (gchandle);
2400 process_guid_set = TRUE;
2401 mono_domain_unlock (mono_root_domain);
2406 * mono_domain_is_unloading:
2409 mono_domain_is_unloading (MonoDomain *domain)
2411 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2418 clear_cached_vtable (MonoVTable *vtable)
2420 MonoClass *klass = vtable->klass;
2421 MonoDomain *domain = vtable->domain;
2422 MonoClassRuntimeInfo *runtime_info;
2425 runtime_info = klass->runtime_info;
2426 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2427 runtime_info->domain_vtables [domain->domain_id] = NULL;
2428 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2429 mono_gc_free_fixed (data);
2432 static G_GNUC_UNUSED void
2433 zero_static_data (MonoVTable *vtable)
2435 MonoClass *klass = vtable->klass;
2438 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2439 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2442 typedef struct unload_data {
2445 char *failure_reason;
2450 unload_data_unref (unload_data *data)
2454 mono_atomic_load_acquire (count, gint32, &data->refcount);
2455 g_assert (count >= 1 && count <= 2);
2460 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2464 deregister_reflection_info_roots_from_list (MonoImage *image)
2466 GSList *list = image->reflection_info_unregister_classes;
2469 MonoClass *klass = (MonoClass *)list->data;
2471 mono_class_free_ref_info (klass);
2476 image->reflection_info_unregister_classes = NULL;
2480 deregister_reflection_info_roots (MonoDomain *domain)
2484 mono_domain_assemblies_lock (domain);
2485 for (list = domain->domain_assemblies; list; list = list->next) {
2486 MonoAssembly *assembly = (MonoAssembly *)list->data;
2487 MonoImage *image = assembly->image;
2491 * No need to take the image lock here since dynamic images are appdomain bound and
2492 * at this point the mutator is gone. Taking the image lock here would mean
2493 * promoting it from a simple lock to a complex lock, which we better avoid if
2496 if (image_is_dynamic (image))
2497 deregister_reflection_info_roots_from_list (image);
2499 for (i = 0; i < image->module_count; ++i) {
2500 MonoImage *module = image->modules [i];
2501 if (module && image_is_dynamic (module))
2502 deregister_reflection_info_roots_from_list (module);
2505 mono_domain_assemblies_unlock (domain);
2509 unload_thread_main (void *arg)
2512 unload_data *data = (unload_data*)arg;
2513 MonoDomain *domain = data->domain;
2514 MonoInternalThread *internal;
2517 internal = mono_thread_internal_current ();
2519 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2520 if (!is_ok (&error)) {
2521 data->failure_reason = g_strdup (mono_error_get_message (&error));
2522 mono_error_cleanup (&error);
2527 * FIXME: Abort our parent thread last, so we can return a failure
2528 * indication if aborting times out.
2530 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2531 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2535 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2536 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2540 /* Finalize all finalizable objects in the doomed appdomain */
2541 if (!mono_domain_finalize (domain, -1)) {
2542 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2546 /* Clear references to our vtables in class->runtime_info.
2547 * We also hold the loader lock because we're going to change
2548 * class->runtime_info.
2551 mono_loader_lock (); //FIXME why do we need the loader lock here?
2552 mono_domain_lock (domain);
2555 * We need to make sure that we don't have any remsets
2556 * pointing into static data of the to-be-freed domain because
2557 * at the next collections they would be invalid. So what we
2558 * do is we first zero all static data and then do a minor
2559 * collection. Because all references in the static data will
2560 * now be null we won't do any unnecessary copies and after
2561 * the collection there won't be any more remsets.
2563 for (i = 0; i < domain->class_vtable_array->len; ++i)
2564 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2565 mono_gc_collect (0);
2567 for (i = 0; i < domain->class_vtable_array->len; ++i)
2568 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2569 deregister_reflection_info_roots (domain);
2571 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2573 mono_domain_unlock (domain);
2574 mono_loader_unlock ();
2576 domain->state = MONO_APPDOMAIN_UNLOADED;
2578 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2580 /* remove from the handle table the items related to this domain */
2581 mono_gchandle_free_domain (domain);
2583 mono_domain_free (domain, FALSE);
2585 mono_gc_collect (mono_gc_max_generation ());
2587 mono_atomic_store_release (&data->done, TRUE);
2588 unload_data_unref (data);
2592 mono_atomic_store_release (&data->done, TRUE);
2593 unload_data_unref (data);
2598 * mono_domain_unload:
2599 * \param domain The domain to unload
2601 * Unloads an appdomain. Follows the process outlined in the comment
2602 * for \c mono_domain_try_unload.
2605 mono_domain_unload (MonoDomain *domain)
2607 MonoObject *exc = NULL;
2608 mono_domain_try_unload (domain, &exc);
2611 static MonoThreadInfoWaitRet
2612 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2614 MonoThreadInfoWaitRet result;
2617 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2624 * mono_domain_unload:
2625 * \param domain The domain to unload
2626 * \param exc Exception information
2628 * Unloads an appdomain. Follows the process outlined in:
2629 * http://blogs.gotdotnet.com/cbrumme
2631 * If doing things the 'right' way is too hard or complex, we do it the
2632 * 'simple' way, which means do everything needed to avoid crashes and
2633 * memory leaks, but not much else.
2635 * It is required to pass a valid reference to the exc argument, upon return
2636 * from this function *exc will be set to the exception thrown, if any.
2638 * If this method is not called from an icall (embedded scenario for instance),
2639 * it must not be called with any managed frames on the stack, since the unload
2640 * process could end up trying to abort the current thread.
2643 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2646 MonoThreadHandle *thread_handle;
2647 MonoAppDomainState prev_state;
2649 unload_data *thread_data;
2650 MonoInternalThread *internal;
2651 MonoDomain *caller_domain = mono_domain_get ();
2653 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2655 /* Atomically change our state to UNLOADING */
2656 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2657 MONO_APPDOMAIN_UNLOADING_START,
2658 MONO_APPDOMAIN_CREATED);
2659 if (prev_state != MONO_APPDOMAIN_CREATED) {
2660 switch (prev_state) {
2661 case MONO_APPDOMAIN_UNLOADING_START:
2662 case MONO_APPDOMAIN_UNLOADING:
2663 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2665 case MONO_APPDOMAIN_UNLOADED:
2666 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2669 g_warning ("Invalid appdomain state %d", prev_state);
2670 g_assert_not_reached ();
2674 mono_domain_set (domain, FALSE);
2675 /* Notify OnDomainUnload listeners */
2676 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2679 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2681 if (!mono_error_ok (&error)) {
2683 mono_error_cleanup (&error);
2685 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2689 /* Roll back the state change */
2690 domain->state = MONO_APPDOMAIN_CREATED;
2691 mono_domain_set (caller_domain, FALSE);
2694 mono_domain_set (caller_domain, FALSE);
2696 thread_data = g_new0 (unload_data, 1);
2697 thread_data->domain = domain;
2698 thread_data->failure_reason = NULL;
2699 thread_data->done = FALSE;
2700 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2702 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2703 domain->state = MONO_APPDOMAIN_UNLOADING;
2705 * First we create a separate thread for unloading, since
2706 * we might have to abort some threads, including the current one.
2708 * Have to attach to the runtime so shutdown can wait for this thread.
2710 * Force it to be attached to avoid racing during shutdown.
2712 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2713 mono_error_assert_ok (&error);
2715 thread_handle = mono_threads_open_thread_handle (internal->handle);
2717 /* Wait for the thread */
2718 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2719 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2720 /* The unload thread tries to abort us */
2721 /* The icall wrapper will execute the abort */
2722 mono_threads_close_thread_handle (thread_handle);
2723 unload_data_unref (thread_data);
2728 mono_threads_close_thread_handle (thread_handle);
2730 if (thread_data->failure_reason) {
2731 /* Roll back the state change */
2732 domain->state = MONO_APPDOMAIN_CREATED;
2734 g_warning ("%s", thread_data->failure_reason);
2736 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2738 g_free (thread_data->failure_reason);
2739 thread_data->failure_reason = NULL;
2742 unload_data_unref (thread_data);