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/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 * @domain: domain returned by 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 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
240 * we know the 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
342 * Checks that the corlib that is loaded matches the version of this runtime.
344 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
345 * allocated string with the error otherwise.
348 mono_check_corlib_version (void)
350 int version = mono_get_corlib_version ();
351 if (version != MONO_CORLIB_VERSION)
352 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
354 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
355 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
356 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
357 if (native_offset != managed_offset)
358 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
365 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
367 * Initializes the @domain's default System.Runtime.Remoting's Context.
370 mono_context_init (MonoDomain *domain)
373 mono_context_init_checked (domain, &error);
374 mono_error_cleanup (&error);
378 mono_context_init_checked (MonoDomain *domain, MonoError *error)
381 MonoAppContext *context;
385 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
386 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
387 return_if_nok (error);
389 context->domain_id = domain->domain_id;
390 context->context_id = 0;
391 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
392 domain->default_context = context;
396 * mono_runtime_cleanup:
401 * This must not be called while there are still running threads executing
405 mono_runtime_cleanup (MonoDomain *domain)
407 mono_attach_cleanup ();
409 /* This ends up calling any pending pending (for at most 2 seconds) */
412 mono_thread_cleanup ();
414 #ifndef DISABLE_SOCKETS
415 mono_network_cleanup ();
417 mono_marshal_cleanup ();
419 mono_type_initialization_cleanup ();
421 mono_monitor_cleanup ();
424 static MonoDomainFunc quit_function = NULL;
427 mono_install_runtime_cleanup (MonoDomainFunc func)
429 quit_function = func;
435 if (quit_function != NULL)
436 quit_function (mono_get_root_domain (), NULL);
440 * mono_domain_create_appdomain:
441 * @friendly_name: The friendly name of the appdomain to create
442 * @configuration_file: The configuration file to initialize the appdomain with
444 * Returns a MonoDomain initialized with the appdomain
447 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
449 HANDLE_FUNCTION_ENTER ();
451 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
452 mono_error_cleanup (&error);
453 HANDLE_FUNCTION_RETURN_VAL (domain);
457 * mono_domain_create_appdomain_checked:
458 * @friendly_name: The friendly name of the appdomain to create
459 * @configuration_file: The configuration file to initialize the appdomain with
460 * @error: Set on error.
462 * Returns a MonoDomain initialized with the appdomain. On failure sets @error and returns NULL.
465 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
467 HANDLE_FUNCTION_ENTER ();
469 MonoDomain *result = NULL;
471 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
472 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
475 MonoStringHandle config_file;
476 if (configuration_file != NULL) {
477 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
481 config_file = MONO_HANDLE_NEW (MonoString, NULL);
483 MONO_HANDLE_SET (setup, configuration_file, config_file);
485 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
489 result = mono_domain_from_appdomain_handle (ad);
491 HANDLE_FUNCTION_RETURN_VAL (result);
495 * mono_domain_set_config:
496 * @domain: MonoDomain initialized with the appdomain we want to change
497 * @base_dir: new base directory for the appdomain
498 * @config_file_name: path to the new configuration for the app domain
500 * Used to set the system configuration for an appdomain
502 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
503 * Error Initializing the configuration system. ---> System.ArgumentException:
504 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
507 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
509 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
510 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
513 static MonoAppDomainSetupHandle
514 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
516 HANDLE_FUNCTION_ENTER ();
517 MonoDomain *caller_domain;
518 MonoClass *ads_class;
519 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
523 caller_domain = mono_domain_get ();
524 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
526 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
530 mono_domain_set_internal (domain);
532 #define XCOPY_FIELD(dst,field,src,error) \
534 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
535 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
536 if (!is_ok (error)) \
538 MONO_HANDLE_SET ((dst),field,copied_val); \
541 #define COPY_VAL(dst,field,type,src) \
543 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
546 XCOPY_FIELD (copy, application_base, setup, error);
547 XCOPY_FIELD (copy, application_name, setup, error);
548 XCOPY_FIELD (copy, cache_path, setup, error);
549 XCOPY_FIELD (copy, configuration_file, setup, error);
550 XCOPY_FIELD (copy, dynamic_base, setup, error);
551 XCOPY_FIELD (copy, license_file, setup, error);
552 XCOPY_FIELD (copy, private_bin_path, setup, error);
553 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
554 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
555 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
556 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
557 COPY_VAL (copy, path_changed, MonoBoolean, setup);
558 COPY_VAL (copy, loader_optimization, int, setup);
559 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
560 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
561 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
562 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
563 XCOPY_FIELD (copy, application_trust, setup, error);
564 XCOPY_FIELD (copy, configuration_bytes, setup, error);
565 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
570 mono_domain_set_internal (caller_domain);
572 MONO_HANDLE_ASSIGN (result, copy);
574 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
577 static MonoAppDomainHandle
578 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
580 HANDLE_FUNCTION_ENTER ();
581 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
587 adclass = mono_class_get_appdomain_class ();
589 /* FIXME: pin all those objects */
590 data = mono_domain_create();
592 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
595 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
596 data->domain = MONO_HANDLE_RAW (ad);
597 data->friendly_name = g_strdup (friendly_name);
599 mono_profiler_appdomain_name (data, data->friendly_name);
601 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
602 if (MONO_HANDLE_IS_NULL (app_base)) {
603 /* Inherit from the root domain since MS.NET does this */
604 MonoDomain *root = mono_get_root_domain ();
605 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
606 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
607 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
608 /* N.B. new string is in the new domain */
609 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
610 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);
611 mono_gchandle_free (gchandle);
612 if (!is_ok (error)) {
613 g_free (data->friendly_name);
616 MONO_HANDLE_SET (setup, application_base, s);
620 mono_context_init_checked (data, error);
624 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
625 if (!mono_error_ok (error)) {
626 g_free (data->friendly_name);
630 mono_domain_set_options_from_config (data);
631 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
633 #ifndef DISABLE_SHADOW_COPY
634 /*FIXME, guard this for when the debugger is not running */
635 char *shadow_location = get_shadow_assembly_location_base (data, error);
636 if (!mono_error_ok (error)) {
637 g_free (data->friendly_name);
641 g_free (shadow_location);
644 create_domain_objects (data);
646 MONO_HANDLE_ASSIGN (result, ad);
648 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
652 * mono_domain_has_type_resolve:
653 * @domain: application domains being looked up
655 * Returns: TRUE if the AppDomain.TypeResolve field has been
659 mono_domain_has_type_resolve (MonoDomain *domain)
661 static MonoClassField *field = NULL;
665 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
669 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
673 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
678 * mono_domain_try_type_resolve:
679 * @domain: application domainwhere the name where the type is going to be resolved
680 * @name: the name of the type to resolve or NULL.
681 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
683 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
684 * the assembly that matches name.
686 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
688 * Returns: A MonoReflectionAssembly or NULL if not found
690 MonoReflectionAssembly *
691 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
694 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
695 mono_error_cleanup (&error);
700 MonoReflectionAssembly *
701 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
703 static MonoMethod *method = NULL;
704 MonoReflectionAssembly *ret;
709 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
711 if (method == NULL) {
712 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
713 if (method == NULL) {
714 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
720 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
724 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
725 return_val_if_nok (error, NULL);
731 * mono_domain_owns_vtable_slot:
733 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to 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);
749 * @force: force setting.
751 * Set the current appdomain to @domain. If @force is set, set it even
752 * if it is being unloaded.
756 * FALSE if the domain is unloaded
759 mono_domain_set (MonoDomain *domain, gboolean force)
761 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
764 mono_domain_set_internal (domain);
770 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
774 if (MONO_HANDLE_IS_NULL (name)) {
775 mono_error_set_argument_null (error, "name", "");
779 g_assert (!MONO_HANDLE_IS_NULL (ad));
780 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
783 char *str = mono_string_handle_to_utf8 (name, error);
784 return_val_if_nok (error, NULL_HANDLE);
786 mono_domain_lock (add);
788 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
790 if (!strcmp (str, "APPBASE"))
791 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
792 else if (!strcmp (str, "APP_CONFIG_FILE"))
793 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
794 else if (!strcmp (str, "DYNAMIC_BASE"))
795 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
796 else if (!strcmp (str, "APP_NAME"))
797 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
798 else if (!strcmp (str, "CACHE_BASE"))
799 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
800 else if (!strcmp (str, "PRIVATE_BINPATH"))
801 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
802 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
803 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
804 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
805 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
806 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
807 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
809 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
811 mono_domain_unlock (add);
814 return MONO_HANDLE_CAST (MonoObject, o);
818 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
822 if (MONO_HANDLE_IS_NULL (name)) {
823 mono_error_set_argument_null (error, "name", "");
827 g_assert (!MONO_HANDLE_IS_NULL (ad));
828 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
831 mono_domain_lock (add);
833 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
835 mono_domain_unlock (add);
838 MonoAppDomainSetupHandle
839 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
842 g_assert (!MONO_HANDLE_IS_NULL (ad));
843 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
846 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
850 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
853 g_assert (!MONO_HANDLE_IS_NULL (ad));
854 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
857 return mono_string_new_handle (domain, domain->friendly_name, error);
861 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
864 MonoDomain *add = mono_domain_get ();
866 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
870 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
873 MonoDomain *root = mono_get_root_domain ();
875 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
879 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
881 MonoDomain *domain = mono_domain_get ();
883 return domain->throw_unobserved_task_exceptions;
887 get_attribute_value (const gchar **attribute_names,
888 const gchar **attribute_values,
889 const char *att_name)
892 for (n = 0; attribute_names [n] != NULL; n++) {
893 if (strcmp (attribute_names [n], att_name) == 0)
894 return g_strdup (attribute_values [n]);
900 start_element (GMarkupParseContext *context,
901 const gchar *element_name,
902 const gchar **attribute_names,
903 const gchar **attribute_values,
907 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
909 if (strcmp (element_name, "runtime") == 0) {
910 runtime_config->runtime_count++;
914 if (strcmp (element_name, "assemblyBinding") == 0) {
915 runtime_config->assemblybinding_count++;
919 if (runtime_config->runtime_count != 1)
922 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
923 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
925 if (value && g_ascii_strcasecmp (value, "true") == 0)
926 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
929 if (runtime_config->assemblybinding_count != 1)
932 if (strcmp (element_name, "probing") != 0)
935 g_free (runtime_config->domain->private_bin_path);
936 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
937 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
938 g_free (runtime_config->domain->private_bin_path);
939 runtime_config->domain->private_bin_path = NULL;
945 end_element (GMarkupParseContext *context,
946 const gchar *element_name,
950 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
951 if (strcmp (element_name, "runtime") == 0)
952 runtime_config->runtime_count--;
953 else if (strcmp (element_name, "assemblyBinding") == 0)
954 runtime_config->assemblybinding_count--;
958 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
960 RuntimeConfig *state = (RuntimeConfig *)user_data;
962 const gchar *filename;
964 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
965 msg = error && error->message ? error->message : "";
966 g_warning ("Error parsing %s: %s", filename, msg);
969 static const GMarkupParser
979 mono_domain_set_options_from_config (MonoDomain *domain)
982 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
984 GMarkupParseContext *context;
985 RuntimeConfig runtime_config;
988 if (!domain || !domain->setup || !domain->setup->configuration_file)
991 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
992 if (!mono_error_ok (&error)) {
993 mono_error_cleanup (&error);
997 config_file_path = mono_portability_find_file (config_file_name, TRUE);
998 if (!config_file_path)
999 config_file_path = config_file_name;
1001 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1004 runtime_config.runtime_count = 0;
1005 runtime_config.assemblybinding_count = 0;
1006 runtime_config.domain = domain;
1007 runtime_config.filename = config_file_path;
1010 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1011 offset = 3; /* Skip UTF-8 BOM */
1013 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1014 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1015 g_markup_parse_context_end_parse (context, NULL);
1016 g_markup_parse_context_free (context);
1020 if (config_file_name != config_file_path)
1021 g_free (config_file_name);
1022 g_free (config_file_path);
1026 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1029 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1031 #ifdef DISABLE_APPDOMAINS
1032 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1036 fname = mono_string_handle_to_utf8 (friendly_name, error);
1037 return_val_if_nok (error, ad);
1038 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1045 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1047 HANDLE_FUNCTION_ENTER ();
1049 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1052 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1054 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1058 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1061 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1065 GPtrArray *assemblies;
1068 * Make a copy of the list of assemblies because we can't hold the assemblies
1069 * lock while creating objects etc.
1071 assemblies = g_ptr_array_new ();
1072 /* Need to skip internal assembly builders created by remoting */
1073 mono_domain_assemblies_lock (domain);
1074 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1075 ass = (MonoAssembly *)tmp->data;
1076 if (refonly != ass->ref_only)
1078 if (ass->corlib_internal)
1080 g_ptr_array_add (assemblies, ass);
1082 mono_domain_assemblies_unlock (domain);
1084 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1087 for (i = 0; i < assemblies->len; ++i) {
1088 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1093 g_ptr_array_free (assemblies, TRUE);
1098 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1100 HANDLE_FUNCTION_ENTER ();
1102 MonoAssembly *result = NULL;
1103 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1106 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1108 HANDLE_FUNCTION_RETURN_VAL (result);
1112 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1114 MonoAssembly *ret = NULL;
1116 MonoBoolean isrefonly;
1117 gpointer params [3];
1121 if (mono_runtime_get_no_exec ())
1124 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1126 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1127 g_assert (method != NULL);
1129 isrefonly = refonly ? 1 : 0;
1130 MonoReflectionAssemblyHandle requesting_handle;
1132 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1133 return_val_if_nok (error, ret);
1135 params [0] = MONO_HANDLE_RAW (fname);
1136 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1137 params [2] = &isrefonly;
1138 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1139 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1144 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1148 MonoAssembly *assembly;
1149 MonoDomain *domain = mono_domain_get ();
1152 aname_str = mono_stringify_assembly_name (aname);
1154 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1156 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1158 mono_error_cleanup (&error);
1164 * LOCKING: assumes assemblies_lock in the domain is already locked.
1167 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1171 gboolean destroy_ht = FALSE;
1173 if (!ass->aname.name)
1177 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1179 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1180 g_hash_table_insert (ht, tmp->data, tmp->data);
1184 /* FIXME: handle lazy loaded assemblies */
1186 if (!g_hash_table_lookup (ht, ass)) {
1187 mono_assembly_addref (ass);
1188 g_hash_table_insert (ht, ass, ass);
1189 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1190 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);
1193 if (ass->image->references) {
1194 for (i = 0; i < ass->image->nreferences; i++) {
1195 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1196 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1197 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1203 g_hash_table_destroy (ht);
1207 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1209 static MonoClassField *assembly_load_field;
1210 static MonoMethod *assembly_load_method;
1212 MonoDomain *domain = mono_domain_get ();
1214 gpointer load_value;
1217 if (!domain->domain)
1218 /* This can happen during startup */
1220 #ifdef ASSEMBLY_LOAD_DEBUG
1221 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1223 klass = domain->domain->mbr.obj.vtable->klass;
1225 mono_domain_assemblies_lock (domain);
1226 add_assemblies_to_domain (domain, assembly, NULL);
1227 mono_domain_assemblies_unlock (domain);
1229 if (assembly_load_field == NULL) {
1230 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1231 g_assert (assembly_load_field);
1234 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1235 if (load_value == NULL) {
1236 /* No events waiting to be triggered */
1240 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1241 mono_error_assert_ok (&error);
1243 if (assembly_load_method == NULL) {
1244 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1245 g_assert (assembly_load_method);
1248 *params = MONO_HANDLE_RAW(ref_assembly);
1250 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1251 mono_error_cleanup (&error);
1255 * LOCKING: Acquires the domain assemblies lock.
1258 set_domain_search_path (MonoDomain *domain)
1261 MonoAppDomainSetup *setup;
1263 gchar *search_path = NULL;
1266 gchar **pvt_split = NULL;
1267 GError *gerror = NULL;
1268 gint appbaselen = -1;
1271 * We use the low-level domain assemblies lock, since this is called from
1272 * assembly loads hooks, which means this thread might hold the loader lock.
1274 mono_domain_assemblies_lock (domain);
1276 if (!domain->setup) {
1277 mono_domain_assemblies_unlock (domain);
1281 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1282 mono_domain_assemblies_unlock (domain);
1285 setup = domain->setup;
1286 if (!setup->application_base) {
1287 mono_domain_assemblies_unlock (domain);
1288 return; /* Must set application base to get private path working */
1293 if (setup->private_bin_path) {
1294 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1295 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1296 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1297 mono_error_cleanup (&error);
1298 mono_domain_assemblies_unlock (domain);
1303 if (domain->private_bin_path) {
1304 if (search_path == NULL)
1305 search_path = domain->private_bin_path;
1307 gchar *tmp2 = search_path;
1308 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1315 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1316 * directories relative to ApplicationBase separated by semicolons (see
1317 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1318 * The loop below copes with the fact that some Unix applications may use ':' (or
1319 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1320 * ';' for the subsequent split.
1322 * The issue was reported in bug #81446
1325 #ifndef TARGET_WIN32
1328 slen = strlen (search_path);
1329 for (i = 0; i < slen; i++)
1330 if (search_path [i] == ':')
1331 search_path [i] = ';';
1334 pvt_split = g_strsplit (search_path, ";", 1000);
1335 g_free (search_path);
1336 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1341 g_strfreev (pvt_split);
1343 * Don't do this because the first time is called, the domain
1344 * setup is not finished.
1346 * domain->search_path = g_malloc (sizeof (char *));
1347 * domain->search_path [0] = NULL;
1349 mono_domain_assemblies_unlock (domain);
1353 if (domain->search_path)
1354 g_strfreev (domain->search_path);
1356 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1357 tmp [npaths] = NULL;
1359 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1360 if (!mono_error_ok (&error)) {
1361 mono_error_cleanup (&error);
1362 g_strfreev (pvt_split);
1365 mono_domain_assemblies_unlock (domain);
1369 domain->search_path = tmp;
1371 /* FIXME: is this needed? */
1372 if (strncmp (*tmp, "file://", 7) == 0) {
1378 uri = g_strdup_printf ("file:///%s", uri + 7);
1381 uri = mono_escape_uri_string (tmpuri);
1382 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1388 if (gerror != NULL) {
1389 g_warning ("%s\n", gerror->message);
1390 g_error_free (gerror);
1397 for (i = 1; pvt_split && i < npaths; i++) {
1398 if (g_path_is_absolute (pvt_split [i - 1])) {
1399 tmp [i] = g_strdup (pvt_split [i - 1]);
1401 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1404 if (strchr (tmp [i], '.')) {
1408 reduced = mono_path_canonicalize (tmp [i]);
1409 if (appbaselen == -1)
1410 appbaselen = strlen (tmp [0]);
1412 if (strncmp (tmp [0], reduced, appbaselen)) {
1415 tmp [i] = g_strdup ("");
1425 if (setup->private_bin_path_probe != NULL) {
1427 tmp [0] = g_strdup ("");
1430 domain->setup->path_changed = FALSE;
1432 g_strfreev (pvt_split);
1434 mono_domain_assemblies_unlock (domain);
1437 #ifdef DISABLE_SHADOW_COPY
1439 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1445 mono_make_shadow_copy (const char *filename, MonoError *error)
1448 return (char *) filename;
1452 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1454 guint16 *orig, *dest;
1455 gboolean copy_result;
1458 strcpy (src + srclen - tail_len, extension);
1460 if (IS_PORTABILITY_CASE) {
1461 gchar *file = mono_portability_find_file (src, TRUE);
1467 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1471 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1473 strcpy (target + targetlen - tail_len, extension);
1474 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1476 mono_w32file_delete (dest);
1478 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1480 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1481 * overwritten when updated in their original locations. */
1483 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1492 get_cstring_hash (const char *str)
1498 if (!str || !str [0])
1503 for (i = 0; i < len; i++) {
1504 h = (h << 5) - h + *p;
1512 * Returned memory is malloc'd. Called must free it
1515 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1517 MonoAppDomainSetup *setup;
1518 char *cache_path, *appname;
1524 setup = domain->setup;
1525 if (setup->cache_path != NULL && setup->application_name != NULL) {
1526 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1527 return_val_if_nok (error, NULL);
1529 #ifndef TARGET_WIN32
1532 for (i = strlen (cache_path) - 1; i >= 0; i--)
1533 if (cache_path [i] == '\\')
1534 cache_path [i] = '/';
1538 appname = mono_string_to_utf8_checked (setup->application_name, error);
1539 if (!mono_error_ok (error)) {
1540 g_free (cache_path);
1544 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1546 g_free (cache_path);
1548 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1549 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1556 get_shadow_assembly_location (const char *filename, MonoError *error)
1558 gint32 hash = 0, hash2 = 0;
1560 char path_hash [30];
1561 char *bname = g_path_get_basename (filename);
1562 char *dirname = g_path_get_dirname (filename);
1563 char *location, *tmploc;
1564 MonoDomain *domain = mono_domain_get ();
1568 hash = get_cstring_hash (bname);
1569 hash2 = get_cstring_hash (dirname);
1570 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1571 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1572 tmploc = get_shadow_assembly_location_base (domain, error);
1573 if (!mono_error_ok (error)) {
1579 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1587 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1589 struct stat sbuf_dest;
1591 gchar *real_src = mono_portability_find_file (src, TRUE);
1594 stat_src = (gchar*)src;
1596 stat_src = real_src;
1598 if (stat (stat_src, sbuf_src) == -1) {
1599 time_t tnow = time (NULL);
1604 memset (sbuf_src, 0, sizeof (*sbuf_src));
1605 sbuf_src->st_mtime = tnow;
1606 sbuf_src->st_atime = tnow;
1613 if (stat (dest, &sbuf_dest) == -1)
1616 if (sbuf_src->st_size == sbuf_dest.st_size &&
1617 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1624 shadow_copy_create_ini (const char *shadow, const char *filename)
1634 dir_name = g_path_get_dirname (shadow);
1635 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1637 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1642 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1647 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1649 if (handle == INVALID_HANDLE_VALUE) {
1653 full_path = mono_path_resolve_symlinks (filename);
1654 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1656 mono_w32file_close (handle);
1661 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1664 MonoAppDomainSetup *setup;
1667 gchar **directories;
1668 gchar *shadow_status_string;
1670 gboolean shadow_enabled;
1671 gboolean found = FALSE;
1676 setup = domain->setup;
1677 if (setup == NULL || setup->shadow_copy_files == NULL)
1680 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1681 if (!mono_error_ok (&error)) {
1682 mono_error_cleanup (&error);
1685 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1686 g_free (shadow_status_string);
1688 if (!shadow_enabled)
1691 if (setup->shadow_copy_directories == NULL)
1694 /* Is dir_name a shadow_copy destination already? */
1695 base_dir = get_shadow_assembly_location_base (domain, &error);
1696 if (!mono_error_ok (&error)) {
1697 mono_error_cleanup (&error);
1701 if (strstr (dir_name, base_dir)) {
1707 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1708 if (!mono_error_ok (&error)) {
1709 mono_error_cleanup (&error);
1713 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1714 dir_ptr = directories;
1716 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1722 g_strfreev (directories);
1728 This function raises exceptions so it can cause as sorts of nasty stuff if called
1729 while holding a lock.
1730 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1731 or NULL if source file not found.
1732 FIXME bubble up the error instead of raising it here
1735 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1738 gchar *sibling_source, *sibling_target;
1739 gint sibling_source_len, sibling_target_len;
1740 guint16 *orig, *dest;
1743 gboolean copy_result;
1744 struct stat src_sbuf;
1745 struct utimbuf utbuf;
1746 char *dir_name = g_path_get_dirname (filename);
1747 MonoDomain *domain = mono_domain_get ();
1751 error_init (oerror);
1753 set_domain_search_path (domain);
1755 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1757 return (char *) filename;
1760 /* Is dir_name a shadow_copy destination already? */
1761 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1762 if (!mono_error_ok (&error)) {
1763 mono_error_cleanup (&error);
1765 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1769 if (strstr (dir_name, shadow_dir)) {
1770 g_free (shadow_dir);
1772 return (char *) filename;
1774 g_free (shadow_dir);
1777 shadow = get_shadow_assembly_location (filename, &error);
1778 if (!mono_error_ok (&error)) {
1779 mono_error_cleanup (&error);
1780 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1784 if (g_ensure_directory_exists (shadow) == FALSE) {
1786 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1790 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1791 return (char*) shadow;
1793 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1794 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1795 mono_w32file_delete (dest);
1797 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1798 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1799 * and not have it runtime error" */
1800 attrs = mono_w32file_get_attributes (orig);
1801 if (attrs == INVALID_FILE_ATTRIBUTES) {
1803 return (char *)filename;
1806 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1808 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1809 * overwritten when updated in their original locations. */
1811 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1816 if (copy_result == FALSE) {
1819 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1820 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1821 return NULL; /* file not found, shadow copy failed */
1823 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1827 /* attempt to copy .mdb, .config if they exist */
1828 sibling_source = g_strconcat (filename, ".config", NULL);
1829 sibling_source_len = strlen (sibling_source);
1830 sibling_target = g_strconcat (shadow, ".config", NULL);
1831 sibling_target_len = strlen (sibling_target);
1833 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1835 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1837 g_free (sibling_source);
1838 g_free (sibling_target);
1842 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1846 /* Create a .ini file containing the original assembly location */
1847 if (!shadow_copy_create_ini (shadow, filename)) {
1849 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1853 utbuf.actime = src_sbuf.st_atime;
1854 utbuf.modtime = src_sbuf.st_mtime;
1855 utime (shadow, &utbuf);
1859 #endif /* DISABLE_SHADOW_COPY */
1862 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1864 HANDLE_FUNCTION_ENTER ();
1865 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1866 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1867 HANDLE_FUNCTION_RETURN_VAL (result);
1871 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1873 HANDLE_FUNCTION_ENTER ();
1874 MonoDomain *dom = NULL;
1875 if (MONO_HANDLE_IS_NULL (appdomain))
1878 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1879 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1880 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1882 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1884 dom = MONO_HANDLE_GETVAL (appdomain, data);
1887 HANDLE_FUNCTION_RETURN_VAL (dom);
1892 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1893 const gchar *path3, const gchar *path4,
1894 gboolean refonly, gboolean is_private)
1897 gboolean found = FALSE;
1900 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1902 if (IS_PORTABILITY_SET) {
1903 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1906 fullpath = new_fullpath;
1910 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1913 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1916 return (*assembly != NULL);
1919 static MonoAssembly *
1920 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1922 MonoAssembly *result = NULL;
1925 const gchar *local_culture;
1927 gboolean is_private = FALSE;
1929 if (!culture || *culture == '\0') {
1932 local_culture = culture;
1935 filename = g_strconcat (name, ".dll", NULL);
1936 len = strlen (filename);
1938 for (path = search_path; *path; path++) {
1939 if (**path == '\0') {
1941 continue; /* Ignore empty ApplicationBase */
1944 /* See test cases in bug #58992 and bug #57710 */
1945 /* 1st try: [culture]/[name].dll (culture may be empty) */
1946 strcpy (filename + len - 4, ".dll");
1947 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1950 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1951 strcpy (filename + len - 4, ".exe");
1952 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1955 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1956 strcpy (filename + len - 4, ".dll");
1957 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1960 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1961 strcpy (filename + len - 4, ".exe");
1962 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1971 * Try loading the assembly from ApplicationBase and PrivateBinPath
1972 * and then from assemblies_path if any.
1973 * LOCKING: This is called from the assembly loading code, which means the caller
1974 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1976 static MonoAssembly *
1977 mono_domain_assembly_preload (MonoAssemblyName *aname,
1978 gchar **assemblies_path,
1981 MonoDomain *domain = mono_domain_get ();
1982 MonoAssembly *result = NULL;
1983 gboolean refonly = GPOINTER_TO_UINT (user_data);
1985 set_domain_search_path (domain);
1987 if (domain->search_path && domain->search_path [0] != NULL) {
1988 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1991 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1992 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1999 * Check whenever a given assembly was already loaded in the current appdomain.
2001 static MonoAssembly *
2002 mono_domain_assembly_search (MonoAssemblyName *aname,
2005 MonoDomain *domain = mono_domain_get ();
2008 gboolean refonly = GPOINTER_TO_UINT (user_data);
2010 mono_domain_assemblies_lock (domain);
2011 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2012 ass = (MonoAssembly *)tmp->data;
2013 /* Dynamic assemblies can't match here in MS.NET */
2014 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2017 mono_domain_assemblies_unlock (domain);
2020 mono_domain_assemblies_unlock (domain);
2025 MonoReflectionAssemblyHandle
2026 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2029 MonoDomain *domain = mono_domain_get ();
2030 char *name, *filename;
2031 MonoImageOpenStatus status = MONO_IMAGE_OK;
2032 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2037 if (fname == NULL) {
2038 mono_error_set_argument_null (error, "assemblyFile", "");
2042 name = filename = mono_string_handle_to_utf8 (fname, error);
2046 MonoAssembly *ass = mono_assembly_open_a_lot (filename, &status, refOnly, TRUE);
2049 if (status == MONO_IMAGE_IMAGE_INVALID)
2050 mono_error_set_bad_image_name (error, g_strdup (name), "");
2052 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2056 result = mono_assembly_get_object_handle (domain, ass, error);
2063 MonoReflectionAssemblyHandle
2064 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2065 MonoArrayHandle raw_assembly,
2066 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2067 MonoBoolean refonly,
2072 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2073 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2074 MonoImageOpenStatus status;
2075 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2077 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2078 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2079 if (!assembly_data) {
2080 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2084 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2085 memcpy (assembly_data, raw_data, raw_assembly_len);
2086 mono_gchandle_free (gchandle); /* unpin */
2087 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2089 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2092 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2096 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2097 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2098 uint32_t symbol_gchandle;
2099 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2100 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2101 mono_gchandle_free (symbol_gchandle);
2104 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2108 mono_image_close (image);
2109 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2113 refass = mono_assembly_get_object_handle (domain, ass, error);
2114 if (!MONO_HANDLE_IS_NULL(refass))
2115 MONO_HANDLE_SET (refass, evidence, evidence);
2119 MonoReflectionAssemblyHandle
2120 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2123 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2124 MonoImageOpenStatus status = MONO_IMAGE_OK;
2126 MonoAssemblyName aname;
2132 name = mono_string_handle_to_utf8 (assRef, error);
2135 parsed = mono_assembly_name_parse (name, &aname);
2139 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2140 /* This is a parse error... */
2142 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2146 refass = mono_assembly_get_object_handle (domain, assm, error);
2154 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2155 mono_assembly_name_free (&aname);
2158 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2160 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2169 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2173 MONO_HANDLE_SET (refass, evidence, evidence);
2177 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2181 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2184 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2186 if (NULL == domain) {
2187 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2191 if (domain == mono_get_root_domain ()) {
2192 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2197 * Unloading seems to cause problems when running NUnit/NAnt, hence
2200 if (g_getenv ("MONO_NO_UNLOAD"))
2202 #ifdef __native_client__
2206 MonoException *exc = NULL;
2207 mono_domain_try_unload (domain, (MonoObject**)&exc);
2209 mono_error_set_exception_instance (error, exc);
2213 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2216 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2221 return mono_domain_is_unloading (domain);
2225 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2227 mono_unhandled_exception ((MonoObject*) exc);
2231 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2232 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2239 g_assert (!MONO_HANDLE_IS_NULL (refass));
2240 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2241 image = assembly->image;
2244 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2247 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2249 if (MONO_HANDLE_IS_NULL (args)) {
2250 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2251 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2252 mono_error_assert_ok (error);
2255 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2260 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2262 return ad->data->domain_id;
2266 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2269 MonoDomain *old_domain = mono_domain_get ();
2271 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2272 mono_error_set_appdomain_unloaded (error);
2273 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2276 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2280 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2282 MonoDomain *current_domain = mono_domain_get ();
2283 MonoDomain *domain = mono_domain_get_by_id (domainid);
2285 if (!domain || !mono_domain_set (domain, FALSE)) {
2286 mono_error_set_appdomain_unloaded (error);
2287 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2290 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2294 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2297 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2301 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2304 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2308 * Raise an exception to prevent the managed code from executing a pop
2311 mono_error_set_appdomain_unloaded (error);
2315 mono_thread_push_appdomain_ref (domain);
2319 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2322 mono_thread_pop_appdomain_ref ();
2326 ves_icall_System_AppDomain_InternalGetContext ()
2328 return mono_context_get ();
2332 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2334 return mono_domain_get ()->default_context;
2338 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2340 MonoAppContext *old_context = mono_context_get ();
2342 mono_context_set (mc);
2348 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2351 MonoDomain* mono_root_domain = mono_get_root_domain ();
2352 mono_domain_lock (mono_root_domain);
2353 if (process_guid_set) {
2354 mono_domain_unlock (mono_root_domain);
2355 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2357 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2358 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2359 mono_gchandle_free (gchandle);
2360 process_guid_set = TRUE;
2361 mono_domain_unlock (mono_root_domain);
2366 mono_domain_is_unloading (MonoDomain *domain)
2368 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2375 clear_cached_vtable (MonoVTable *vtable)
2377 MonoClass *klass = vtable->klass;
2378 MonoDomain *domain = vtable->domain;
2379 MonoClassRuntimeInfo *runtime_info;
2382 runtime_info = klass->runtime_info;
2383 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2384 runtime_info->domain_vtables [domain->domain_id] = NULL;
2385 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2386 mono_gc_free_fixed (data);
2389 static G_GNUC_UNUSED void
2390 zero_static_data (MonoVTable *vtable)
2392 MonoClass *klass = vtable->klass;
2395 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2396 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2399 typedef struct unload_data {
2402 char *failure_reason;
2407 unload_data_unref (unload_data *data)
2411 mono_atomic_load_acquire (count, gint32, &data->refcount);
2412 g_assert (count >= 1 && count <= 2);
2417 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2421 deregister_reflection_info_roots_from_list (MonoImage *image)
2423 GSList *list = image->reflection_info_unregister_classes;
2426 MonoClass *klass = (MonoClass *)list->data;
2428 mono_class_free_ref_info (klass);
2433 image->reflection_info_unregister_classes = NULL;
2437 deregister_reflection_info_roots (MonoDomain *domain)
2441 mono_domain_assemblies_lock (domain);
2442 for (list = domain->domain_assemblies; list; list = list->next) {
2443 MonoAssembly *assembly = (MonoAssembly *)list->data;
2444 MonoImage *image = assembly->image;
2448 * No need to take the image lock here since dynamic images are appdomain bound and
2449 * at this point the mutator is gone. Taking the image lock here would mean
2450 * promoting it from a simple lock to a complex lock, which we better avoid if
2453 if (image_is_dynamic (image))
2454 deregister_reflection_info_roots_from_list (image);
2456 for (i = 0; i < image->module_count; ++i) {
2457 MonoImage *module = image->modules [i];
2458 if (module && image_is_dynamic (module))
2459 deregister_reflection_info_roots_from_list (module);
2462 mono_domain_assemblies_unlock (domain);
2466 unload_thread_main (void *arg)
2469 unload_data *data = (unload_data*)arg;
2470 MonoDomain *domain = data->domain;
2471 MonoInternalThread *internal;
2474 internal = mono_thread_internal_current ();
2476 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2477 if (!is_ok (&error)) {
2478 data->failure_reason = g_strdup (mono_error_get_message (&error));
2479 mono_error_cleanup (&error);
2484 * FIXME: Abort our parent thread last, so we can return a failure
2485 * indication if aborting times out.
2487 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2488 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2492 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2493 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2497 /* Finalize all finalizable objects in the doomed appdomain */
2498 if (!mono_domain_finalize (domain, -1)) {
2499 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2503 /* Clear references to our vtables in class->runtime_info.
2504 * We also hold the loader lock because we're going to change
2505 * class->runtime_info.
2508 mono_loader_lock (); //FIXME why do we need the loader lock here?
2509 mono_domain_lock (domain);
2512 * We need to make sure that we don't have any remsets
2513 * pointing into static data of the to-be-freed domain because
2514 * at the next collections they would be invalid. So what we
2515 * do is we first zero all static data and then do a minor
2516 * collection. Because all references in the static data will
2517 * now be null we won't do any unnecessary copies and after
2518 * the collection there won't be any more remsets.
2520 for (i = 0; i < domain->class_vtable_array->len; ++i)
2521 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2522 mono_gc_collect (0);
2524 for (i = 0; i < domain->class_vtable_array->len; ++i)
2525 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2526 deregister_reflection_info_roots (domain);
2528 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2530 mono_domain_unlock (domain);
2531 mono_loader_unlock ();
2533 domain->state = MONO_APPDOMAIN_UNLOADED;
2535 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2537 /* remove from the handle table the items related to this domain */
2538 mono_gchandle_free_domain (domain);
2540 mono_domain_free (domain, FALSE);
2542 mono_gc_collect (mono_gc_max_generation ());
2544 mono_atomic_store_release (&data->done, TRUE);
2545 unload_data_unref (data);
2549 mono_atomic_store_release (&data->done, TRUE);
2550 unload_data_unref (data);
2555 * mono_domain_unload:
2556 * @domain: The domain to unload
2558 * Unloads an appdomain. Follows the process outlined in the comment
2559 * for mono_domain_try_unload.
2562 mono_domain_unload (MonoDomain *domain)
2564 MonoObject *exc = NULL;
2565 mono_domain_try_unload (domain, &exc);
2568 static MonoThreadInfoWaitRet
2569 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2571 MonoThreadInfoWaitRet result;
2574 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2581 * mono_domain_unload:
2582 * @domain: The domain to unload
2583 * @exc: Exception information
2585 * Unloads an appdomain. Follows the process outlined in:
2586 * http://blogs.gotdotnet.com/cbrumme
2588 * If doing things the 'right' way is too hard or complex, we do it the
2589 * 'simple' way, which means do everything needed to avoid crashes and
2590 * memory leaks, but not much else.
2592 * It is required to pass a valid reference to the exc argument, upon return
2593 * from this function *exc will be set to the exception thrown, if any.
2595 * If this method is not called from an icall (embedded scenario for instance),
2596 * it must not be called with any managed frames on the stack, since the unload
2597 * process could end up trying to abort the current thread.
2600 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2603 MonoThreadHandle *thread_handle;
2604 MonoAppDomainState prev_state;
2606 unload_data *thread_data;
2607 MonoInternalThread *internal;
2608 MonoDomain *caller_domain = mono_domain_get ();
2610 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2612 /* Atomically change our state to UNLOADING */
2613 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2614 MONO_APPDOMAIN_UNLOADING_START,
2615 MONO_APPDOMAIN_CREATED);
2616 if (prev_state != MONO_APPDOMAIN_CREATED) {
2617 switch (prev_state) {
2618 case MONO_APPDOMAIN_UNLOADING_START:
2619 case MONO_APPDOMAIN_UNLOADING:
2620 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2622 case MONO_APPDOMAIN_UNLOADED:
2623 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2626 g_warning ("Invalid appdomain state %d", prev_state);
2627 g_assert_not_reached ();
2631 mono_domain_set (domain, FALSE);
2632 /* Notify OnDomainUnload listeners */
2633 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2636 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2638 if (!mono_error_ok (&error)) {
2640 mono_error_cleanup (&error);
2642 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2646 /* Roll back the state change */
2647 domain->state = MONO_APPDOMAIN_CREATED;
2648 mono_domain_set (caller_domain, FALSE);
2651 mono_domain_set (caller_domain, FALSE);
2653 thread_data = g_new0 (unload_data, 1);
2654 thread_data->domain = domain;
2655 thread_data->failure_reason = NULL;
2656 thread_data->done = FALSE;
2657 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2659 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2660 domain->state = MONO_APPDOMAIN_UNLOADING;
2662 * First we create a separate thread for unloading, since
2663 * we might have to abort some threads, including the current one.
2665 * Have to attach to the runtime so shutdown can wait for this thread.
2667 * Force it to be attached to avoid racing during shutdown.
2669 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2670 mono_error_assert_ok (&error);
2672 thread_handle = mono_threads_open_thread_handle (internal->handle);
2674 /* Wait for the thread */
2675 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2676 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2677 /* The unload thread tries to abort us */
2678 /* The icall wrapper will execute the abort */
2679 mono_threads_close_thread_handle (thread_handle);
2680 unload_data_unref (thread_data);
2685 mono_threads_close_thread_handle (thread_handle);
2687 if (thread_data->failure_reason) {
2688 /* Roll back the state change */
2689 domain->state = MONO_APPDOMAIN_CREATED;
2691 g_warning ("%s", thread_data->failure_reason);
2693 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2695 g_free (thread_data->failure_reason);
2696 thread_data->failure_reason = NULL;
2699 unload_data_unref (thread_data);