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, ".config", sibling_target, sibling_target_len, 7);
1848 g_free (sibling_source);
1849 g_free (sibling_target);
1853 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1857 /* Create a .ini file containing the original assembly location */
1858 if (!shadow_copy_create_ini (shadow, filename)) {
1860 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1864 utbuf.actime = src_sbuf.st_atime;
1865 utbuf.modtime = src_sbuf.st_mtime;
1866 utime (shadow, &utbuf);
1870 #endif /* DISABLE_SHADOW_COPY */
1873 * mono_domain_from_appdomain:
1876 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1878 HANDLE_FUNCTION_ENTER ();
1879 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1880 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1881 HANDLE_FUNCTION_RETURN_VAL (result);
1885 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1887 HANDLE_FUNCTION_ENTER ();
1888 MonoDomain *dom = NULL;
1889 if (MONO_HANDLE_IS_NULL (appdomain))
1892 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1893 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1894 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1896 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1898 dom = MONO_HANDLE_GETVAL (appdomain, data);
1901 HANDLE_FUNCTION_RETURN_VAL (dom);
1906 try_load_from (MonoAssembly **assembly,
1907 const gchar *path1, const gchar *path2,
1908 const gchar *path3, const gchar *path4,
1909 gboolean refonly, gboolean is_private,
1910 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1913 gboolean found = FALSE;
1916 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1918 if (IS_PORTABILITY_SET) {
1919 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1922 fullpath = new_fullpath;
1926 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1929 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1932 return (*assembly != NULL);
1935 static MonoAssembly *
1936 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1938 MonoAssembly *result = NULL;
1941 const gchar *local_culture;
1943 gboolean is_private = FALSE;
1945 if (!culture || *culture == '\0') {
1948 local_culture = culture;
1951 filename = g_strconcat (name, ".dll", NULL);
1952 len = strlen (filename);
1954 for (path = search_path; *path; path++) {
1955 if (**path == '\0') {
1957 continue; /* Ignore empty ApplicationBase */
1960 /* See test cases in bug #58992 and bug #57710 */
1961 /* 1st try: [culture]/[name].dll (culture may be empty) */
1962 strcpy (filename + len - 4, ".dll");
1963 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1966 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1967 strcpy (filename + len - 4, ".exe");
1968 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1971 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1972 strcpy (filename + len - 4, ".dll");
1973 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1976 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1977 strcpy (filename + len - 4, ".exe");
1978 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1987 * Try loading the assembly from ApplicationBase and PrivateBinPath
1988 * and then from assemblies_path if any.
1989 * LOCKING: This is called from the assembly loading code, which means the caller
1990 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1992 static MonoAssembly *
1993 mono_domain_assembly_preload (MonoAssemblyName *aname,
1994 gchar **assemblies_path,
1997 MonoDomain *domain = mono_domain_get ();
1998 MonoAssembly *result = NULL;
1999 gboolean refonly = GPOINTER_TO_UINT (user_data);
2001 set_domain_search_path (domain);
2003 if (domain->search_path && domain->search_path [0] != NULL) {
2004 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2005 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2006 for (int i = 0; domain->search_path [i]; i++) {
2007 const char *p = domain->search_path[i];
2008 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2010 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2012 result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2015 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2016 result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2023 * Check whenever a given assembly was already loaded in the current appdomain.
2025 static MonoAssembly *
2026 mono_domain_assembly_search (MonoAssemblyName *aname,
2029 MonoDomain *domain = mono_domain_get ();
2032 gboolean refonly = GPOINTER_TO_UINT (user_data);
2034 mono_domain_assemblies_lock (domain);
2035 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2036 ass = (MonoAssembly *)tmp->data;
2037 /* Dynamic assemblies can't match here in MS.NET */
2038 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2041 mono_domain_assemblies_unlock (domain);
2044 mono_domain_assemblies_unlock (domain);
2049 MonoReflectionAssemblyHandle
2050 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2053 MonoDomain *domain = mono_domain_get ();
2054 char *name, *filename;
2055 MonoImageOpenStatus status = MONO_IMAGE_OK;
2056 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2061 if (fname == NULL) {
2062 mono_error_set_argument_null (error, "assemblyFile", "");
2066 name = filename = mono_string_handle_to_utf8 (fname, error);
2070 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2073 if (status == MONO_IMAGE_IMAGE_INVALID)
2074 mono_error_set_bad_image_name (error, g_strdup (name), "");
2076 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2080 result = mono_assembly_get_object_handle (domain, ass, error);
2087 MonoReflectionAssemblyHandle
2088 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2089 MonoArrayHandle raw_assembly,
2090 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2091 MonoBoolean refonly,
2096 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2097 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2098 MonoImageOpenStatus status;
2099 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2101 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2102 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2103 if (!assembly_data) {
2104 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2108 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2109 memcpy (assembly_data, raw_data, raw_assembly_len);
2110 mono_gchandle_free (gchandle); /* unpin */
2111 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2113 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2116 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2120 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2121 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2122 uint32_t symbol_gchandle;
2123 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2124 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2125 mono_gchandle_free (symbol_gchandle);
2128 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2132 mono_image_close (image);
2133 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2137 refass = mono_assembly_get_object_handle (domain, ass, error);
2138 if (!MONO_HANDLE_IS_NULL(refass))
2139 MONO_HANDLE_SET (refass, evidence, evidence);
2143 MonoReflectionAssemblyHandle
2144 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2147 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2148 MonoImageOpenStatus status = MONO_IMAGE_OK;
2150 MonoAssemblyName aname;
2156 name = mono_string_handle_to_utf8 (assRef, error);
2159 parsed = mono_assembly_name_parse (name, &aname);
2163 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2164 /* This is a parse error... */
2166 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2170 refass = mono_assembly_get_object_handle (domain, assm, error);
2178 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2179 mono_assembly_name_free (&aname);
2182 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2184 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2193 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2197 MONO_HANDLE_SET (refass, evidence, evidence);
2201 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2205 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2208 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2210 if (NULL == domain) {
2211 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2215 if (domain == mono_get_root_domain ()) {
2216 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2221 * Unloading seems to cause problems when running NUnit/NAnt, hence
2224 if (g_hasenv ("MONO_NO_UNLOAD"))
2227 #ifdef __native_client__
2231 MonoException *exc = NULL;
2232 mono_domain_try_unload (domain, (MonoObject**)&exc);
2234 mono_error_set_exception_instance (error, exc);
2238 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2241 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2246 return mono_domain_is_unloading (domain);
2250 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2253 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2254 mono_error_assert_ok (error);
2258 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2259 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2266 g_assert (!MONO_HANDLE_IS_NULL (refass));
2267 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2268 image = assembly->image;
2271 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2274 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2276 if (MONO_HANDLE_IS_NULL (args)) {
2277 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2278 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2279 mono_error_assert_ok (error);
2282 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2287 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2289 return ad->data->domain_id;
2293 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2296 MonoDomain *old_domain = mono_domain_get ();
2298 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2299 mono_error_set_appdomain_unloaded (error);
2300 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2303 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2307 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2309 MonoDomain *current_domain = mono_domain_get ();
2310 MonoDomain *domain = mono_domain_get_by_id (domainid);
2312 if (!domain || !mono_domain_set (domain, FALSE)) {
2313 mono_error_set_appdomain_unloaded (error);
2314 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2317 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2321 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2324 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2328 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2331 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2335 * Raise an exception to prevent the managed code from executing a pop
2338 mono_error_set_appdomain_unloaded (error);
2342 mono_thread_push_appdomain_ref (domain);
2346 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2349 mono_thread_pop_appdomain_ref ();
2352 MonoAppContextHandle
2353 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2356 return mono_context_get_handle ();
2359 MonoAppContextHandle
2360 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2363 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2366 MonoAppContextHandle
2367 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2370 MonoAppContextHandle old_context = mono_context_get_handle ();
2372 mono_context_set_handle (mc);
2378 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2381 MonoDomain* mono_root_domain = mono_get_root_domain ();
2382 mono_domain_lock (mono_root_domain);
2383 if (process_guid_set) {
2384 mono_domain_unlock (mono_root_domain);
2385 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2387 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2388 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2389 mono_gchandle_free (gchandle);
2390 process_guid_set = TRUE;
2391 mono_domain_unlock (mono_root_domain);
2396 * mono_domain_is_unloading:
2399 mono_domain_is_unloading (MonoDomain *domain)
2401 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2408 clear_cached_vtable (MonoVTable *vtable)
2410 MonoClass *klass = vtable->klass;
2411 MonoDomain *domain = vtable->domain;
2412 MonoClassRuntimeInfo *runtime_info;
2415 runtime_info = klass->runtime_info;
2416 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2417 runtime_info->domain_vtables [domain->domain_id] = NULL;
2418 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2419 mono_gc_free_fixed (data);
2422 static G_GNUC_UNUSED void
2423 zero_static_data (MonoVTable *vtable)
2425 MonoClass *klass = vtable->klass;
2428 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2429 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2432 typedef struct unload_data {
2435 char *failure_reason;
2440 unload_data_unref (unload_data *data)
2444 mono_atomic_load_acquire (count, gint32, &data->refcount);
2445 g_assert (count >= 1 && count <= 2);
2450 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2454 deregister_reflection_info_roots_from_list (MonoImage *image)
2456 GSList *list = image->reflection_info_unregister_classes;
2459 MonoClass *klass = (MonoClass *)list->data;
2461 mono_class_free_ref_info (klass);
2466 image->reflection_info_unregister_classes = NULL;
2470 deregister_reflection_info_roots (MonoDomain *domain)
2474 mono_domain_assemblies_lock (domain);
2475 for (list = domain->domain_assemblies; list; list = list->next) {
2476 MonoAssembly *assembly = (MonoAssembly *)list->data;
2477 MonoImage *image = assembly->image;
2481 * No need to take the image lock here since dynamic images are appdomain bound and
2482 * at this point the mutator is gone. Taking the image lock here would mean
2483 * promoting it from a simple lock to a complex lock, which we better avoid if
2486 if (image_is_dynamic (image))
2487 deregister_reflection_info_roots_from_list (image);
2489 for (i = 0; i < image->module_count; ++i) {
2490 MonoImage *module = image->modules [i];
2491 if (module && image_is_dynamic (module))
2492 deregister_reflection_info_roots_from_list (module);
2495 mono_domain_assemblies_unlock (domain);
2499 unload_thread_main (void *arg)
2502 unload_data *data = (unload_data*)arg;
2503 MonoDomain *domain = data->domain;
2504 MonoInternalThread *internal;
2507 internal = mono_thread_internal_current ();
2509 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2510 if (!is_ok (&error)) {
2511 data->failure_reason = g_strdup (mono_error_get_message (&error));
2512 mono_error_cleanup (&error);
2517 * FIXME: Abort our parent thread last, so we can return a failure
2518 * indication if aborting times out.
2520 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2521 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2525 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2526 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2530 /* Finalize all finalizable objects in the doomed appdomain */
2531 if (!mono_domain_finalize (domain, -1)) {
2532 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2536 /* Clear references to our vtables in class->runtime_info.
2537 * We also hold the loader lock because we're going to change
2538 * class->runtime_info.
2541 mono_loader_lock (); //FIXME why do we need the loader lock here?
2542 mono_domain_lock (domain);
2545 * We need to make sure that we don't have any remsets
2546 * pointing into static data of the to-be-freed domain because
2547 * at the next collections they would be invalid. So what we
2548 * do is we first zero all static data and then do a minor
2549 * collection. Because all references in the static data will
2550 * now be null we won't do any unnecessary copies and after
2551 * the collection there won't be any more remsets.
2553 for (i = 0; i < domain->class_vtable_array->len; ++i)
2554 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2555 mono_gc_collect (0);
2557 for (i = 0; i < domain->class_vtable_array->len; ++i)
2558 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2559 deregister_reflection_info_roots (domain);
2561 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2563 mono_domain_unlock (domain);
2564 mono_loader_unlock ();
2566 domain->state = MONO_APPDOMAIN_UNLOADED;
2568 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2570 /* remove from the handle table the items related to this domain */
2571 mono_gchandle_free_domain (domain);
2573 mono_domain_free (domain, FALSE);
2575 mono_gc_collect (mono_gc_max_generation ());
2577 mono_atomic_store_release (&data->done, TRUE);
2578 unload_data_unref (data);
2582 mono_atomic_store_release (&data->done, TRUE);
2583 unload_data_unref (data);
2588 * mono_domain_unload:
2589 * \param domain The domain to unload
2591 * Unloads an appdomain. Follows the process outlined in the comment
2592 * for \c mono_domain_try_unload.
2595 mono_domain_unload (MonoDomain *domain)
2597 MonoObject *exc = NULL;
2598 mono_domain_try_unload (domain, &exc);
2601 static MonoThreadInfoWaitRet
2602 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2604 MonoThreadInfoWaitRet result;
2607 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2614 * mono_domain_unload:
2615 * \param domain The domain to unload
2616 * \param exc Exception information
2618 * Unloads an appdomain. Follows the process outlined in:
2619 * http://blogs.gotdotnet.com/cbrumme
2621 * If doing things the 'right' way is too hard or complex, we do it the
2622 * 'simple' way, which means do everything needed to avoid crashes and
2623 * memory leaks, but not much else.
2625 * It is required to pass a valid reference to the exc argument, upon return
2626 * from this function *exc will be set to the exception thrown, if any.
2628 * If this method is not called from an icall (embedded scenario for instance),
2629 * it must not be called with any managed frames on the stack, since the unload
2630 * process could end up trying to abort the current thread.
2633 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2636 MonoThreadHandle *thread_handle;
2637 MonoAppDomainState prev_state;
2639 unload_data *thread_data;
2640 MonoInternalThread *internal;
2641 MonoDomain *caller_domain = mono_domain_get ();
2643 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2645 /* Atomically change our state to UNLOADING */
2646 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2647 MONO_APPDOMAIN_UNLOADING_START,
2648 MONO_APPDOMAIN_CREATED);
2649 if (prev_state != MONO_APPDOMAIN_CREATED) {
2650 switch (prev_state) {
2651 case MONO_APPDOMAIN_UNLOADING_START:
2652 case MONO_APPDOMAIN_UNLOADING:
2653 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2655 case MONO_APPDOMAIN_UNLOADED:
2656 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2659 g_warning ("Invalid appdomain state %d", prev_state);
2660 g_assert_not_reached ();
2664 mono_domain_set (domain, FALSE);
2665 /* Notify OnDomainUnload listeners */
2666 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2669 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2671 if (!mono_error_ok (&error)) {
2673 mono_error_cleanup (&error);
2675 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2679 /* Roll back the state change */
2680 domain->state = MONO_APPDOMAIN_CREATED;
2681 mono_domain_set (caller_domain, FALSE);
2684 mono_domain_set (caller_domain, FALSE);
2686 thread_data = g_new0 (unload_data, 1);
2687 thread_data->domain = domain;
2688 thread_data->failure_reason = NULL;
2689 thread_data->done = FALSE;
2690 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2692 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2693 domain->state = MONO_APPDOMAIN_UNLOADING;
2695 * First we create a separate thread for unloading, since
2696 * we might have to abort some threads, including the current one.
2698 * Have to attach to the runtime so shutdown can wait for this thread.
2700 * Force it to be attached to avoid racing during shutdown.
2702 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2703 mono_error_assert_ok (&error);
2705 thread_handle = mono_threads_open_thread_handle (internal->handle);
2707 /* Wait for the thread */
2708 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2709 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2710 /* The unload thread tries to abort us */
2711 /* The icall wrapper will execute the abort */
2712 mono_threads_close_thread_handle (thread_handle);
2713 unload_data_unref (thread_data);
2718 mono_threads_close_thread_handle (thread_handle);
2720 if (thread_data->failure_reason) {
2721 /* Roll back the state change */
2722 domain->state = MONO_APPDOMAIN_CREATED;
2724 g_warning ("%s", thread_data->failure_reason);
2726 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2728 g_free (thread_data->failure_reason);
2729 thread_data->failure_reason = NULL;
2732 unload_data_unref (thread_data);