2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/appdomain-icalls.h>
39 #include <mono/metadata/domain-internals.h>
40 #include "mono/metadata/metadata-internals.h"
41 #include <mono/metadata/assembly.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/mono-debug-debugger.h>
54 #include <mono/metadata/attach.h>
55 #include <mono/metadata/w32file.h>
56 #include <mono/metadata/lock-tracer.h>
57 #include <mono/metadata/console-io.h>
58 #include <mono/metadata/threads-types.h>
59 #include <mono/metadata/tokentype.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/reflection-internals.h>
62 #include <mono/metadata/abi-details.h>
63 #include <mono/metadata/w32socket.h>
64 #include <mono/utils/mono-uri.h>
65 #include <mono/utils/mono-logger-internals.h>
66 #include <mono/utils/mono-path.h>
67 #include <mono/utils/mono-stdlib.h>
68 #include <mono/utils/mono-io-portability.h>
69 #include <mono/utils/mono-error-internals.h>
70 #include <mono/utils/atomic.h>
71 #include <mono/utils/mono-memory-model.h>
72 #include <mono/utils/mono-threads.h>
73 #include <mono/metadata/w32handle.h>
74 #include <mono/metadata/w32error.h>
75 #include <mono/utils/w32api.h>
81 * This is the version number of the corlib-runtime interface. When
82 * making changes to this interface (by changing the layout
83 * of classes the runtime knows about, changing icall signature or
84 * semantics etc), increment this variable. Also increment the
85 * pair of this variable in mscorlib in:
86 * mcs/class/corlib/System/Environment.cs
88 * Changes which are already detected at runtime, like the addition
89 * of icalls, do not require an increment.
91 #define MONO_CORLIB_VERSION 164
96 int assemblybinding_count;
101 static gunichar2 process_guid [36];
102 static gboolean process_guid_set = FALSE;
104 static gboolean no_exec = FALSE;
106 static MonoAssembly *
107 mono_domain_assembly_preload (MonoAssemblyName *aname,
108 gchar **assemblies_path,
111 static MonoAssembly *
112 mono_domain_assembly_search (MonoAssemblyName *aname,
116 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
119 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
121 static MonoAppDomainHandle
122 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
125 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
129 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
131 static MonoLoadFunc load_function = NULL;
133 /* Lazy class loading functions */
134 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
136 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
139 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
142 mono_error_set_appdomain_unloaded (MonoError *error)
144 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
148 mono_install_runtime_load (MonoLoadFunc func)
150 load_function = func;
154 mono_runtime_load (const char *filename, const char *runtime_version)
156 g_assert (load_function);
157 return load_function (filename, runtime_version);
161 * mono_runtime_set_no_exec:
163 * Instructs the runtime to operate in static mode, i.e. avoid/do not
164 * allow managed code execution. This is useful for running the AOT
165 * compiler on platforms which allow full-aot execution only. This
166 * should be called before mono_runtime_init ().
169 mono_runtime_set_no_exec (gboolean val)
175 * mono_runtime_get_no_exec:
177 * If true, then the runtime will not allow managed code execution.
180 mono_runtime_get_no_exec (void)
186 create_domain_objects (MonoDomain *domain)
189 MonoDomain *old_domain = mono_domain_get ();
191 MonoVTable *string_vt;
192 MonoClassField *string_empty_fld;
194 if (domain != old_domain) {
195 mono_thread_push_appdomain_ref (domain);
196 mono_domain_set_internal_with_options (domain, FALSE);
200 * Initialize String.Empty. This enables the removal of
201 * the static cctor of the String class.
203 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
204 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
205 g_assert (string_empty_fld);
206 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
207 mono_error_assert_ok (&error);
208 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
209 domain->empty_string = empty_str;
212 * Create an instance early since we can't do it when there is no memory.
214 arg = mono_string_new (domain, "Out of memory");
215 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
216 mono_error_assert_ok (&error);
219 * These two are needed because the signal handlers might be executing on
220 * an alternate stack, and Boehm GC can't handle that.
222 arg = mono_string_new (domain, "A null value was found where an object instance was required");
223 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
224 mono_error_assert_ok (&error);
225 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
226 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
227 mono_error_assert_ok (&error);
229 /*The ephemeron tombstone i*/
230 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
231 mono_error_assert_ok (&error);
233 if (domain != old_domain) {
234 mono_thread_pop_appdomain_ref ();
235 mono_domain_set_internal_with_options (old_domain, FALSE);
239 * This class is used during exception handling, so initialize it here, to prevent
240 * stack overflows while handling stack overflows.
242 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
247 * @domain: domain returned by mono_init ()
249 * Initialize the core AppDomain: this function will run also some
250 * IL initialization code, so it needs the execution engine to be fully
253 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
254 * we know the entry_assembly.
258 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
261 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
262 mono_error_cleanup (&error);
266 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
268 MonoAppDomainSetup *setup;
274 mono_portability_helpers_init ();
276 mono_gc_base_init ();
277 mono_monitor_init ();
278 mono_marshal_init ();
280 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
281 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
282 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
283 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
284 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
285 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
286 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
288 mono_thread_init (start_cb, attach_cb);
290 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
291 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
292 return_if_nok (error);
294 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
296 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
297 return_if_nok (error);
301 domain->setup = setup;
303 mono_thread_attach (domain);
305 mono_type_initialization_init ();
307 if (!mono_runtime_get_no_exec ())
308 create_domain_objects (domain);
310 /* GC init has to happen after thread init */
313 /* contexts use GC handles, so they must be initialized after the GC */
314 mono_context_init_checked (domain, error);
315 return_if_nok (error);
316 mono_context_set (domain->default_context);
318 #ifndef DISABLE_SOCKETS
319 mono_network_init ();
322 mono_console_init ();
325 mono_locks_tracer_init ();
327 /* mscorlib is loaded before we install the load hook */
328 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
334 mono_get_corlib_version (void)
338 MonoClassField *field;
341 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
342 mono_class_init (klass);
343 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
346 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
348 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
349 mono_error_assert_ok (&error);
350 return *(gint32*)((gchar*)value + sizeof (MonoObject));
354 * mono_check_corlib_version
356 * Checks that the corlib that is loaded matches the version of this runtime.
358 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
359 * allocated string with the error otherwise.
362 mono_check_corlib_version (void)
364 int version = mono_get_corlib_version ();
365 if (version != MONO_CORLIB_VERSION)
366 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
368 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
369 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
370 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
371 if (native_offset != managed_offset)
372 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
379 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
381 * Initializes the @domain's default System.Runtime.Remoting's Context.
384 mono_context_init (MonoDomain *domain)
387 mono_context_init_checked (domain, &error);
388 mono_error_cleanup (&error);
392 mono_context_init_checked (MonoDomain *domain, MonoError *error)
395 MonoAppContext *context;
399 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
400 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
401 return_if_nok (error);
403 context->domain_id = domain->domain_id;
404 context->context_id = 0;
405 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
406 domain->default_context = context;
410 * mono_runtime_cleanup:
415 * This must not be called while there are still running threads executing
419 mono_runtime_cleanup (MonoDomain *domain)
421 mono_attach_cleanup ();
423 /* This ends up calling any pending pending (for at most 2 seconds) */
426 mono_thread_cleanup ();
428 #ifndef DISABLE_SOCKETS
429 mono_network_cleanup ();
431 mono_marshal_cleanup ();
433 mono_type_initialization_cleanup ();
435 mono_monitor_cleanup ();
438 static MonoDomainFunc quit_function = NULL;
441 mono_install_runtime_cleanup (MonoDomainFunc func)
443 quit_function = func;
449 if (quit_function != NULL)
450 quit_function (mono_get_root_domain (), NULL);
454 * mono_domain_create_appdomain:
455 * @friendly_name: The friendly name of the appdomain to create
456 * @configuration_file: The configuration file to initialize the appdomain with
458 * Returns a MonoDomain initialized with the appdomain
461 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
463 HANDLE_FUNCTION_ENTER ();
465 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
466 mono_error_cleanup (&error);
467 HANDLE_FUNCTION_RETURN_VAL (domain);
471 * mono_domain_create_appdomain_checked:
472 * @friendly_name: The friendly name of the appdomain to create
473 * @configuration_file: The configuration file to initialize the appdomain with
474 * @error: Set on error.
476 * Returns a MonoDomain initialized with the appdomain. On failure sets @error and returns NULL.
479 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
481 HANDLE_FUNCTION_ENTER ();
483 MonoDomain *result = NULL;
485 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
486 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
489 MonoStringHandle config_file;
490 if (configuration_file != NULL) {
491 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
495 config_file = MONO_HANDLE_NEW (MonoString, NULL);
497 MONO_HANDLE_SET (setup, configuration_file, config_file);
499 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
503 result = mono_domain_from_appdomain_handle (ad);
505 HANDLE_FUNCTION_RETURN_VAL (result);
509 * mono_domain_set_config:
510 * @domain: MonoDomain initialized with the appdomain we want to change
511 * @base_dir: new base directory for the appdomain
512 * @config_file_name: path to the new configuration for the app domain
514 * Used to set the system configuration for an appdomain
516 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
517 * Error Initializing the configuration system. ---> System.ArgumentException:
518 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
521 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
523 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
524 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
527 static MonoAppDomainSetupHandle
528 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
530 HANDLE_FUNCTION_ENTER ();
531 MonoDomain *caller_domain;
532 MonoClass *ads_class;
533 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
537 caller_domain = mono_domain_get ();
538 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
540 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
544 mono_domain_set_internal (domain);
546 #define XCOPY_FIELD(dst,field,src,error) \
548 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
549 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
550 if (!is_ok (error)) \
552 MONO_HANDLE_SET ((dst),field,copied_val); \
555 #define COPY_VAL(dst,field,type,src) \
557 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
560 XCOPY_FIELD (copy, application_base, setup, error);
561 XCOPY_FIELD (copy, application_name, setup, error);
562 XCOPY_FIELD (copy, cache_path, setup, error);
563 XCOPY_FIELD (copy, configuration_file, setup, error);
564 XCOPY_FIELD (copy, dynamic_base, setup, error);
565 XCOPY_FIELD (copy, license_file, setup, error);
566 XCOPY_FIELD (copy, private_bin_path, setup, error);
567 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
568 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
569 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
570 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
571 COPY_VAL (copy, path_changed, MonoBoolean, setup);
572 COPY_VAL (copy, loader_optimization, int, setup);
573 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
574 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
575 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
576 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
577 XCOPY_FIELD (copy, application_trust, setup, error);
578 XCOPY_FIELD (copy, configuration_bytes, setup, error);
579 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
584 mono_domain_set_internal (caller_domain);
586 MONO_HANDLE_ASSIGN (result, copy);
588 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
591 static MonoAppDomainHandle
592 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
594 HANDLE_FUNCTION_ENTER ();
595 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
601 adclass = mono_class_get_appdomain_class ();
603 /* FIXME: pin all those objects */
604 data = mono_domain_create();
606 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
609 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
610 data->domain = MONO_HANDLE_RAW (ad);
611 data->friendly_name = g_strdup (friendly_name);
613 mono_profiler_appdomain_name (data, data->friendly_name);
615 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
616 if (MONO_HANDLE_IS_NULL (app_base)) {
617 /* Inherit from the root domain since MS.NET does this */
618 MonoDomain *root = mono_get_root_domain ();
619 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
620 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
621 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
622 /* N.B. new string is in the new domain */
623 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
624 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);
625 mono_gchandle_free (gchandle);
626 if (!is_ok (error)) {
627 g_free (data->friendly_name);
630 MONO_HANDLE_SET (setup, application_base, s);
634 mono_context_init_checked (data, error);
638 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
639 if (!mono_error_ok (error)) {
640 g_free (data->friendly_name);
644 mono_domain_set_options_from_config (data);
645 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
647 #ifndef DISABLE_SHADOW_COPY
648 /*FIXME, guard this for when the debugger is not running */
649 char *shadow_location = get_shadow_assembly_location_base (data, error);
650 if (!mono_error_ok (error)) {
651 g_free (data->friendly_name);
655 g_free (shadow_location);
658 create_domain_objects (data);
660 MONO_HANDLE_ASSIGN (result, ad);
662 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
666 * mono_domain_has_type_resolve:
667 * @domain: application domains being looked up
669 * Returns: TRUE if the AppDomain.TypeResolve field has been
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 * @domain: application domainwhere the name where the type is going to be resolved
694 * @name: the name of the type to resolve or NULL.
695 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
697 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
698 * the assembly that matches name.
700 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
702 * Returns: A 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:
747 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
750 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
754 mono_domain_lock (domain);
755 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
756 mono_domain_unlock (domain);
763 * @force: force setting.
765 * Set the current appdomain to @domain. If @force is set, set it even
766 * if it is being unloaded.
770 * FALSE if the domain is unloaded
773 mono_domain_set (MonoDomain *domain, gboolean force)
775 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
778 mono_domain_set_internal (domain);
784 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
788 if (MONO_HANDLE_IS_NULL (name)) {
789 mono_error_set_argument_null (error, "name", "");
793 g_assert (!MONO_HANDLE_IS_NULL (ad));
794 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
797 char *str = mono_string_handle_to_utf8 (name, error);
798 return_val_if_nok (error, NULL_HANDLE);
800 mono_domain_lock (add);
802 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
804 if (!strcmp (str, "APPBASE"))
805 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
806 else if (!strcmp (str, "APP_CONFIG_FILE"))
807 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
808 else if (!strcmp (str, "DYNAMIC_BASE"))
809 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
810 else if (!strcmp (str, "APP_NAME"))
811 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
812 else if (!strcmp (str, "CACHE_BASE"))
813 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
814 else if (!strcmp (str, "PRIVATE_BINPATH"))
815 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
816 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
817 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
818 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
819 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
820 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
821 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
823 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
825 mono_domain_unlock (add);
828 return MONO_HANDLE_CAST (MonoObject, o);
832 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
836 if (MONO_HANDLE_IS_NULL (name)) {
837 mono_error_set_argument_null (error, "name", "");
841 g_assert (!MONO_HANDLE_IS_NULL (ad));
842 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
845 mono_domain_lock (add);
847 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
849 mono_domain_unlock (add);
852 MonoAppDomainSetupHandle
853 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
856 g_assert (!MONO_HANDLE_IS_NULL (ad));
857 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
860 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
864 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
867 g_assert (!MONO_HANDLE_IS_NULL (ad));
868 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
871 return mono_string_new_handle (domain, domain->friendly_name, error);
875 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
878 MonoDomain *add = mono_domain_get ();
880 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
884 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
887 MonoDomain *root = mono_get_root_domain ();
889 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
893 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
895 MonoDomain *domain = mono_domain_get ();
897 return domain->throw_unobserved_task_exceptions;
901 get_attribute_value (const gchar **attribute_names,
902 const gchar **attribute_values,
903 const char *att_name)
906 for (n = 0; attribute_names [n] != NULL; n++) {
907 if (strcmp (attribute_names [n], att_name) == 0)
908 return g_strdup (attribute_values [n]);
914 start_element (GMarkupParseContext *context,
915 const gchar *element_name,
916 const gchar **attribute_names,
917 const gchar **attribute_values,
921 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
923 if (strcmp (element_name, "runtime") == 0) {
924 runtime_config->runtime_count++;
928 if (strcmp (element_name, "assemblyBinding") == 0) {
929 runtime_config->assemblybinding_count++;
933 if (runtime_config->runtime_count != 1)
936 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
937 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
939 if (value && g_ascii_strcasecmp (value, "true") == 0)
940 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
943 if (runtime_config->assemblybinding_count != 1)
946 if (strcmp (element_name, "probing") != 0)
949 g_free (runtime_config->domain->private_bin_path);
950 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
951 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
952 g_free (runtime_config->domain->private_bin_path);
953 runtime_config->domain->private_bin_path = NULL;
959 end_element (GMarkupParseContext *context,
960 const gchar *element_name,
964 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
965 if (strcmp (element_name, "runtime") == 0)
966 runtime_config->runtime_count--;
967 else if (strcmp (element_name, "assemblyBinding") == 0)
968 runtime_config->assemblybinding_count--;
972 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
974 RuntimeConfig *state = (RuntimeConfig *)user_data;
976 const gchar *filename;
978 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
979 msg = error && error->message ? error->message : "";
980 g_warning ("Error parsing %s: %s", filename, msg);
983 static const GMarkupParser
993 mono_domain_set_options_from_config (MonoDomain *domain)
996 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
998 GMarkupParseContext *context;
999 RuntimeConfig runtime_config;
1002 if (!domain || !domain->setup || !domain->setup->configuration_file)
1005 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1006 if (!mono_error_ok (&error)) {
1007 mono_error_cleanup (&error);
1011 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1012 if (!config_file_path)
1013 config_file_path = config_file_name;
1015 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1018 runtime_config.runtime_count = 0;
1019 runtime_config.assemblybinding_count = 0;
1020 runtime_config.domain = domain;
1021 runtime_config.filename = config_file_path;
1024 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1025 offset = 3; /* Skip UTF-8 BOM */
1027 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1028 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1029 g_markup_parse_context_end_parse (context, NULL);
1030 g_markup_parse_context_free (context);
1034 if (config_file_name != config_file_path)
1035 g_free (config_file_name);
1036 g_free (config_file_path);
1040 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1043 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1045 #ifdef DISABLE_APPDOMAINS
1046 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1050 fname = mono_string_handle_to_utf8 (friendly_name, error);
1051 return_val_if_nok (error, ad);
1052 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1059 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1061 HANDLE_FUNCTION_ENTER ();
1063 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1066 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1068 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1072 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1075 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1079 GPtrArray *assemblies;
1082 * Make a copy of the list of assemblies because we can't hold the assemblies
1083 * lock while creating objects etc.
1085 assemblies = g_ptr_array_new ();
1086 /* Need to skip internal assembly builders created by remoting */
1087 mono_domain_assemblies_lock (domain);
1088 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1089 ass = (MonoAssembly *)tmp->data;
1090 if (refonly != ass->ref_only)
1092 if (ass->corlib_internal)
1094 g_ptr_array_add (assemblies, ass);
1096 mono_domain_assemblies_unlock (domain);
1098 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1101 for (i = 0; i < assemblies->len; ++i) {
1102 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1107 g_ptr_array_free (assemblies, TRUE);
1112 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1114 HANDLE_FUNCTION_ENTER ();
1116 MonoAssembly *result = NULL;
1117 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1120 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1122 HANDLE_FUNCTION_RETURN_VAL (result);
1126 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1128 MonoAssembly *ret = NULL;
1130 MonoBoolean isrefonly;
1131 gpointer params [3];
1135 if (mono_runtime_get_no_exec ())
1138 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1140 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1141 g_assert (method != NULL);
1143 isrefonly = refonly ? 1 : 0;
1144 MonoReflectionAssemblyHandle requesting_handle;
1146 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1147 return_val_if_nok (error, ret);
1149 params [0] = MONO_HANDLE_RAW (fname);
1150 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1151 params [2] = &isrefonly;
1152 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1153 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1158 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1162 MonoAssembly *assembly;
1163 MonoDomain *domain = mono_domain_get ();
1166 aname_str = mono_stringify_assembly_name (aname);
1168 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1170 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1172 mono_error_cleanup (&error);
1178 * LOCKING: assumes assemblies_lock in the domain is already locked.
1181 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1185 gboolean destroy_ht = FALSE;
1187 if (!ass->aname.name)
1191 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1195 /* FIXME: handle lazy loaded assemblies */
1196 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1197 g_hash_table_insert (ht, tmp->data, tmp->data);
1199 if (!g_hash_table_lookup (ht, ass)) {
1200 mono_assembly_addref (ass);
1201 g_hash_table_insert (ht, ass, ass);
1202 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1203 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);
1206 if (ass->image->references) {
1207 for (i = 0; ass->image->references [i] != NULL; i++) {
1208 if (ass->image->references [i] != REFERENCE_MISSING)
1209 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1210 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1215 g_hash_table_destroy (ht);
1219 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1221 static MonoClassField *assembly_load_field;
1222 static MonoMethod *assembly_load_method;
1224 MonoDomain *domain = mono_domain_get ();
1226 gpointer load_value;
1229 if (!domain->domain)
1230 /* This can happen during startup */
1232 #ifdef ASSEMBLY_LOAD_DEBUG
1233 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1235 klass = domain->domain->mbr.obj.vtable->klass;
1237 mono_domain_assemblies_lock (domain);
1238 add_assemblies_to_domain (domain, assembly, NULL);
1239 mono_domain_assemblies_unlock (domain);
1241 if (assembly_load_field == NULL) {
1242 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1243 g_assert (assembly_load_field);
1246 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1247 if (load_value == NULL) {
1248 /* No events waiting to be triggered */
1252 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1253 mono_error_assert_ok (&error);
1255 if (assembly_load_method == NULL) {
1256 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1257 g_assert (assembly_load_method);
1260 *params = MONO_HANDLE_RAW(ref_assembly);
1262 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1263 mono_error_cleanup (&error);
1267 * LOCKING: Acquires the domain assemblies lock.
1270 set_domain_search_path (MonoDomain *domain)
1273 MonoAppDomainSetup *setup;
1275 gchar *search_path = NULL;
1278 gchar **pvt_split = NULL;
1279 GError *gerror = NULL;
1280 gint appbaselen = -1;
1283 * We use the low-level domain assemblies lock, since this is called from
1284 * assembly loads hooks, which means this thread might hold the loader lock.
1286 mono_domain_assemblies_lock (domain);
1288 if (!domain->setup) {
1289 mono_domain_assemblies_unlock (domain);
1293 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1294 mono_domain_assemblies_unlock (domain);
1297 setup = domain->setup;
1298 if (!setup->application_base) {
1299 mono_domain_assemblies_unlock (domain);
1300 return; /* Must set application base to get private path working */
1305 if (setup->private_bin_path) {
1306 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1307 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1308 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1309 mono_error_cleanup (&error);
1310 mono_domain_assemblies_unlock (domain);
1315 if (domain->private_bin_path) {
1316 if (search_path == NULL)
1317 search_path = domain->private_bin_path;
1319 gchar *tmp2 = search_path;
1320 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1327 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1328 * directories relative to ApplicationBase separated by semicolons (see
1329 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1330 * The loop below copes with the fact that some Unix applications may use ':' (or
1331 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1332 * ';' for the subsequent split.
1334 * The issue was reported in bug #81446
1337 #ifndef TARGET_WIN32
1340 slen = strlen (search_path);
1341 for (i = 0; i < slen; i++)
1342 if (search_path [i] == ':')
1343 search_path [i] = ';';
1346 pvt_split = g_strsplit (search_path, ";", 1000);
1347 g_free (search_path);
1348 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1353 g_strfreev (pvt_split);
1355 * Don't do this because the first time is called, the domain
1356 * setup is not finished.
1358 * domain->search_path = g_malloc (sizeof (char *));
1359 * domain->search_path [0] = NULL;
1361 mono_domain_assemblies_unlock (domain);
1365 if (domain->search_path)
1366 g_strfreev (domain->search_path);
1368 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1369 tmp [npaths] = NULL;
1371 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1372 if (!mono_error_ok (&error)) {
1373 mono_error_cleanup (&error);
1374 g_strfreev (pvt_split);
1377 mono_domain_assemblies_unlock (domain);
1381 domain->search_path = tmp;
1383 /* FIXME: is this needed? */
1384 if (strncmp (*tmp, "file://", 7) == 0) {
1390 uri = g_strdup_printf ("file:///%s", uri + 7);
1393 uri = mono_escape_uri_string (tmpuri);
1394 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1400 if (gerror != NULL) {
1401 g_warning ("%s\n", gerror->message);
1402 g_error_free (gerror);
1409 for (i = 1; pvt_split && i < npaths; i++) {
1410 if (g_path_is_absolute (pvt_split [i - 1])) {
1411 tmp [i] = g_strdup (pvt_split [i - 1]);
1413 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1416 if (strchr (tmp [i], '.')) {
1420 reduced = mono_path_canonicalize (tmp [i]);
1421 if (appbaselen == -1)
1422 appbaselen = strlen (tmp [0]);
1424 if (strncmp (tmp [0], reduced, appbaselen)) {
1427 tmp [i] = g_strdup ("");
1437 if (setup->private_bin_path_probe != NULL) {
1439 tmp [0] = g_strdup ("");
1442 domain->setup->path_changed = FALSE;
1444 g_strfreev (pvt_split);
1446 mono_domain_assemblies_unlock (domain);
1449 #ifdef DISABLE_SHADOW_COPY
1451 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1457 mono_make_shadow_copy (const char *filename, MonoError *error)
1460 return (char *) filename;
1464 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1466 guint16 *orig, *dest;
1467 gboolean copy_result;
1470 strcpy (src + srclen - tail_len, extension);
1472 if (IS_PORTABILITY_CASE) {
1473 gchar *file = mono_portability_find_file (src, TRUE);
1479 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1483 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1485 strcpy (target + targetlen - tail_len, extension);
1486 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1488 mono_w32file_delete (dest);
1490 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1492 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1493 * overwritten when updated in their original locations. */
1495 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1504 get_cstring_hash (const char *str)
1510 if (!str || !str [0])
1515 for (i = 0; i < len; i++) {
1516 h = (h << 5) - h + *p;
1524 * Returned memory is malloc'd. Called must free it
1527 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1529 MonoAppDomainSetup *setup;
1530 char *cache_path, *appname;
1536 setup = domain->setup;
1537 if (setup->cache_path != NULL && setup->application_name != NULL) {
1538 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1539 return_val_if_nok (error, NULL);
1541 #ifndef TARGET_WIN32
1544 for (i = strlen (cache_path) - 1; i >= 0; i--)
1545 if (cache_path [i] == '\\')
1546 cache_path [i] = '/';
1550 appname = mono_string_to_utf8_checked (setup->application_name, error);
1551 if (!mono_error_ok (error)) {
1552 g_free (cache_path);
1556 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1558 g_free (cache_path);
1560 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1561 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1568 get_shadow_assembly_location (const char *filename, MonoError *error)
1570 gint32 hash = 0, hash2 = 0;
1572 char path_hash [30];
1573 char *bname = g_path_get_basename (filename);
1574 char *dirname = g_path_get_dirname (filename);
1575 char *location, *tmploc;
1576 MonoDomain *domain = mono_domain_get ();
1580 hash = get_cstring_hash (bname);
1581 hash2 = get_cstring_hash (dirname);
1582 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1583 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1584 tmploc = get_shadow_assembly_location_base (domain, error);
1585 if (!mono_error_ok (error)) {
1591 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1599 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1601 struct stat sbuf_dest;
1603 gchar *real_src = mono_portability_find_file (src, TRUE);
1606 stat_src = (gchar*)src;
1608 stat_src = real_src;
1610 if (stat (stat_src, sbuf_src) == -1) {
1611 time_t tnow = time (NULL);
1616 memset (sbuf_src, 0, sizeof (*sbuf_src));
1617 sbuf_src->st_mtime = tnow;
1618 sbuf_src->st_atime = tnow;
1625 if (stat (dest, &sbuf_dest) == -1)
1628 if (sbuf_src->st_size == sbuf_dest.st_size &&
1629 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1636 shadow_copy_create_ini (const char *shadow, const char *filename)
1646 dir_name = g_path_get_dirname (shadow);
1647 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1649 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1654 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1659 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1661 if (handle == INVALID_HANDLE_VALUE) {
1665 full_path = mono_path_resolve_symlinks (filename);
1666 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1668 mono_w32file_close (handle);
1673 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1676 MonoAppDomainSetup *setup;
1679 gchar **directories;
1680 gchar *shadow_status_string;
1682 gboolean shadow_enabled;
1683 gboolean found = FALSE;
1688 setup = domain->setup;
1689 if (setup == NULL || setup->shadow_copy_files == NULL)
1692 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1693 if (!mono_error_ok (&error)) {
1694 mono_error_cleanup (&error);
1697 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1698 g_free (shadow_status_string);
1700 if (!shadow_enabled)
1703 if (setup->shadow_copy_directories == NULL)
1706 /* Is dir_name a shadow_copy destination already? */
1707 base_dir = get_shadow_assembly_location_base (domain, &error);
1708 if (!mono_error_ok (&error)) {
1709 mono_error_cleanup (&error);
1713 if (strstr (dir_name, base_dir)) {
1719 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1720 if (!mono_error_ok (&error)) {
1721 mono_error_cleanup (&error);
1725 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1726 dir_ptr = directories;
1728 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1734 g_strfreev (directories);
1740 This function raises exceptions so it can cause as sorts of nasty stuff if called
1741 while holding a lock.
1742 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1743 or NULL if source file not found.
1744 FIXME bubble up the error instead of raising it here
1747 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1750 gchar *sibling_source, *sibling_target;
1751 gint sibling_source_len, sibling_target_len;
1752 guint16 *orig, *dest;
1755 gboolean copy_result;
1756 struct stat src_sbuf;
1757 struct utimbuf utbuf;
1758 char *dir_name = g_path_get_dirname (filename);
1759 MonoDomain *domain = mono_domain_get ();
1763 error_init (oerror);
1765 set_domain_search_path (domain);
1767 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1769 return (char *) filename;
1772 /* Is dir_name a shadow_copy destination already? */
1773 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1774 if (!mono_error_ok (&error)) {
1775 mono_error_cleanup (&error);
1777 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1781 if (strstr (dir_name, shadow_dir)) {
1782 g_free (shadow_dir);
1784 return (char *) filename;
1786 g_free (shadow_dir);
1789 shadow = get_shadow_assembly_location (filename, &error);
1790 if (!mono_error_ok (&error)) {
1791 mono_error_cleanup (&error);
1792 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1796 if (g_ensure_directory_exists (shadow) == FALSE) {
1798 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1802 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1803 return (char*) shadow;
1805 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1806 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1807 mono_w32file_delete (dest);
1809 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1810 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1811 * and not have it runtime error" */
1812 attrs = mono_w32file_get_attributes (orig);
1813 if (attrs == INVALID_FILE_ATTRIBUTES) {
1815 return (char *)filename;
1818 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1820 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1821 * overwritten when updated in their original locations. */
1823 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1828 if (copy_result == FALSE) {
1831 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1832 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1833 return NULL; /* file not found, shadow copy failed */
1835 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1839 /* attempt to copy .mdb, .config if they exist */
1840 sibling_source = g_strconcat (filename, ".config", NULL);
1841 sibling_source_len = strlen (sibling_source);
1842 sibling_target = g_strconcat (shadow, ".config", NULL);
1843 sibling_target_len = strlen (sibling_target);
1845 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1847 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1849 g_free (sibling_source);
1850 g_free (sibling_target);
1854 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1858 /* Create a .ini file containing the original assembly location */
1859 if (!shadow_copy_create_ini (shadow, filename)) {
1861 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1865 utbuf.actime = src_sbuf.st_atime;
1866 utbuf.modtime = src_sbuf.st_mtime;
1867 utime (shadow, &utbuf);
1871 #endif /* DISABLE_SHADOW_COPY */
1874 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1876 HANDLE_FUNCTION_ENTER ();
1877 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1878 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1879 HANDLE_FUNCTION_RETURN_VAL (result);
1883 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1885 HANDLE_FUNCTION_ENTER ();
1886 MonoDomain *dom = NULL;
1887 if (MONO_HANDLE_IS_NULL (appdomain))
1890 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1891 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1892 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1894 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1896 dom = MONO_HANDLE_GETVAL (appdomain, data);
1899 HANDLE_FUNCTION_RETURN_VAL (dom);
1904 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1905 const gchar *path3, const gchar *path4,
1906 gboolean refonly, gboolean is_private)
1909 gboolean found = FALSE;
1912 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1914 if (IS_PORTABILITY_SET) {
1915 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1918 fullpath = new_fullpath;
1922 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1925 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1928 return (*assembly != NULL);
1931 static MonoAssembly *
1932 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1934 MonoAssembly *result = NULL;
1937 const gchar *local_culture;
1939 gboolean is_private = FALSE;
1941 if (!culture || *culture == '\0') {
1944 local_culture = culture;
1947 filename = g_strconcat (name, ".dll", NULL);
1948 len = strlen (filename);
1950 for (path = search_path; *path; path++) {
1951 if (**path == '\0') {
1953 continue; /* Ignore empty ApplicationBase */
1956 /* See test cases in bug #58992 and bug #57710 */
1957 /* 1st try: [culture]/[name].dll (culture may be empty) */
1958 strcpy (filename + len - 4, ".dll");
1959 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1962 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1963 strcpy (filename + len - 4, ".exe");
1964 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1967 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1968 strcpy (filename + len - 4, ".dll");
1969 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1972 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1973 strcpy (filename + len - 4, ".exe");
1974 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1983 * Try loading the assembly from ApplicationBase and PrivateBinPath
1984 * and then from assemblies_path if any.
1985 * LOCKING: This is called from the assembly loading code, which means the caller
1986 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1988 static MonoAssembly *
1989 mono_domain_assembly_preload (MonoAssemblyName *aname,
1990 gchar **assemblies_path,
1993 MonoDomain *domain = mono_domain_get ();
1994 MonoAssembly *result = NULL;
1995 gboolean refonly = GPOINTER_TO_UINT (user_data);
1997 set_domain_search_path (domain);
1999 if (domain->search_path && domain->search_path [0] != NULL) {
2000 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
2003 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2004 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
2011 * Check whenever a given assembly was already loaded in the current appdomain.
2013 static MonoAssembly *
2014 mono_domain_assembly_search (MonoAssemblyName *aname,
2017 MonoDomain *domain = mono_domain_get ();
2020 gboolean refonly = GPOINTER_TO_UINT (user_data);
2022 mono_domain_assemblies_lock (domain);
2023 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2024 ass = (MonoAssembly *)tmp->data;
2025 /* Dynamic assemblies can't match here in MS.NET */
2026 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2029 mono_domain_assemblies_unlock (domain);
2032 mono_domain_assemblies_unlock (domain);
2037 MonoReflectionAssemblyHandle
2038 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2041 MonoDomain *domain = mono_domain_get ();
2042 char *name, *filename;
2043 MonoImageOpenStatus status = MONO_IMAGE_OK;
2044 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2049 if (fname == NULL) {
2050 mono_error_set_argument_null (error, "assemblyFile", "");
2054 name = filename = mono_string_handle_to_utf8 (fname, error);
2058 MonoAssembly *ass = mono_assembly_open_a_lot (filename, &status, refOnly, TRUE);
2061 if (status == MONO_IMAGE_IMAGE_INVALID)
2062 mono_error_set_bad_image_name (error, g_strdup (name), "");
2064 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2068 result = mono_assembly_get_object_handle (domain, ass, error);
2075 MonoReflectionAssemblyHandle
2076 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2077 MonoArrayHandle raw_assembly,
2078 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2079 MonoBoolean refonly,
2084 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2085 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2086 MonoImageOpenStatus status;
2087 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2089 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2090 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2091 if (!assembly_data) {
2092 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2096 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2097 memcpy (assembly_data, raw_data, raw_assembly_len);
2098 mono_gchandle_free (gchandle); /* unpin */
2099 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2101 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2104 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2108 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2109 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2110 uint32_t symbol_gchandle;
2111 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2112 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2113 mono_gchandle_free (symbol_gchandle);
2116 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2120 mono_image_close (image);
2121 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2125 refass = mono_assembly_get_object_handle (domain, ass, error);
2126 if (!MONO_HANDLE_IS_NULL(refass))
2127 MONO_HANDLE_SET (refass, evidence, evidence);
2131 MonoReflectionAssemblyHandle
2132 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2135 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2136 MonoImageOpenStatus status = MONO_IMAGE_OK;
2138 MonoAssemblyName aname;
2144 name = mono_string_handle_to_utf8 (assRef, error);
2147 parsed = mono_assembly_name_parse (name, &aname);
2151 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2152 /* This is a parse error... */
2154 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2158 refass = mono_assembly_get_object_handle (domain, assm, error);
2166 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2167 mono_assembly_name_free (&aname);
2170 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2172 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2181 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2185 MONO_HANDLE_SET (refass, evidence, evidence);
2189 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2193 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2196 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2198 if (NULL == domain) {
2199 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2203 if (domain == mono_get_root_domain ()) {
2204 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2209 * Unloading seems to cause problems when running NUnit/NAnt, hence
2212 if (g_getenv ("MONO_NO_UNLOAD"))
2214 #ifdef __native_client__
2218 MonoException *exc = NULL;
2219 mono_domain_try_unload (domain, (MonoObject**)&exc);
2221 mono_error_set_exception_instance (error, exc);
2225 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2228 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2233 return mono_domain_is_unloading (domain);
2237 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2239 mono_unhandled_exception ((MonoObject*) exc);
2243 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2244 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2251 g_assert (!MONO_HANDLE_IS_NULL (refass));
2252 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2253 image = assembly->image;
2256 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2259 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2261 if (MONO_HANDLE_IS_NULL (args)) {
2262 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2263 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2264 mono_error_assert_ok (error);
2267 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2272 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2274 return ad->data->domain_id;
2278 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2281 MonoDomain *old_domain = mono_domain_get ();
2283 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2284 mono_error_set_appdomain_unloaded (error);
2285 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2288 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2292 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2294 MonoDomain *current_domain = mono_domain_get ();
2295 MonoDomain *domain = mono_domain_get_by_id (domainid);
2297 if (!domain || !mono_domain_set (domain, FALSE)) {
2298 mono_error_set_appdomain_unloaded (error);
2299 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2302 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2306 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2309 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2313 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2316 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2320 * Raise an exception to prevent the managed code from executing a pop
2323 mono_error_set_appdomain_unloaded (error);
2327 mono_thread_push_appdomain_ref (domain);
2331 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2334 mono_thread_pop_appdomain_ref ();
2338 ves_icall_System_AppDomain_InternalGetContext ()
2340 return mono_context_get ();
2344 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2346 return mono_domain_get ()->default_context;
2350 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2352 MonoAppContext *old_context = mono_context_get ();
2354 mono_context_set (mc);
2360 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2363 MonoDomain* mono_root_domain = mono_get_root_domain ();
2364 mono_domain_lock (mono_root_domain);
2365 if (process_guid_set) {
2366 mono_domain_unlock (mono_root_domain);
2367 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2369 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2370 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2371 mono_gchandle_free (gchandle);
2372 process_guid_set = TRUE;
2373 mono_domain_unlock (mono_root_domain);
2378 mono_domain_is_unloading (MonoDomain *domain)
2380 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2387 clear_cached_vtable (MonoVTable *vtable)
2389 MonoClass *klass = vtable->klass;
2390 MonoDomain *domain = vtable->domain;
2391 MonoClassRuntimeInfo *runtime_info;
2394 runtime_info = klass->runtime_info;
2395 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2396 runtime_info->domain_vtables [domain->domain_id] = NULL;
2397 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2398 mono_gc_free_fixed (data);
2401 static G_GNUC_UNUSED void
2402 zero_static_data (MonoVTable *vtable)
2404 MonoClass *klass = vtable->klass;
2407 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2408 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2411 typedef struct unload_data {
2414 char *failure_reason;
2419 unload_data_unref (unload_data *data)
2423 mono_atomic_load_acquire (count, gint32, &data->refcount);
2424 g_assert (count >= 1 && count <= 2);
2429 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2433 deregister_reflection_info_roots_from_list (MonoImage *image)
2435 GSList *list = image->reflection_info_unregister_classes;
2438 MonoClass *klass = (MonoClass *)list->data;
2440 mono_class_free_ref_info (klass);
2445 image->reflection_info_unregister_classes = NULL;
2449 deregister_reflection_info_roots (MonoDomain *domain)
2453 mono_domain_assemblies_lock (domain);
2454 for (list = domain->domain_assemblies; list; list = list->next) {
2455 MonoAssembly *assembly = (MonoAssembly *)list->data;
2456 MonoImage *image = assembly->image;
2460 * No need to take the image lock here since dynamic images are appdomain bound and
2461 * at this point the mutator is gone. Taking the image lock here would mean
2462 * promoting it from a simple lock to a complex lock, which we better avoid if
2465 if (image_is_dynamic (image))
2466 deregister_reflection_info_roots_from_list (image);
2468 for (i = 0; i < image->module_count; ++i) {
2469 MonoImage *module = image->modules [i];
2470 if (module && image_is_dynamic (module))
2471 deregister_reflection_info_roots_from_list (module);
2474 mono_domain_assemblies_unlock (domain);
2478 unload_thread_main (void *arg)
2481 unload_data *data = (unload_data*)arg;
2482 MonoDomain *domain = data->domain;
2486 /* Have to attach to the runtime so shutdown can wait for this thread */
2487 /* Force it to be attached to avoid racing during shutdown. */
2488 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2490 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "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 mono_threads_clear_cached_culture (domain);
2549 domain->state = MONO_APPDOMAIN_UNLOADED;
2551 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2553 /* remove from the handle table the items related to this domain */
2554 mono_gchandle_free_domain (domain);
2556 mono_domain_free (domain, FALSE);
2558 mono_gc_collect (mono_gc_max_generation ());
2560 mono_atomic_store_release (&data->done, TRUE);
2561 unload_data_unref (data);
2562 mono_thread_detach (thread);
2566 mono_atomic_store_release (&data->done, TRUE);
2567 unload_data_unref (data);
2568 mono_thread_detach (thread);
2573 * mono_domain_unload:
2574 * @domain: The domain to unload
2576 * Unloads an appdomain. Follows the process outlined in the comment
2577 * for mono_domain_try_unload.
2580 mono_domain_unload (MonoDomain *domain)
2582 MonoObject *exc = NULL;
2583 mono_domain_try_unload (domain, &exc);
2586 static MonoThreadInfoWaitRet
2587 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2589 MonoThreadInfoWaitRet result;
2592 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2599 * mono_domain_unload:
2600 * @domain: The domain to unload
2601 * @exc: Exception information
2603 * Unloads an appdomain. Follows the process outlined in:
2604 * http://blogs.gotdotnet.com/cbrumme
2606 * If doing things the 'right' way is too hard or complex, we do it the
2607 * 'simple' way, which means do everything needed to avoid crashes and
2608 * memory leaks, but not much else.
2610 * It is required to pass a valid reference to the exc argument, upon return
2611 * from this function *exc will be set to the exception thrown, if any.
2613 * If this method is not called from an icall (embedded scenario for instance),
2614 * it must not be called with any managed frames on the stack, since the unload
2615 * process could end up trying to abort the current thread.
2618 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2621 MonoThreadHandle *thread_handle;
2622 MonoAppDomainState prev_state;
2624 unload_data *thread_data;
2625 MonoNativeThreadId tid;
2626 MonoDomain *caller_domain = mono_domain_get ();
2628 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2630 /* Atomically change our state to UNLOADING */
2631 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2632 MONO_APPDOMAIN_UNLOADING_START,
2633 MONO_APPDOMAIN_CREATED);
2634 if (prev_state != MONO_APPDOMAIN_CREATED) {
2635 switch (prev_state) {
2636 case MONO_APPDOMAIN_UNLOADING_START:
2637 case MONO_APPDOMAIN_UNLOADING:
2638 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2640 case MONO_APPDOMAIN_UNLOADED:
2641 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2644 g_warning ("Invalid appdomain state %d", prev_state);
2645 g_assert_not_reached ();
2649 mono_domain_set (domain, FALSE);
2650 /* Notify OnDomainUnload listeners */
2651 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2654 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2656 if (!mono_error_ok (&error)) {
2658 mono_error_cleanup (&error);
2660 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2664 /* Roll back the state change */
2665 domain->state = MONO_APPDOMAIN_CREATED;
2666 mono_domain_set (caller_domain, FALSE);
2669 mono_domain_set (caller_domain, FALSE);
2671 thread_data = g_new0 (unload_data, 1);
2672 thread_data->domain = domain;
2673 thread_data->failure_reason = NULL;
2674 thread_data->done = FALSE;
2675 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2677 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2678 domain->state = MONO_APPDOMAIN_UNLOADING;
2680 * First we create a separate thread for unloading, since
2681 * we might have to abort some threads, including the current one.
2683 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2684 if (thread_handle == NULL)
2687 /* Wait for the thread */
2688 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2689 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2690 /* The unload thread tries to abort us */
2691 /* The icall wrapper will execute the abort */
2692 mono_threads_close_thread_handle (thread_handle);
2693 unload_data_unref (thread_data);
2698 mono_threads_close_thread_handle (thread_handle);
2700 if (thread_data->failure_reason) {
2701 /* Roll back the state change */
2702 domain->state = MONO_APPDOMAIN_CREATED;
2704 g_warning ("%s", thread_data->failure_reason);
2706 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2708 g_free (thread_data->failure_reason);
2709 thread_data->failure_reason = NULL;
2712 unload_data_unref (thread_data);