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 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
117 static MonoLoadFunc load_function = NULL;
119 /* Lazy class loading functions */
120 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
122 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
125 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
128 mono_error_set_appdomain_unloaded (MonoError *error)
130 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
134 mono_install_runtime_load (MonoLoadFunc func)
136 load_function = func;
140 mono_runtime_load (const char *filename, const char *runtime_version)
142 g_assert (load_function);
143 return load_function (filename, runtime_version);
147 * mono_runtime_set_no_exec:
149 * Instructs the runtime to operate in static mode, i.e. avoid/do not
150 * allow managed code execution. This is useful for running the AOT
151 * compiler on platforms which allow full-aot execution only. This
152 * should be called before mono_runtime_init ().
155 mono_runtime_set_no_exec (gboolean val)
161 * mono_runtime_get_no_exec:
163 * If true, then the runtime will not allow managed code execution.
166 mono_runtime_get_no_exec (void)
172 create_domain_objects (MonoDomain *domain)
175 MonoDomain *old_domain = mono_domain_get ();
177 MonoVTable *string_vt;
178 MonoClassField *string_empty_fld;
180 if (domain != old_domain) {
181 mono_thread_push_appdomain_ref (domain);
182 mono_domain_set_internal_with_options (domain, FALSE);
186 * Initialize String.Empty. This enables the removal of
187 * the static cctor of the String class.
189 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
190 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
191 g_assert (string_empty_fld);
192 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
193 mono_error_assert_ok (&error);
194 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
195 domain->empty_string = empty_str;
198 * Create an instance early since we can't do it when there is no memory.
200 arg = mono_string_new (domain, "Out of memory");
201 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
202 mono_error_assert_ok (&error);
205 * These two are needed because the signal handlers might be executing on
206 * an alternate stack, and Boehm GC can't handle that.
208 arg = mono_string_new (domain, "A null value was found where an object instance was required");
209 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
210 mono_error_assert_ok (&error);
211 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
212 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
213 mono_error_assert_ok (&error);
215 /*The ephemeron tombstone i*/
216 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
217 mono_error_assert_ok (&error);
219 if (domain != old_domain) {
220 mono_thread_pop_appdomain_ref ();
221 mono_domain_set_internal_with_options (old_domain, FALSE);
225 * This class is used during exception handling, so initialize it here, to prevent
226 * stack overflows while handling stack overflows.
228 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
233 * \param domain domain returned by \c mono_init
235 * Initialize the core AppDomain: this function will run also some
236 * IL initialization code, so it needs the execution engine to be fully
239 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
240 * we know the \c entry_assembly.
244 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
247 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
248 mono_error_cleanup (&error);
252 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
254 MonoAppDomainSetup *setup;
260 mono_portability_helpers_init ();
262 mono_gc_base_init ();
263 mono_monitor_init ();
264 mono_marshal_init ();
266 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
267 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
268 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
269 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
270 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
271 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
272 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
274 mono_thread_init (start_cb, attach_cb);
276 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
277 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
278 return_if_nok (error);
280 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
282 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
283 return_if_nok (error);
287 domain->setup = setup;
289 mono_thread_attach (domain);
291 mono_type_initialization_init ();
293 if (!mono_runtime_get_no_exec ())
294 create_domain_objects (domain);
296 /* GC init has to happen after thread init */
299 /* contexts use GC handles, so they must be initialized after the GC */
300 mono_context_init_checked (domain, error);
301 return_if_nok (error);
302 mono_context_set (domain->default_context);
304 #ifndef DISABLE_SOCKETS
305 mono_network_init ();
308 mono_console_init ();
311 mono_locks_tracer_init ();
313 /* mscorlib is loaded before we install the load hook */
314 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
320 mono_get_corlib_version (void)
324 MonoClassField *field;
327 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
328 mono_class_init (klass);
329 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
332 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
334 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
335 mono_error_assert_ok (&error);
336 return *(gint32*)((gchar*)value + sizeof (MonoObject));
340 * mono_check_corlib_version:
341 * Checks that the corlib that is loaded matches the version of this runtime.
342 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
343 * allocated string with the error otherwise.
346 mono_check_corlib_version (void)
348 int version = mono_get_corlib_version ();
349 if (version != MONO_CORLIB_VERSION)
350 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
352 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
353 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
354 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
355 if (native_offset != managed_offset)
356 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
363 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
364 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
367 mono_context_init (MonoDomain *domain)
370 mono_context_init_checked (domain, &error);
371 mono_error_cleanup (&error);
375 mono_context_init_checked (MonoDomain *domain, MonoError *error)
378 MonoAppContext *context;
382 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
383 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
384 return_if_nok (error);
386 context->domain_id = domain->domain_id;
387 context->context_id = 0;
388 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
389 domain->default_context = context;
393 * mono_runtime_cleanup:
394 * \param domain unused.
398 * This must not be called while there are still running threads executing
402 mono_runtime_cleanup (MonoDomain *domain)
404 mono_attach_cleanup ();
406 /* This ends up calling any pending pending (for at most 2 seconds) */
409 mono_thread_cleanup ();
411 #ifndef DISABLE_SOCKETS
412 mono_network_cleanup ();
414 mono_marshal_cleanup ();
416 mono_type_initialization_cleanup ();
418 mono_monitor_cleanup ();
421 static MonoDomainFunc quit_function = NULL;
424 * mono_install_runtime_cleanup:
427 mono_install_runtime_cleanup (MonoDomainFunc func)
429 quit_function = func;
438 if (quit_function != NULL)
439 quit_function (mono_get_root_domain (), NULL);
443 * mono_domain_create_appdomain:
444 * \param friendly_name The friendly name of the appdomain to create
445 * \param configuration_file The configuration file to initialize the appdomain with
446 * \returns a \c MonoDomain initialized with the appdomain
449 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
451 HANDLE_FUNCTION_ENTER ();
453 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
454 mono_error_cleanup (&error);
455 HANDLE_FUNCTION_RETURN_VAL (domain);
459 * mono_domain_create_appdomain_checked:
460 * \param friendly_name The friendly name of the appdomain to create
461 * \param configuration_file The configuration file to initialize the appdomain with
462 * \param error Set on error.
464 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
467 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
469 HANDLE_FUNCTION_ENTER ();
471 MonoDomain *result = NULL;
473 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
474 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
477 MonoStringHandle config_file;
478 if (configuration_file != NULL) {
479 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
483 config_file = MONO_HANDLE_NEW (MonoString, NULL);
485 MONO_HANDLE_SET (setup, configuration_file, config_file);
487 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
491 result = mono_domain_from_appdomain_handle (ad);
493 HANDLE_FUNCTION_RETURN_VAL (result);
497 * mono_domain_set_config:
498 * \param domain \c MonoDomain initialized with the appdomain we want to change
499 * \param base_dir new base directory for the appdomain
500 * \param config_file_name path to the new configuration for the app domain
502 * Used to set the system configuration for an appdomain
504 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
505 * Error Initializing the configuration system. ---> System.ArgumentException:
506 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
509 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
511 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
512 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
515 static MonoAppDomainSetupHandle
516 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
518 HANDLE_FUNCTION_ENTER ();
519 MonoDomain *caller_domain;
520 MonoClass *ads_class;
521 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
525 caller_domain = mono_domain_get ();
526 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
528 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
532 mono_domain_set_internal (domain);
534 #define XCOPY_FIELD(dst,field,src,error) \
536 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
537 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
538 if (!is_ok (error)) \
540 MONO_HANDLE_SET ((dst),field,copied_val); \
543 #define COPY_VAL(dst,field,type,src) \
545 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
548 XCOPY_FIELD (copy, application_base, setup, error);
549 XCOPY_FIELD (copy, application_name, setup, error);
550 XCOPY_FIELD (copy, cache_path, setup, error);
551 XCOPY_FIELD (copy, configuration_file, setup, error);
552 XCOPY_FIELD (copy, dynamic_base, setup, error);
553 XCOPY_FIELD (copy, license_file, setup, error);
554 XCOPY_FIELD (copy, private_bin_path, setup, error);
555 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
556 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
557 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
558 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
559 COPY_VAL (copy, path_changed, MonoBoolean, setup);
560 COPY_VAL (copy, loader_optimization, int, setup);
561 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
562 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
563 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
564 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
565 XCOPY_FIELD (copy, application_trust, setup, error);
566 XCOPY_FIELD (copy, configuration_bytes, setup, error);
567 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
572 mono_domain_set_internal (caller_domain);
574 MONO_HANDLE_ASSIGN (result, copy);
576 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
579 static MonoAppDomainHandle
580 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
582 HANDLE_FUNCTION_ENTER ();
583 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
589 adclass = mono_class_get_appdomain_class ();
591 /* FIXME: pin all those objects */
592 data = mono_domain_create();
594 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
597 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
598 data->domain = MONO_HANDLE_RAW (ad);
599 data->friendly_name = g_strdup (friendly_name);
601 mono_profiler_appdomain_name (data, data->friendly_name);
603 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
604 if (MONO_HANDLE_IS_NULL (app_base)) {
605 /* Inherit from the root domain since MS.NET does this */
606 MonoDomain *root = mono_get_root_domain ();
607 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
608 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
609 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
610 /* N.B. new string is in the new domain */
611 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
612 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);
613 mono_gchandle_free (gchandle);
614 if (!is_ok (error)) {
615 g_free (data->friendly_name);
618 MONO_HANDLE_SET (setup, application_base, s);
622 mono_context_init_checked (data, error);
626 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
627 if (!mono_error_ok (error)) {
628 g_free (data->friendly_name);
632 mono_domain_set_options_from_config (data);
633 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
635 #ifndef DISABLE_SHADOW_COPY
636 /*FIXME, guard this for when the debugger is not running */
637 char *shadow_location = get_shadow_assembly_location_base (data, error);
638 if (!mono_error_ok (error)) {
639 g_free (data->friendly_name);
643 g_free (shadow_location);
646 create_domain_objects (data);
648 MONO_HANDLE_ASSIGN (result, ad);
650 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
654 * mono_domain_has_type_resolve:
655 * \param domain application domain being looked up
657 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
660 mono_domain_has_type_resolve (MonoDomain *domain)
662 static MonoClassField *field = NULL;
666 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
670 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
674 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
679 * mono_domain_try_type_resolve:
680 * \param domain application domainwhere the name where the type is going to be resolved
681 * \param name the name of the type to resolve or NULL.
682 * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
684 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
685 * the assembly that matches name.
687 * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
689 * \returns A \c MonoReflectionAssembly or NULL if not found
691 MonoReflectionAssembly *
692 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
695 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
696 mono_error_cleanup (&error);
701 MonoReflectionAssembly *
702 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
704 static MonoMethod *method = NULL;
705 MonoReflectionAssembly *ret;
710 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
712 if (method == NULL) {
713 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
714 if (method == NULL) {
715 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
721 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
725 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
726 return_val_if_nok (error, NULL);
732 * mono_domain_owns_vtable_slot:
733 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
736 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
740 mono_domain_lock (domain);
741 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
742 mono_domain_unlock (domain);
748 * \param domain domain
749 * \param force force setting.
751 * Set the current appdomain to \p domain. If \p force is set, set it even
752 * if it is being unloaded.
754 * \returns TRUE on success; FALSE if the domain is unloaded
757 mono_domain_set (MonoDomain *domain, gboolean force)
759 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
762 mono_domain_set_internal (domain);
768 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
772 if (MONO_HANDLE_IS_NULL (name)) {
773 mono_error_set_argument_null (error, "name", "");
777 g_assert (!MONO_HANDLE_IS_NULL (ad));
778 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
781 char *str = mono_string_handle_to_utf8 (name, error);
782 return_val_if_nok (error, NULL_HANDLE);
784 mono_domain_lock (add);
786 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
788 if (!strcmp (str, "APPBASE"))
789 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
790 else if (!strcmp (str, "APP_CONFIG_FILE"))
791 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
792 else if (!strcmp (str, "DYNAMIC_BASE"))
793 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
794 else if (!strcmp (str, "APP_NAME"))
795 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
796 else if (!strcmp (str, "CACHE_BASE"))
797 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
798 else if (!strcmp (str, "PRIVATE_BINPATH"))
799 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
800 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
801 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
802 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
803 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
804 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
805 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
807 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
809 mono_domain_unlock (add);
812 return MONO_HANDLE_CAST (MonoObject, o);
816 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
820 if (MONO_HANDLE_IS_NULL (name)) {
821 mono_error_set_argument_null (error, "name", "");
825 g_assert (!MONO_HANDLE_IS_NULL (ad));
826 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
829 mono_domain_lock (add);
831 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
833 mono_domain_unlock (add);
836 MonoAppDomainSetupHandle
837 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
840 g_assert (!MONO_HANDLE_IS_NULL (ad));
841 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
844 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
848 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
851 g_assert (!MONO_HANDLE_IS_NULL (ad));
852 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
855 return mono_string_new_handle (domain, domain->friendly_name, error);
859 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
862 MonoDomain *add = mono_domain_get ();
864 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
868 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
871 MonoDomain *root = mono_get_root_domain ();
873 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
877 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
879 MonoDomain *domain = mono_domain_get ();
881 return domain->throw_unobserved_task_exceptions;
885 get_attribute_value (const gchar **attribute_names,
886 const gchar **attribute_values,
887 const char *att_name)
890 for (n = 0; attribute_names [n] != NULL; n++) {
891 if (strcmp (attribute_names [n], att_name) == 0)
892 return g_strdup (attribute_values [n]);
898 start_element (GMarkupParseContext *context,
899 const gchar *element_name,
900 const gchar **attribute_names,
901 const gchar **attribute_values,
905 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
907 if (strcmp (element_name, "runtime") == 0) {
908 runtime_config->runtime_count++;
912 if (strcmp (element_name, "assemblyBinding") == 0) {
913 runtime_config->assemblybinding_count++;
917 if (runtime_config->runtime_count != 1)
920 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
921 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
923 if (value && g_ascii_strcasecmp (value, "true") == 0)
924 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
927 if (runtime_config->assemblybinding_count != 1)
930 if (strcmp (element_name, "probing") != 0)
933 g_free (runtime_config->domain->private_bin_path);
934 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
935 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
936 g_free (runtime_config->domain->private_bin_path);
937 runtime_config->domain->private_bin_path = NULL;
943 end_element (GMarkupParseContext *context,
944 const gchar *element_name,
948 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
949 if (strcmp (element_name, "runtime") == 0)
950 runtime_config->runtime_count--;
951 else if (strcmp (element_name, "assemblyBinding") == 0)
952 runtime_config->assemblybinding_count--;
956 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
958 RuntimeConfig *state = (RuntimeConfig *)user_data;
960 const gchar *filename;
962 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
963 msg = error && error->message ? error->message : "";
964 g_warning ("Error parsing %s: %s", filename, msg);
967 static const GMarkupParser
977 mono_domain_set_options_from_config (MonoDomain *domain)
980 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
982 GMarkupParseContext *context;
983 RuntimeConfig runtime_config;
986 if (!domain || !domain->setup || !domain->setup->configuration_file)
989 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
990 if (!mono_error_ok (&error)) {
991 mono_error_cleanup (&error);
995 config_file_path = mono_portability_find_file (config_file_name, TRUE);
996 if (!config_file_path)
997 config_file_path = config_file_name;
999 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1002 runtime_config.runtime_count = 0;
1003 runtime_config.assemblybinding_count = 0;
1004 runtime_config.domain = domain;
1005 runtime_config.filename = config_file_path;
1008 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1009 offset = 3; /* Skip UTF-8 BOM */
1011 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1012 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1013 g_markup_parse_context_end_parse (context, NULL);
1014 g_markup_parse_context_free (context);
1018 if (config_file_name != config_file_path)
1019 g_free (config_file_name);
1020 g_free (config_file_path);
1024 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1027 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1029 #ifdef DISABLE_APPDOMAINS
1030 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1034 fname = mono_string_handle_to_utf8 (friendly_name, error);
1035 return_val_if_nok (error, ad);
1036 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1043 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1045 HANDLE_FUNCTION_ENTER ();
1047 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1050 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1052 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1056 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1059 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1063 GPtrArray *assemblies;
1066 * Make a copy of the list of assemblies because we can't hold the assemblies
1067 * lock while creating objects etc.
1069 assemblies = g_ptr_array_new ();
1070 /* Need to skip internal assembly builders created by remoting */
1071 mono_domain_assemblies_lock (domain);
1072 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1073 ass = (MonoAssembly *)tmp->data;
1074 if (refonly != ass->ref_only)
1076 if (ass->corlib_internal)
1078 g_ptr_array_add (assemblies, ass);
1080 mono_domain_assemblies_unlock (domain);
1082 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1085 for (i = 0; i < assemblies->len; ++i) {
1086 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1091 g_ptr_array_free (assemblies, TRUE);
1096 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1098 HANDLE_FUNCTION_ENTER ();
1100 MonoAssembly *result = NULL;
1101 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1104 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1106 HANDLE_FUNCTION_RETURN_VAL (result);
1110 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1112 MonoAssembly *ret = NULL;
1114 MonoBoolean isrefonly;
1115 gpointer params [3];
1119 if (mono_runtime_get_no_exec ())
1122 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1124 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1125 g_assert (method != NULL);
1127 isrefonly = refonly ? 1 : 0;
1128 MonoReflectionAssemblyHandle requesting_handle;
1130 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1131 return_val_if_nok (error, ret);
1133 params [0] = MONO_HANDLE_RAW (fname);
1134 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1135 params [2] = &isrefonly;
1136 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1137 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1142 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1146 MonoAssembly *assembly;
1147 MonoDomain *domain = mono_domain_get ();
1150 aname_str = mono_stringify_assembly_name (aname);
1152 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1154 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1156 mono_error_cleanup (&error);
1162 * LOCKING: assumes assemblies_lock in the domain is already locked.
1165 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1169 gboolean destroy_ht = FALSE;
1171 if (!ass->aname.name)
1175 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1177 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1178 g_hash_table_insert (ht, tmp->data, tmp->data);
1182 /* FIXME: handle lazy loaded assemblies */
1184 if (!g_hash_table_lookup (ht, ass)) {
1185 mono_assembly_addref (ass);
1186 g_hash_table_insert (ht, ass, ass);
1187 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1188 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);
1191 if (ass->image->references) {
1192 for (i = 0; i < ass->image->nreferences; i++) {
1193 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1194 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1195 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1201 g_hash_table_destroy (ht);
1205 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1207 static MonoClassField *assembly_load_field;
1208 static MonoMethod *assembly_load_method;
1210 MonoDomain *domain = mono_domain_get ();
1212 gpointer load_value;
1215 if (!domain->domain)
1216 /* This can happen during startup */
1218 #ifdef ASSEMBLY_LOAD_DEBUG
1219 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1221 klass = domain->domain->mbr.obj.vtable->klass;
1223 mono_domain_assemblies_lock (domain);
1224 add_assemblies_to_domain (domain, assembly, NULL);
1225 mono_domain_assemblies_unlock (domain);
1227 if (assembly_load_field == NULL) {
1228 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1229 g_assert (assembly_load_field);
1232 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1233 if (load_value == NULL) {
1234 /* No events waiting to be triggered */
1238 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1239 mono_error_assert_ok (&error);
1241 if (assembly_load_method == NULL) {
1242 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1243 g_assert (assembly_load_method);
1246 *params = MONO_HANDLE_RAW(ref_assembly);
1248 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1249 mono_error_cleanup (&error);
1253 * LOCKING: Acquires the domain assemblies lock.
1256 set_domain_search_path (MonoDomain *domain)
1259 MonoAppDomainSetup *setup;
1261 gchar *search_path = NULL;
1264 gchar **pvt_split = NULL;
1265 GError *gerror = NULL;
1266 gint appbaselen = -1;
1269 * We use the low-level domain assemblies lock, since this is called from
1270 * assembly loads hooks, which means this thread might hold the loader lock.
1272 mono_domain_assemblies_lock (domain);
1274 if (!domain->setup) {
1275 mono_domain_assemblies_unlock (domain);
1279 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1280 mono_domain_assemblies_unlock (domain);
1283 setup = domain->setup;
1284 if (!setup->application_base) {
1285 mono_domain_assemblies_unlock (domain);
1286 return; /* Must set application base to get private path working */
1291 if (setup->private_bin_path) {
1292 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1293 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1294 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1295 mono_error_cleanup (&error);
1296 mono_domain_assemblies_unlock (domain);
1301 if (domain->private_bin_path) {
1302 if (search_path == NULL)
1303 search_path = domain->private_bin_path;
1305 gchar *tmp2 = search_path;
1306 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1313 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1314 * directories relative to ApplicationBase separated by semicolons (see
1315 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1316 * The loop below copes with the fact that some Unix applications may use ':' (or
1317 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1318 * ';' for the subsequent split.
1320 * The issue was reported in bug #81446
1323 #ifndef TARGET_WIN32
1326 slen = strlen (search_path);
1327 for (i = 0; i < slen; i++)
1328 if (search_path [i] == ':')
1329 search_path [i] = ';';
1332 pvt_split = g_strsplit (search_path, ";", 1000);
1333 g_free (search_path);
1334 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1339 g_strfreev (pvt_split);
1341 * Don't do this because the first time is called, the domain
1342 * setup is not finished.
1344 * domain->search_path = g_malloc (sizeof (char *));
1345 * domain->search_path [0] = NULL;
1347 mono_domain_assemblies_unlock (domain);
1351 if (domain->search_path)
1352 g_strfreev (domain->search_path);
1354 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1355 tmp [npaths] = NULL;
1357 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1358 if (!mono_error_ok (&error)) {
1359 mono_error_cleanup (&error);
1360 g_strfreev (pvt_split);
1363 mono_domain_assemblies_unlock (domain);
1367 domain->search_path = tmp;
1369 /* FIXME: is this needed? */
1370 if (strncmp (*tmp, "file://", 7) == 0) {
1376 uri = g_strdup_printf ("file:///%s", uri + 7);
1379 uri = mono_escape_uri_string (tmpuri);
1380 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1386 if (gerror != NULL) {
1387 g_warning ("%s\n", gerror->message);
1388 g_error_free (gerror);
1395 for (i = 1; pvt_split && i < npaths; i++) {
1396 if (g_path_is_absolute (pvt_split [i - 1])) {
1397 tmp [i] = g_strdup (pvt_split [i - 1]);
1399 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1402 if (strchr (tmp [i], '.')) {
1406 reduced = mono_path_canonicalize (tmp [i]);
1407 if (appbaselen == -1)
1408 appbaselen = strlen (tmp [0]);
1410 if (strncmp (tmp [0], reduced, appbaselen)) {
1413 tmp [i] = g_strdup ("");
1423 if (setup->private_bin_path_probe != NULL) {
1425 tmp [0] = g_strdup ("");
1428 domain->setup->path_changed = FALSE;
1430 g_strfreev (pvt_split);
1432 mono_domain_assemblies_unlock (domain);
1435 #ifdef DISABLE_SHADOW_COPY
1437 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1443 mono_make_shadow_copy (const char *filename, MonoError *error)
1446 return (char *) filename;
1450 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1452 guint16 *orig, *dest;
1453 gboolean copy_result;
1456 strcpy (src + srclen - tail_len, extension);
1458 if (IS_PORTABILITY_CASE) {
1459 gchar *file = mono_portability_find_file (src, TRUE);
1465 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1469 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1471 strcpy (target + targetlen - tail_len, extension);
1472 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1474 mono_w32file_delete (dest);
1476 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1478 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1479 * overwritten when updated in their original locations. */
1481 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1490 get_cstring_hash (const char *str)
1496 if (!str || !str [0])
1501 for (i = 0; i < len; i++) {
1502 h = (h << 5) - h + *p;
1510 * Returned memory is malloc'd. Called must free it
1513 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1515 MonoAppDomainSetup *setup;
1516 char *cache_path, *appname;
1522 setup = domain->setup;
1523 if (setup->cache_path != NULL && setup->application_name != NULL) {
1524 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1525 return_val_if_nok (error, NULL);
1527 #ifndef TARGET_WIN32
1530 for (i = strlen (cache_path) - 1; i >= 0; i--)
1531 if (cache_path [i] == '\\')
1532 cache_path [i] = '/';
1536 appname = mono_string_to_utf8_checked (setup->application_name, error);
1537 if (!mono_error_ok (error)) {
1538 g_free (cache_path);
1542 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1544 g_free (cache_path);
1546 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1547 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1554 get_shadow_assembly_location (const char *filename, MonoError *error)
1556 gint32 hash = 0, hash2 = 0;
1558 char path_hash [30];
1559 char *bname = g_path_get_basename (filename);
1560 char *dirname = g_path_get_dirname (filename);
1561 char *location, *tmploc;
1562 MonoDomain *domain = mono_domain_get ();
1566 hash = get_cstring_hash (bname);
1567 hash2 = get_cstring_hash (dirname);
1568 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1569 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1570 tmploc = get_shadow_assembly_location_base (domain, error);
1571 if (!mono_error_ok (error)) {
1577 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1585 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1587 struct stat sbuf_dest;
1589 gchar *real_src = mono_portability_find_file (src, TRUE);
1592 stat_src = (gchar*)src;
1594 stat_src = real_src;
1596 if (stat (stat_src, sbuf_src) == -1) {
1597 time_t tnow = time (NULL);
1602 memset (sbuf_src, 0, sizeof (*sbuf_src));
1603 sbuf_src->st_mtime = tnow;
1604 sbuf_src->st_atime = tnow;
1611 if (stat (dest, &sbuf_dest) == -1)
1614 if (sbuf_src->st_size == sbuf_dest.st_size &&
1615 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1622 shadow_copy_create_ini (const char *shadow, const char *filename)
1632 dir_name = g_path_get_dirname (shadow);
1633 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1635 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1640 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1645 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1647 if (handle == INVALID_HANDLE_VALUE) {
1651 full_path = mono_path_resolve_symlinks (filename);
1652 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1654 mono_w32file_close (handle);
1659 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1662 MonoAppDomainSetup *setup;
1665 gchar **directories;
1666 gchar *shadow_status_string;
1668 gboolean shadow_enabled;
1669 gboolean found = FALSE;
1674 setup = domain->setup;
1675 if (setup == NULL || setup->shadow_copy_files == NULL)
1678 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1679 if (!mono_error_ok (&error)) {
1680 mono_error_cleanup (&error);
1683 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1684 g_free (shadow_status_string);
1686 if (!shadow_enabled)
1689 if (setup->shadow_copy_directories == NULL)
1692 /* Is dir_name a shadow_copy destination already? */
1693 base_dir = get_shadow_assembly_location_base (domain, &error);
1694 if (!mono_error_ok (&error)) {
1695 mono_error_cleanup (&error);
1699 if (strstr (dir_name, base_dir)) {
1705 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1706 if (!mono_error_ok (&error)) {
1707 mono_error_cleanup (&error);
1711 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1712 dir_ptr = directories;
1714 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1720 g_strfreev (directories);
1726 This function raises exceptions so it can cause as sorts of nasty stuff if called
1727 while holding a lock.
1728 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1729 or NULL if source file not found.
1730 FIXME bubble up the error instead of raising it here
1733 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1736 gchar *sibling_source, *sibling_target;
1737 gint sibling_source_len, sibling_target_len;
1738 guint16 *orig, *dest;
1741 gboolean copy_result;
1742 struct stat src_sbuf;
1743 struct utimbuf utbuf;
1744 char *dir_name = g_path_get_dirname (filename);
1745 MonoDomain *domain = mono_domain_get ();
1749 error_init (oerror);
1751 set_domain_search_path (domain);
1753 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1755 return (char *) filename;
1758 /* Is dir_name a shadow_copy destination already? */
1759 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1760 if (!mono_error_ok (&error)) {
1761 mono_error_cleanup (&error);
1763 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1767 if (strstr (dir_name, shadow_dir)) {
1768 g_free (shadow_dir);
1770 return (char *) filename;
1772 g_free (shadow_dir);
1775 shadow = get_shadow_assembly_location (filename, &error);
1776 if (!mono_error_ok (&error)) {
1777 mono_error_cleanup (&error);
1778 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1782 if (g_ensure_directory_exists (shadow) == FALSE) {
1784 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1788 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1789 return (char*) shadow;
1791 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1792 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1793 mono_w32file_delete (dest);
1795 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1796 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1797 * and not have it runtime error" */
1798 attrs = mono_w32file_get_attributes (orig);
1799 if (attrs == INVALID_FILE_ATTRIBUTES) {
1801 return (char *)filename;
1804 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1806 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1807 * overwritten when updated in their original locations. */
1809 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1814 if (copy_result == FALSE) {
1817 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1818 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1819 return NULL; /* file not found, shadow copy failed */
1821 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1825 /* attempt to copy .mdb, .config if they exist */
1826 sibling_source = g_strconcat (filename, ".config", NULL);
1827 sibling_source_len = strlen (sibling_source);
1828 sibling_target = g_strconcat (shadow, ".config", NULL);
1829 sibling_target_len = strlen (sibling_target);
1831 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1833 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1835 g_free (sibling_source);
1836 g_free (sibling_target);
1840 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1844 /* Create a .ini file containing the original assembly location */
1845 if (!shadow_copy_create_ini (shadow, filename)) {
1847 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1851 utbuf.actime = src_sbuf.st_atime;
1852 utbuf.modtime = src_sbuf.st_mtime;
1853 utime (shadow, &utbuf);
1857 #endif /* DISABLE_SHADOW_COPY */
1860 * mono_domain_from_appdomain:
1863 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1865 HANDLE_FUNCTION_ENTER ();
1866 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1867 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1868 HANDLE_FUNCTION_RETURN_VAL (result);
1872 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1874 HANDLE_FUNCTION_ENTER ();
1875 MonoDomain *dom = NULL;
1876 if (MONO_HANDLE_IS_NULL (appdomain))
1879 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1880 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1881 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1883 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1885 dom = MONO_HANDLE_GETVAL (appdomain, data);
1888 HANDLE_FUNCTION_RETURN_VAL (dom);
1893 try_load_from (MonoAssembly **assembly,
1894 const gchar *path1, const gchar *path2,
1895 const gchar *path3, const gchar *path4,
1896 gboolean refonly, gboolean is_private,
1897 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1900 gboolean found = FALSE;
1903 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1905 if (IS_PORTABILITY_SET) {
1906 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1909 fullpath = new_fullpath;
1913 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1916 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1919 return (*assembly != NULL);
1922 static MonoAssembly *
1923 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1925 MonoAssembly *result = NULL;
1928 const gchar *local_culture;
1930 gboolean is_private = FALSE;
1932 if (!culture || *culture == '\0') {
1935 local_culture = culture;
1938 filename = g_strconcat (name, ".dll", NULL);
1939 len = strlen (filename);
1941 for (path = search_path; *path; path++) {
1942 if (**path == '\0') {
1944 continue; /* Ignore empty ApplicationBase */
1947 /* See test cases in bug #58992 and bug #57710 */
1948 /* 1st try: [culture]/[name].dll (culture may be empty) */
1949 strcpy (filename + len - 4, ".dll");
1950 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1953 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1954 strcpy (filename + len - 4, ".exe");
1955 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1958 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1959 strcpy (filename + len - 4, ".dll");
1960 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1963 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1964 strcpy (filename + len - 4, ".exe");
1965 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
1974 * Try loading the assembly from ApplicationBase and PrivateBinPath
1975 * and then from assemblies_path if any.
1976 * LOCKING: This is called from the assembly loading code, which means the caller
1977 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1979 static MonoAssembly *
1980 mono_domain_assembly_preload (MonoAssemblyName *aname,
1981 gchar **assemblies_path,
1984 MonoDomain *domain = mono_domain_get ();
1985 MonoAssembly *result = NULL;
1986 gboolean refonly = GPOINTER_TO_UINT (user_data);
1988 set_domain_search_path (domain);
1990 if (domain->search_path && domain->search_path [0] != NULL) {
1991 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
1992 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
1993 for (int i = 0; domain->search_path [i]; i++) {
1994 const char *p = domain->search_path[i];
1995 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
1997 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
1999 result = real_load (domain->search_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2002 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2003 result = real_load (assemblies_path, aname->culture, aname->name, refonly, &mono_assembly_candidate_predicate_sn_same_name, aname);
2010 * Check whenever a given assembly was already loaded in the current appdomain.
2012 static MonoAssembly *
2013 mono_domain_assembly_search (MonoAssemblyName *aname,
2016 MonoDomain *domain = mono_domain_get ();
2019 gboolean refonly = GPOINTER_TO_UINT (user_data);
2021 mono_domain_assemblies_lock (domain);
2022 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2023 ass = (MonoAssembly *)tmp->data;
2024 /* Dynamic assemblies can't match here in MS.NET */
2025 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2028 mono_domain_assemblies_unlock (domain);
2031 mono_domain_assemblies_unlock (domain);
2036 MonoReflectionAssemblyHandle
2037 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2040 MonoDomain *domain = mono_domain_get ();
2041 char *name, *filename;
2042 MonoImageOpenStatus status = MONO_IMAGE_OK;
2043 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2048 if (fname == NULL) {
2049 mono_error_set_argument_null (error, "assemblyFile", "");
2053 name = filename = mono_string_handle_to_utf8 (fname, error);
2057 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2060 if (status == MONO_IMAGE_IMAGE_INVALID)
2061 mono_error_set_bad_image_name (error, g_strdup (name), "");
2063 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2067 result = mono_assembly_get_object_handle (domain, ass, error);
2074 MonoReflectionAssemblyHandle
2075 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2076 MonoArrayHandle raw_assembly,
2077 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2078 MonoBoolean refonly,
2083 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2084 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2085 MonoImageOpenStatus status;
2086 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2088 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2089 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2090 if (!assembly_data) {
2091 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2095 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2096 memcpy (assembly_data, raw_data, raw_assembly_len);
2097 mono_gchandle_free (gchandle); /* unpin */
2098 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2100 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2103 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2107 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2108 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2109 uint32_t symbol_gchandle;
2110 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2111 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2112 mono_gchandle_free (symbol_gchandle);
2115 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2119 mono_image_close (image);
2120 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2124 refass = mono_assembly_get_object_handle (domain, ass, error);
2125 if (!MONO_HANDLE_IS_NULL(refass))
2126 MONO_HANDLE_SET (refass, evidence, evidence);
2130 MonoReflectionAssemblyHandle
2131 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2134 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2135 MonoImageOpenStatus status = MONO_IMAGE_OK;
2137 MonoAssemblyName aname;
2143 name = mono_string_handle_to_utf8 (assRef, error);
2146 parsed = mono_assembly_name_parse (name, &aname);
2150 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2151 /* This is a parse error... */
2153 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2157 refass = mono_assembly_get_object_handle (domain, assm, error);
2165 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2166 mono_assembly_name_free (&aname);
2169 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2171 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2180 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2184 MONO_HANDLE_SET (refass, evidence, evidence);
2188 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2192 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2195 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2197 if (NULL == domain) {
2198 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2202 if (domain == mono_get_root_domain ()) {
2203 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2208 * Unloading seems to cause problems when running NUnit/NAnt, hence
2211 if (g_getenv ("MONO_NO_UNLOAD"))
2213 #ifdef __native_client__
2217 MonoException *exc = NULL;
2218 mono_domain_try_unload (domain, (MonoObject**)&exc);
2220 mono_error_set_exception_instance (error, exc);
2224 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2227 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2232 return mono_domain_is_unloading (domain);
2236 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2238 mono_unhandled_exception ((MonoObject*) exc);
2242 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2243 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2250 g_assert (!MONO_HANDLE_IS_NULL (refass));
2251 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2252 image = assembly->image;
2255 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2258 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2260 if (MONO_HANDLE_IS_NULL (args)) {
2261 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2262 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2263 mono_error_assert_ok (error);
2266 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2271 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2273 return ad->data->domain_id;
2277 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2280 MonoDomain *old_domain = mono_domain_get ();
2282 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2283 mono_error_set_appdomain_unloaded (error);
2284 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2287 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2291 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2293 MonoDomain *current_domain = mono_domain_get ();
2294 MonoDomain *domain = mono_domain_get_by_id (domainid);
2296 if (!domain || !mono_domain_set (domain, FALSE)) {
2297 mono_error_set_appdomain_unloaded (error);
2298 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2301 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2305 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2308 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2312 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2315 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2319 * Raise an exception to prevent the managed code from executing a pop
2322 mono_error_set_appdomain_unloaded (error);
2326 mono_thread_push_appdomain_ref (domain);
2330 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2333 mono_thread_pop_appdomain_ref ();
2337 ves_icall_System_AppDomain_InternalGetContext ()
2339 return mono_context_get ();
2343 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2345 return mono_domain_get ()->default_context;
2349 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2351 MonoAppContext *old_context = mono_context_get ();
2353 mono_context_set (mc);
2359 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2362 MonoDomain* mono_root_domain = mono_get_root_domain ();
2363 mono_domain_lock (mono_root_domain);
2364 if (process_guid_set) {
2365 mono_domain_unlock (mono_root_domain);
2366 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2368 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2369 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2370 mono_gchandle_free (gchandle);
2371 process_guid_set = TRUE;
2372 mono_domain_unlock (mono_root_domain);
2377 * mono_domain_is_unloading:
2380 mono_domain_is_unloading (MonoDomain *domain)
2382 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2389 clear_cached_vtable (MonoVTable *vtable)
2391 MonoClass *klass = vtable->klass;
2392 MonoDomain *domain = vtable->domain;
2393 MonoClassRuntimeInfo *runtime_info;
2396 runtime_info = klass->runtime_info;
2397 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2398 runtime_info->domain_vtables [domain->domain_id] = NULL;
2399 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2400 mono_gc_free_fixed (data);
2403 static G_GNUC_UNUSED void
2404 zero_static_data (MonoVTable *vtable)
2406 MonoClass *klass = vtable->klass;
2409 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2410 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2413 typedef struct unload_data {
2416 char *failure_reason;
2421 unload_data_unref (unload_data *data)
2425 mono_atomic_load_acquire (count, gint32, &data->refcount);
2426 g_assert (count >= 1 && count <= 2);
2431 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2435 deregister_reflection_info_roots_from_list (MonoImage *image)
2437 GSList *list = image->reflection_info_unregister_classes;
2440 MonoClass *klass = (MonoClass *)list->data;
2442 mono_class_free_ref_info (klass);
2447 image->reflection_info_unregister_classes = NULL;
2451 deregister_reflection_info_roots (MonoDomain *domain)
2455 mono_domain_assemblies_lock (domain);
2456 for (list = domain->domain_assemblies; list; list = list->next) {
2457 MonoAssembly *assembly = (MonoAssembly *)list->data;
2458 MonoImage *image = assembly->image;
2462 * No need to take the image lock here since dynamic images are appdomain bound and
2463 * at this point the mutator is gone. Taking the image lock here would mean
2464 * promoting it from a simple lock to a complex lock, which we better avoid if
2467 if (image_is_dynamic (image))
2468 deregister_reflection_info_roots_from_list (image);
2470 for (i = 0; i < image->module_count; ++i) {
2471 MonoImage *module = image->modules [i];
2472 if (module && image_is_dynamic (module))
2473 deregister_reflection_info_roots_from_list (module);
2476 mono_domain_assemblies_unlock (domain);
2480 unload_thread_main (void *arg)
2483 unload_data *data = (unload_data*)arg;
2484 MonoDomain *domain = data->domain;
2485 MonoInternalThread *internal;
2488 internal = mono_thread_internal_current ();
2490 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2491 if (!is_ok (&error)) {
2492 data->failure_reason = g_strdup (mono_error_get_message (&error));
2493 mono_error_cleanup (&error);
2498 * FIXME: Abort our parent thread last, so we can return a failure
2499 * indication if aborting times out.
2501 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2502 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2506 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2507 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2511 /* Finalize all finalizable objects in the doomed appdomain */
2512 if (!mono_domain_finalize (domain, -1)) {
2513 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2517 /* Clear references to our vtables in class->runtime_info.
2518 * We also hold the loader lock because we're going to change
2519 * class->runtime_info.
2522 mono_loader_lock (); //FIXME why do we need the loader lock here?
2523 mono_domain_lock (domain);
2526 * We need to make sure that we don't have any remsets
2527 * pointing into static data of the to-be-freed domain because
2528 * at the next collections they would be invalid. So what we
2529 * do is we first zero all static data and then do a minor
2530 * collection. Because all references in the static data will
2531 * now be null we won't do any unnecessary copies and after
2532 * the collection there won't be any more remsets.
2534 for (i = 0; i < domain->class_vtable_array->len; ++i)
2535 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2536 mono_gc_collect (0);
2538 for (i = 0; i < domain->class_vtable_array->len; ++i)
2539 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2540 deregister_reflection_info_roots (domain);
2542 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2544 mono_domain_unlock (domain);
2545 mono_loader_unlock ();
2547 domain->state = MONO_APPDOMAIN_UNLOADED;
2549 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2551 /* remove from the handle table the items related to this domain */
2552 mono_gchandle_free_domain (domain);
2554 mono_domain_free (domain, FALSE);
2556 mono_gc_collect (mono_gc_max_generation ());
2558 mono_atomic_store_release (&data->done, TRUE);
2559 unload_data_unref (data);
2563 mono_atomic_store_release (&data->done, TRUE);
2564 unload_data_unref (data);
2569 * mono_domain_unload:
2570 * \param domain The domain to unload
2572 * Unloads an appdomain. Follows the process outlined in the comment
2573 * for \c mono_domain_try_unload.
2576 mono_domain_unload (MonoDomain *domain)
2578 MonoObject *exc = NULL;
2579 mono_domain_try_unload (domain, &exc);
2582 static MonoThreadInfoWaitRet
2583 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2585 MonoThreadInfoWaitRet result;
2588 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2595 * mono_domain_unload:
2596 * \param domain The domain to unload
2597 * \param exc Exception information
2599 * Unloads an appdomain. Follows the process outlined in:
2600 * http://blogs.gotdotnet.com/cbrumme
2602 * If doing things the 'right' way is too hard or complex, we do it the
2603 * 'simple' way, which means do everything needed to avoid crashes and
2604 * memory leaks, but not much else.
2606 * It is required to pass a valid reference to the exc argument, upon return
2607 * from this function *exc will be set to the exception thrown, if any.
2609 * If this method is not called from an icall (embedded scenario for instance),
2610 * it must not be called with any managed frames on the stack, since the unload
2611 * process could end up trying to abort the current thread.
2614 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2617 MonoThreadHandle *thread_handle;
2618 MonoAppDomainState prev_state;
2620 unload_data *thread_data;
2621 MonoInternalThread *internal;
2622 MonoDomain *caller_domain = mono_domain_get ();
2624 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2626 /* Atomically change our state to UNLOADING */
2627 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2628 MONO_APPDOMAIN_UNLOADING_START,
2629 MONO_APPDOMAIN_CREATED);
2630 if (prev_state != MONO_APPDOMAIN_CREATED) {
2631 switch (prev_state) {
2632 case MONO_APPDOMAIN_UNLOADING_START:
2633 case MONO_APPDOMAIN_UNLOADING:
2634 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2636 case MONO_APPDOMAIN_UNLOADED:
2637 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2640 g_warning ("Invalid appdomain state %d", prev_state);
2641 g_assert_not_reached ();
2645 mono_domain_set (domain, FALSE);
2646 /* Notify OnDomainUnload listeners */
2647 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2650 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2652 if (!mono_error_ok (&error)) {
2654 mono_error_cleanup (&error);
2656 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2660 /* Roll back the state change */
2661 domain->state = MONO_APPDOMAIN_CREATED;
2662 mono_domain_set (caller_domain, FALSE);
2665 mono_domain_set (caller_domain, FALSE);
2667 thread_data = g_new0 (unload_data, 1);
2668 thread_data->domain = domain;
2669 thread_data->failure_reason = NULL;
2670 thread_data->done = FALSE;
2671 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2673 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2674 domain->state = MONO_APPDOMAIN_UNLOADING;
2676 * First we create a separate thread for unloading, since
2677 * we might have to abort some threads, including the current one.
2679 * Have to attach to the runtime so shutdown can wait for this thread.
2681 * Force it to be attached to avoid racing during shutdown.
2683 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2684 mono_error_assert_ok (&error);
2686 thread_handle = mono_threads_open_thread_handle (internal->handle);
2688 /* Wait for the thread */
2689 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2690 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2691 /* The unload thread tries to abort us */
2692 /* The icall wrapper will execute the abort */
2693 mono_threads_close_thread_handle (thread_handle);
2694 unload_data_unref (thread_data);
2699 mono_threads_close_thread_handle (thread_handle);
2701 if (thread_data->failure_reason) {
2702 /* Roll back the state change */
2703 domain->state = MONO_APPDOMAIN_CREATED;
2705 g_warning ("%s", thread_data->failure_reason);
2707 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2709 g_free (thread_data->failure_reason);
2710 thread_data->failure_reason = NULL;
2713 unload_data_unref (thread_data);