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/exception.h>
43 #include <mono/metadata/exception-internals.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/threadpool.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/marshal-internals.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/w32file.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/metadata/abi-details.h>
61 #include <mono/metadata/w32socket.h>
62 #include <mono/utils/mono-uri.h>
63 #include <mono/utils/mono-logger-internals.h>
64 #include <mono/utils/mono-path.h>
65 #include <mono/utils/mono-stdlib.h>
66 #include <mono/utils/mono-io-portability.h>
67 #include <mono/utils/mono-error-internals.h>
68 #include <mono/utils/atomic.h>
69 #include <mono/utils/mono-memory-model.h>
70 #include <mono/utils/mono-threads.h>
71 #include <mono/metadata/w32handle.h>
72 #include <mono/metadata/w32error.h>
73 #include <mono/utils/w32api.h>
79 * This is the version number of the corlib-runtime interface. When
80 * making changes to this interface (by changing the layout
81 * of classes the runtime knows about, changing icall signature or
82 * semantics etc), increment this variable. Also increment the
83 * pair of this variable in mscorlib in:
84 * mcs/class/corlib/System/Environment.cs
86 * Changes which are already detected at runtime, like the addition
87 * of icalls, do not require an increment.
89 #define MONO_CORLIB_VERSION 164
94 int assemblybinding_count;
99 static gunichar2 process_guid [36];
100 static gboolean process_guid_set = FALSE;
102 static gboolean no_exec = FALSE;
104 static MonoAssembly *
105 mono_domain_assembly_preload (MonoAssemblyName *aname,
106 gchar **assemblies_path,
109 static MonoAssembly *
110 mono_domain_assembly_search (MonoAssemblyName *aname,
114 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
117 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
119 static MonoAppDomainHandle
120 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
123 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
127 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
129 static MonoLoadFunc load_function = NULL;
131 /* Lazy class loading functions */
132 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
134 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
137 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
140 mono_error_set_appdomain_unloaded (MonoError *error)
142 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
146 mono_install_runtime_load (MonoLoadFunc func)
148 load_function = func;
152 mono_runtime_load (const char *filename, const char *runtime_version)
154 g_assert (load_function);
155 return load_function (filename, runtime_version);
159 * mono_runtime_set_no_exec:
161 * Instructs the runtime to operate in static mode, i.e. avoid/do not
162 * allow managed code execution. This is useful for running the AOT
163 * compiler on platforms which allow full-aot execution only. This
164 * should be called before mono_runtime_init ().
167 mono_runtime_set_no_exec (gboolean val)
173 * mono_runtime_get_no_exec:
175 * If true, then the runtime will not allow managed code execution.
178 mono_runtime_get_no_exec (void)
184 create_domain_objects (MonoDomain *domain)
187 MonoDomain *old_domain = mono_domain_get ();
189 MonoVTable *string_vt;
190 MonoClassField *string_empty_fld;
192 if (domain != old_domain) {
193 mono_thread_push_appdomain_ref (domain);
194 mono_domain_set_internal_with_options (domain, FALSE);
198 * Initialize String.Empty. This enables the removal of
199 * the static cctor of the String class.
201 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
202 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
203 g_assert (string_empty_fld);
204 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
205 mono_error_assert_ok (&error);
206 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
207 domain->empty_string = empty_str;
210 * Create an instance early since we can't do it when there is no memory.
212 arg = mono_string_new (domain, "Out of memory");
213 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
214 mono_error_assert_ok (&error);
217 * These two are needed because the signal handlers might be executing on
218 * an alternate stack, and Boehm GC can't handle that.
220 arg = mono_string_new (domain, "A null value was found where an object instance was required");
221 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
222 mono_error_assert_ok (&error);
223 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
224 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
225 mono_error_assert_ok (&error);
227 /*The ephemeron tombstone i*/
228 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
229 mono_error_assert_ok (&error);
231 if (domain != old_domain) {
232 mono_thread_pop_appdomain_ref ();
233 mono_domain_set_internal_with_options (old_domain, FALSE);
237 * This class is used during exception handling, so initialize it here, to prevent
238 * stack overflows while handling stack overflows.
240 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
245 * @domain: domain returned by mono_init ()
247 * Initialize the core AppDomain: this function will run also some
248 * IL initialization code, so it needs the execution engine to be fully
251 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
252 * we know the entry_assembly.
256 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
259 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
260 mono_error_cleanup (&error);
264 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
266 MonoAppDomainSetup *setup;
272 mono_portability_helpers_init ();
274 mono_gc_base_init ();
275 mono_monitor_init ();
276 mono_marshal_init ();
278 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
279 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
280 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
281 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
282 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
283 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
284 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
286 mono_thread_init (start_cb, attach_cb);
288 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
289 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
290 return_if_nok (error);
292 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
294 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
295 return_if_nok (error);
299 domain->setup = setup;
301 mono_thread_attach (domain);
303 mono_type_initialization_init ();
305 if (!mono_runtime_get_no_exec ())
306 create_domain_objects (domain);
308 /* GC init has to happen after thread init */
311 /* contexts use GC handles, so they must be initialized after the GC */
312 mono_context_init_checked (domain, error);
313 return_if_nok (error);
314 mono_context_set (domain->default_context);
316 #ifndef DISABLE_SOCKETS
317 mono_network_init ();
320 mono_console_init ();
323 mono_locks_tracer_init ();
325 /* mscorlib is loaded before we install the load hook */
326 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
332 mono_get_corlib_version (void)
336 MonoClassField *field;
339 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
340 mono_class_init (klass);
341 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
344 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
346 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
347 mono_error_assert_ok (&error);
348 return *(gint32*)((gchar*)value + sizeof (MonoObject));
352 * mono_check_corlib_version
354 * Checks that the corlib that is loaded matches the version of this runtime.
356 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
357 * allocated string with the error otherwise.
360 mono_check_corlib_version (void)
362 int version = mono_get_corlib_version ();
363 if (version != MONO_CORLIB_VERSION)
364 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
366 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
367 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
368 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
369 if (native_offset != managed_offset)
370 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
377 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
379 * Initializes the @domain's default System.Runtime.Remoting's Context.
382 mono_context_init (MonoDomain *domain)
385 mono_context_init_checked (domain, &error);
386 mono_error_cleanup (&error);
390 mono_context_init_checked (MonoDomain *domain, MonoError *error)
393 MonoAppContext *context;
397 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
398 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
399 return_if_nok (error);
401 context->domain_id = domain->domain_id;
402 context->context_id = 0;
403 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
404 domain->default_context = context;
408 * mono_runtime_cleanup:
413 * This must not be called while there are still running threads executing
417 mono_runtime_cleanup (MonoDomain *domain)
419 mono_attach_cleanup ();
421 /* This ends up calling any pending pending (for at most 2 seconds) */
424 mono_thread_cleanup ();
426 #ifndef DISABLE_SOCKETS
427 mono_network_cleanup ();
429 mono_marshal_cleanup ();
431 mono_type_initialization_cleanup ();
433 mono_monitor_cleanup ();
436 static MonoDomainFunc quit_function = NULL;
439 mono_install_runtime_cleanup (MonoDomainFunc func)
441 quit_function = func;
447 if (quit_function != NULL)
448 quit_function (mono_get_root_domain (), NULL);
452 * mono_domain_create_appdomain:
453 * @friendly_name: The friendly name of the appdomain to create
454 * @configuration_file: The configuration file to initialize the appdomain with
456 * Returns a MonoDomain initialized with the appdomain
459 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
461 HANDLE_FUNCTION_ENTER ();
463 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
464 mono_error_cleanup (&error);
465 HANDLE_FUNCTION_RETURN_VAL (domain);
469 * mono_domain_create_appdomain_checked:
470 * @friendly_name: The friendly name of the appdomain to create
471 * @configuration_file: The configuration file to initialize the appdomain with
472 * @error: Set on error.
474 * Returns a MonoDomain initialized with the appdomain. On failure sets @error and returns NULL.
477 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
479 HANDLE_FUNCTION_ENTER ();
481 MonoDomain *result = NULL;
483 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
484 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
487 MonoStringHandle config_file;
488 if (configuration_file != NULL) {
489 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
493 config_file = MONO_HANDLE_NEW (MonoString, NULL);
495 MONO_HANDLE_SET (setup, configuration_file, config_file);
497 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
501 result = mono_domain_from_appdomain_handle (ad);
503 HANDLE_FUNCTION_RETURN_VAL (result);
507 * mono_domain_set_config:
508 * @domain: MonoDomain initialized with the appdomain we want to change
509 * @base_dir: new base directory for the appdomain
510 * @config_file_name: path to the new configuration for the app domain
512 * Used to set the system configuration for an appdomain
514 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
515 * Error Initializing the configuration system. ---> System.ArgumentException:
516 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
519 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
521 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
522 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
525 static MonoAppDomainSetupHandle
526 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
528 HANDLE_FUNCTION_ENTER ();
529 MonoDomain *caller_domain;
530 MonoClass *ads_class;
531 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
535 caller_domain = mono_domain_get ();
536 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
538 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
542 mono_domain_set_internal (domain);
544 #define XCOPY_FIELD(dst,field,src,error) \
546 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
547 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
548 if (!is_ok (error)) \
550 MONO_HANDLE_SET ((dst),field,copied_val); \
553 #define COPY_VAL(dst,field,type,src) \
555 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
558 XCOPY_FIELD (copy, application_base, setup, error);
559 XCOPY_FIELD (copy, application_name, setup, error);
560 XCOPY_FIELD (copy, cache_path, setup, error);
561 XCOPY_FIELD (copy, configuration_file, setup, error);
562 XCOPY_FIELD (copy, dynamic_base, setup, error);
563 XCOPY_FIELD (copy, license_file, setup, error);
564 XCOPY_FIELD (copy, private_bin_path, setup, error);
565 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
566 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
567 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
568 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
569 COPY_VAL (copy, path_changed, MonoBoolean, setup);
570 COPY_VAL (copy, loader_optimization, int, setup);
571 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
572 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
573 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
574 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
575 XCOPY_FIELD (copy, application_trust, setup, error);
576 XCOPY_FIELD (copy, configuration_bytes, setup, error);
577 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
582 mono_domain_set_internal (caller_domain);
584 MONO_HANDLE_ASSIGN (result, copy);
586 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
589 static MonoAppDomainHandle
590 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
592 HANDLE_FUNCTION_ENTER ();
593 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
599 adclass = mono_class_get_appdomain_class ();
601 /* FIXME: pin all those objects */
602 data = mono_domain_create();
604 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
607 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
608 data->domain = MONO_HANDLE_RAW (ad);
609 data->friendly_name = g_strdup (friendly_name);
611 mono_profiler_appdomain_name (data, data->friendly_name);
613 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
614 if (MONO_HANDLE_IS_NULL (app_base)) {
615 /* Inherit from the root domain since MS.NET does this */
616 MonoDomain *root = mono_get_root_domain ();
617 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
618 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
619 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
620 /* N.B. new string is in the new domain */
621 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
622 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);
623 mono_gchandle_free (gchandle);
624 if (!is_ok (error)) {
625 g_free (data->friendly_name);
628 MONO_HANDLE_SET (setup, application_base, s);
632 mono_context_init_checked (data, error);
636 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
637 if (!mono_error_ok (error)) {
638 g_free (data->friendly_name);
642 mono_domain_set_options_from_config (data);
643 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
645 #ifndef DISABLE_SHADOW_COPY
646 /*FIXME, guard this for when the debugger is not running */
647 char *shadow_location = get_shadow_assembly_location_base (data, error);
648 if (!mono_error_ok (error)) {
649 g_free (data->friendly_name);
653 g_free (shadow_location);
656 create_domain_objects (data);
658 MONO_HANDLE_ASSIGN (result, ad);
660 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
664 * mono_domain_has_type_resolve:
665 * @domain: application domains being looked up
667 * Returns: TRUE if the AppDomain.TypeResolve field has been
671 mono_domain_has_type_resolve (MonoDomain *domain)
673 static MonoClassField *field = NULL;
677 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
681 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
685 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
690 * mono_domain_try_type_resolve:
691 * @domain: application domainwhere the name where the type is going to be resolved
692 * @name: the name of the type to resolve or NULL.
693 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
695 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
696 * the assembly that matches name.
698 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
700 * Returns: A MonoReflectionAssembly or NULL if not found
702 MonoReflectionAssembly *
703 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
706 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
707 mono_error_cleanup (&error);
712 MonoReflectionAssembly *
713 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
715 static MonoMethod *method = NULL;
716 MonoReflectionAssembly *ret;
721 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
723 if (method == NULL) {
724 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
725 if (method == NULL) {
726 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
732 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
736 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
737 return_val_if_nok (error, NULL);
743 * mono_domain_owns_vtable_slot:
745 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
748 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
752 mono_domain_lock (domain);
753 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
754 mono_domain_unlock (domain);
761 * @force: force setting.
763 * Set the current appdomain to @domain. If @force is set, set it even
764 * if it is being unloaded.
768 * FALSE if the domain is unloaded
771 mono_domain_set (MonoDomain *domain, gboolean force)
773 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
776 mono_domain_set_internal (domain);
782 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
786 if (MONO_HANDLE_IS_NULL (name)) {
787 mono_error_set_argument_null (error, "name", "");
791 g_assert (!MONO_HANDLE_IS_NULL (ad));
792 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
795 char *str = mono_string_handle_to_utf8 (name, error);
796 return_val_if_nok (error, NULL_HANDLE);
798 mono_domain_lock (add);
800 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
802 if (!strcmp (str, "APPBASE"))
803 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
804 else if (!strcmp (str, "APP_CONFIG_FILE"))
805 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
806 else if (!strcmp (str, "DYNAMIC_BASE"))
807 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
808 else if (!strcmp (str, "APP_NAME"))
809 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
810 else if (!strcmp (str, "CACHE_BASE"))
811 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
812 else if (!strcmp (str, "PRIVATE_BINPATH"))
813 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
814 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
815 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
816 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
817 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
818 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
819 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
821 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
823 mono_domain_unlock (add);
826 return MONO_HANDLE_CAST (MonoObject, o);
830 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
834 if (MONO_HANDLE_IS_NULL (name)) {
835 mono_error_set_argument_null (error, "name", "");
839 g_assert (!MONO_HANDLE_IS_NULL (ad));
840 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
843 mono_domain_lock (add);
845 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
847 mono_domain_unlock (add);
850 MonoAppDomainSetupHandle
851 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
854 g_assert (!MONO_HANDLE_IS_NULL (ad));
855 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
858 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
862 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
865 g_assert (!MONO_HANDLE_IS_NULL (ad));
866 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
869 return mono_string_new_handle (domain, domain->friendly_name, error);
873 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
876 MonoDomain *add = mono_domain_get ();
878 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
882 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
885 MonoDomain *root = mono_get_root_domain ();
887 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
891 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
893 MonoDomain *domain = mono_domain_get ();
895 return domain->throw_unobserved_task_exceptions;
899 get_attribute_value (const gchar **attribute_names,
900 const gchar **attribute_values,
901 const char *att_name)
904 for (n = 0; attribute_names [n] != NULL; n++) {
905 if (strcmp (attribute_names [n], att_name) == 0)
906 return g_strdup (attribute_values [n]);
912 start_element (GMarkupParseContext *context,
913 const gchar *element_name,
914 const gchar **attribute_names,
915 const gchar **attribute_values,
919 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
921 if (strcmp (element_name, "runtime") == 0) {
922 runtime_config->runtime_count++;
926 if (strcmp (element_name, "assemblyBinding") == 0) {
927 runtime_config->assemblybinding_count++;
931 if (runtime_config->runtime_count != 1)
934 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
935 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
937 if (value && g_ascii_strcasecmp (value, "true") == 0)
938 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
941 if (runtime_config->assemblybinding_count != 1)
944 if (strcmp (element_name, "probing") != 0)
947 g_free (runtime_config->domain->private_bin_path);
948 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
949 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
950 g_free (runtime_config->domain->private_bin_path);
951 runtime_config->domain->private_bin_path = NULL;
957 end_element (GMarkupParseContext *context,
958 const gchar *element_name,
962 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
963 if (strcmp (element_name, "runtime") == 0)
964 runtime_config->runtime_count--;
965 else if (strcmp (element_name, "assemblyBinding") == 0)
966 runtime_config->assemblybinding_count--;
970 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
972 RuntimeConfig *state = (RuntimeConfig *)user_data;
974 const gchar *filename;
976 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
977 msg = error && error->message ? error->message : "";
978 g_warning ("Error parsing %s: %s", filename, msg);
981 static const GMarkupParser
991 mono_domain_set_options_from_config (MonoDomain *domain)
994 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
996 GMarkupParseContext *context;
997 RuntimeConfig runtime_config;
1000 if (!domain || !domain->setup || !domain->setup->configuration_file)
1003 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1004 if (!mono_error_ok (&error)) {
1005 mono_error_cleanup (&error);
1009 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1010 if (!config_file_path)
1011 config_file_path = config_file_name;
1013 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1016 runtime_config.runtime_count = 0;
1017 runtime_config.assemblybinding_count = 0;
1018 runtime_config.domain = domain;
1019 runtime_config.filename = config_file_path;
1022 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1023 offset = 3; /* Skip UTF-8 BOM */
1025 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1026 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1027 g_markup_parse_context_end_parse (context, NULL);
1028 g_markup_parse_context_free (context);
1032 if (config_file_name != config_file_path)
1033 g_free (config_file_name);
1034 g_free (config_file_path);
1038 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1041 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1043 #ifdef DISABLE_APPDOMAINS
1044 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1048 fname = mono_string_handle_to_utf8 (friendly_name, error);
1049 return_val_if_nok (error, ad);
1050 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1057 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1059 HANDLE_FUNCTION_ENTER ();
1061 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1064 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1066 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1070 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1073 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1077 GPtrArray *assemblies;
1080 * Make a copy of the list of assemblies because we can't hold the assemblies
1081 * lock while creating objects etc.
1083 assemblies = g_ptr_array_new ();
1084 /* Need to skip internal assembly builders created by remoting */
1085 mono_domain_assemblies_lock (domain);
1086 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1087 ass = (MonoAssembly *)tmp->data;
1088 if (refonly != ass->ref_only)
1090 if (ass->corlib_internal)
1092 g_ptr_array_add (assemblies, ass);
1094 mono_domain_assemblies_unlock (domain);
1096 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1099 for (i = 0; i < assemblies->len; ++i) {
1100 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1105 g_ptr_array_free (assemblies, TRUE);
1110 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1112 HANDLE_FUNCTION_ENTER ();
1114 MonoAssembly *result = NULL;
1115 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1118 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1120 HANDLE_FUNCTION_RETURN_VAL (result);
1124 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1126 MonoAssembly *ret = NULL;
1128 MonoBoolean isrefonly;
1129 gpointer params [3];
1133 if (mono_runtime_get_no_exec ())
1136 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1138 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1139 g_assert (method != NULL);
1141 isrefonly = refonly ? 1 : 0;
1142 MonoReflectionAssemblyHandle requesting_handle;
1144 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1145 return_val_if_nok (error, ret);
1147 params [0] = MONO_HANDLE_RAW (fname);
1148 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1149 params [2] = &isrefonly;
1150 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1151 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1156 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1160 MonoAssembly *assembly;
1161 MonoDomain *domain = mono_domain_get ();
1164 aname_str = mono_stringify_assembly_name (aname);
1166 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1168 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1170 mono_error_cleanup (&error);
1176 * LOCKING: assumes assemblies_lock in the domain is already locked.
1179 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1183 gboolean destroy_ht = FALSE;
1185 if (!ass->aname.name)
1189 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1193 /* FIXME: handle lazy loaded assemblies */
1194 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1195 g_hash_table_insert (ht, tmp->data, tmp->data);
1197 if (!g_hash_table_lookup (ht, ass)) {
1198 mono_assembly_addref (ass);
1199 g_hash_table_insert (ht, ass, ass);
1200 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1201 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1204 if (ass->image->references) {
1205 for (i = 0; ass->image->references [i] != NULL; i++) {
1206 if (ass->image->references [i] != REFERENCE_MISSING)
1207 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1208 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1213 g_hash_table_destroy (ht);
1217 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1219 static MonoClassField *assembly_load_field;
1220 static MonoMethod *assembly_load_method;
1222 MonoDomain *domain = mono_domain_get ();
1224 gpointer load_value;
1227 if (!domain->domain)
1228 /* This can happen during startup */
1230 #ifdef ASSEMBLY_LOAD_DEBUG
1231 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1233 klass = domain->domain->mbr.obj.vtable->klass;
1235 mono_domain_assemblies_lock (domain);
1236 add_assemblies_to_domain (domain, assembly, NULL);
1237 mono_domain_assemblies_unlock (domain);
1239 if (assembly_load_field == NULL) {
1240 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1241 g_assert (assembly_load_field);
1244 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1245 if (load_value == NULL) {
1246 /* No events waiting to be triggered */
1250 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1251 mono_error_assert_ok (&error);
1253 if (assembly_load_method == NULL) {
1254 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1255 g_assert (assembly_load_method);
1258 *params = MONO_HANDLE_RAW(ref_assembly);
1260 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1261 mono_error_cleanup (&error);
1265 * LOCKING: Acquires the domain assemblies lock.
1268 set_domain_search_path (MonoDomain *domain)
1271 MonoAppDomainSetup *setup;
1273 gchar *search_path = NULL;
1276 gchar **pvt_split = NULL;
1277 GError *gerror = NULL;
1278 gint appbaselen = -1;
1281 * We use the low-level domain assemblies lock, since this is called from
1282 * assembly loads hooks, which means this thread might hold the loader lock.
1284 mono_domain_assemblies_lock (domain);
1286 if (!domain->setup) {
1287 mono_domain_assemblies_unlock (domain);
1291 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1292 mono_domain_assemblies_unlock (domain);
1295 setup = domain->setup;
1296 if (!setup->application_base) {
1297 mono_domain_assemblies_unlock (domain);
1298 return; /* Must set application base to get private path working */
1303 if (setup->private_bin_path) {
1304 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1305 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1306 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1307 mono_error_cleanup (&error);
1308 mono_domain_assemblies_unlock (domain);
1313 if (domain->private_bin_path) {
1314 if (search_path == NULL)
1315 search_path = domain->private_bin_path;
1317 gchar *tmp2 = search_path;
1318 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1325 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1326 * directories relative to ApplicationBase separated by semicolons (see
1327 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1328 * The loop below copes with the fact that some Unix applications may use ':' (or
1329 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1330 * ';' for the subsequent split.
1332 * The issue was reported in bug #81446
1335 #ifndef TARGET_WIN32
1338 slen = strlen (search_path);
1339 for (i = 0; i < slen; i++)
1340 if (search_path [i] == ':')
1341 search_path [i] = ';';
1344 pvt_split = g_strsplit (search_path, ";", 1000);
1345 g_free (search_path);
1346 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1351 g_strfreev (pvt_split);
1353 * Don't do this because the first time is called, the domain
1354 * setup is not finished.
1356 * domain->search_path = g_malloc (sizeof (char *));
1357 * domain->search_path [0] = NULL;
1359 mono_domain_assemblies_unlock (domain);
1363 if (domain->search_path)
1364 g_strfreev (domain->search_path);
1366 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1367 tmp [npaths] = NULL;
1369 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1370 if (!mono_error_ok (&error)) {
1371 mono_error_cleanup (&error);
1372 g_strfreev (pvt_split);
1375 mono_domain_assemblies_unlock (domain);
1379 domain->search_path = tmp;
1381 /* FIXME: is this needed? */
1382 if (strncmp (*tmp, "file://", 7) == 0) {
1388 uri = g_strdup_printf ("file:///%s", uri + 7);
1391 uri = mono_escape_uri_string (tmpuri);
1392 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1398 if (gerror != NULL) {
1399 g_warning ("%s\n", gerror->message);
1400 g_error_free (gerror);
1407 for (i = 1; pvt_split && i < npaths; i++) {
1408 if (g_path_is_absolute (pvt_split [i - 1])) {
1409 tmp [i] = g_strdup (pvt_split [i - 1]);
1411 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1414 if (strchr (tmp [i], '.')) {
1418 reduced = mono_path_canonicalize (tmp [i]);
1419 if (appbaselen == -1)
1420 appbaselen = strlen (tmp [0]);
1422 if (strncmp (tmp [0], reduced, appbaselen)) {
1425 tmp [i] = g_strdup ("");
1435 if (setup->private_bin_path_probe != NULL) {
1437 tmp [0] = g_strdup ("");
1440 domain->setup->path_changed = FALSE;
1442 g_strfreev (pvt_split);
1444 mono_domain_assemblies_unlock (domain);
1447 #ifdef DISABLE_SHADOW_COPY
1449 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1455 mono_make_shadow_copy (const char *filename, MonoError *error)
1458 return (char *) filename;
1462 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1464 guint16 *orig, *dest;
1465 gboolean copy_result;
1468 strcpy (src + srclen - tail_len, extension);
1470 if (IS_PORTABILITY_CASE) {
1471 gchar *file = mono_portability_find_file (src, TRUE);
1477 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1481 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1483 strcpy (target + targetlen - tail_len, extension);
1484 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1486 mono_w32file_delete (dest);
1488 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1490 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1491 * overwritten when updated in their original locations. */
1493 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1502 get_cstring_hash (const char *str)
1508 if (!str || !str [0])
1513 for (i = 0; i < len; i++) {
1514 h = (h << 5) - h + *p;
1522 * Returned memory is malloc'd. Called must free it
1525 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1527 MonoAppDomainSetup *setup;
1528 char *cache_path, *appname;
1534 setup = domain->setup;
1535 if (setup->cache_path != NULL && setup->application_name != NULL) {
1536 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1537 return_val_if_nok (error, NULL);
1539 #ifndef TARGET_WIN32
1542 for (i = strlen (cache_path) - 1; i >= 0; i--)
1543 if (cache_path [i] == '\\')
1544 cache_path [i] = '/';
1548 appname = mono_string_to_utf8_checked (setup->application_name, error);
1549 if (!mono_error_ok (error)) {
1550 g_free (cache_path);
1554 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1556 g_free (cache_path);
1558 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1559 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1566 get_shadow_assembly_location (const char *filename, MonoError *error)
1568 gint32 hash = 0, hash2 = 0;
1570 char path_hash [30];
1571 char *bname = g_path_get_basename (filename);
1572 char *dirname = g_path_get_dirname (filename);
1573 char *location, *tmploc;
1574 MonoDomain *domain = mono_domain_get ();
1578 hash = get_cstring_hash (bname);
1579 hash2 = get_cstring_hash (dirname);
1580 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1581 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1582 tmploc = get_shadow_assembly_location_base (domain, error);
1583 if (!mono_error_ok (error)) {
1589 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1597 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1599 struct stat sbuf_dest;
1601 gchar *real_src = mono_portability_find_file (src, TRUE);
1604 stat_src = (gchar*)src;
1606 stat_src = real_src;
1608 if (stat (stat_src, sbuf_src) == -1) {
1609 time_t tnow = time (NULL);
1614 memset (sbuf_src, 0, sizeof (*sbuf_src));
1615 sbuf_src->st_mtime = tnow;
1616 sbuf_src->st_atime = tnow;
1623 if (stat (dest, &sbuf_dest) == -1)
1626 if (sbuf_src->st_size == sbuf_dest.st_size &&
1627 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1634 shadow_copy_create_ini (const char *shadow, const char *filename)
1644 dir_name = g_path_get_dirname (shadow);
1645 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1647 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1652 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1657 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1659 if (handle == INVALID_HANDLE_VALUE) {
1663 full_path = mono_path_resolve_symlinks (filename);
1664 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1666 mono_w32file_close (handle);
1671 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1674 MonoAppDomainSetup *setup;
1677 gchar **directories;
1678 gchar *shadow_status_string;
1680 gboolean shadow_enabled;
1681 gboolean found = FALSE;
1686 setup = domain->setup;
1687 if (setup == NULL || setup->shadow_copy_files == NULL)
1690 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1691 if (!mono_error_ok (&error)) {
1692 mono_error_cleanup (&error);
1695 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1696 g_free (shadow_status_string);
1698 if (!shadow_enabled)
1701 if (setup->shadow_copy_directories == NULL)
1704 /* Is dir_name a shadow_copy destination already? */
1705 base_dir = get_shadow_assembly_location_base (domain, &error);
1706 if (!mono_error_ok (&error)) {
1707 mono_error_cleanup (&error);
1711 if (strstr (dir_name, base_dir)) {
1717 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1718 if (!mono_error_ok (&error)) {
1719 mono_error_cleanup (&error);
1723 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1724 dir_ptr = directories;
1726 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1732 g_strfreev (directories);
1738 This function raises exceptions so it can cause as sorts of nasty stuff if called
1739 while holding a lock.
1740 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1741 or NULL if source file not found.
1742 FIXME bubble up the error instead of raising it here
1745 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1748 gchar *sibling_source, *sibling_target;
1749 gint sibling_source_len, sibling_target_len;
1750 guint16 *orig, *dest;
1753 gboolean copy_result;
1754 struct stat src_sbuf;
1755 struct utimbuf utbuf;
1756 char *dir_name = g_path_get_dirname (filename);
1757 MonoDomain *domain = mono_domain_get ();
1761 error_init (oerror);
1763 set_domain_search_path (domain);
1765 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1767 return (char *) filename;
1770 /* Is dir_name a shadow_copy destination already? */
1771 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1772 if (!mono_error_ok (&error)) {
1773 mono_error_cleanup (&error);
1775 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1779 if (strstr (dir_name, shadow_dir)) {
1780 g_free (shadow_dir);
1782 return (char *) filename;
1784 g_free (shadow_dir);
1787 shadow = get_shadow_assembly_location (filename, &error);
1788 if (!mono_error_ok (&error)) {
1789 mono_error_cleanup (&error);
1790 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1794 if (g_ensure_directory_exists (shadow) == FALSE) {
1796 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1800 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1801 return (char*) shadow;
1803 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1804 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1805 mono_w32file_delete (dest);
1807 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1808 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1809 * and not have it runtime error" */
1810 attrs = mono_w32file_get_attributes (orig);
1811 if (attrs == INVALID_FILE_ATTRIBUTES) {
1813 return (char *)filename;
1816 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1818 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1819 * overwritten when updated in their original locations. */
1821 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1826 if (copy_result == FALSE) {
1829 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1830 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1831 return NULL; /* file not found, shadow copy failed */
1833 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1837 /* attempt to copy .mdb, .config if they exist */
1838 sibling_source = g_strconcat (filename, ".config", NULL);
1839 sibling_source_len = strlen (sibling_source);
1840 sibling_target = g_strconcat (shadow, ".config", NULL);
1841 sibling_target_len = strlen (sibling_target);
1843 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1845 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1847 g_free (sibling_source);
1848 g_free (sibling_target);
1852 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1856 /* Create a .ini file containing the original assembly location */
1857 if (!shadow_copy_create_ini (shadow, filename)) {
1859 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1863 utbuf.actime = src_sbuf.st_atime;
1864 utbuf.modtime = src_sbuf.st_mtime;
1865 utime (shadow, &utbuf);
1869 #endif /* DISABLE_SHADOW_COPY */
1872 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1874 HANDLE_FUNCTION_ENTER ();
1875 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1876 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1877 HANDLE_FUNCTION_RETURN_VAL (result);
1881 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1883 HANDLE_FUNCTION_ENTER ();
1884 MonoDomain *dom = NULL;
1885 if (MONO_HANDLE_IS_NULL (appdomain))
1888 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1889 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1890 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1892 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1894 dom = MONO_HANDLE_GETVAL (appdomain, data);
1897 HANDLE_FUNCTION_RETURN_VAL (dom);
1902 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1903 const gchar *path3, const gchar *path4,
1904 gboolean refonly, gboolean is_private)
1907 gboolean found = FALSE;
1910 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1912 if (IS_PORTABILITY_SET) {
1913 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1916 fullpath = new_fullpath;
1920 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1923 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1926 return (*assembly != NULL);
1929 static MonoAssembly *
1930 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1932 MonoAssembly *result = NULL;
1935 const gchar *local_culture;
1937 gboolean is_private = FALSE;
1939 if (!culture || *culture == '\0') {
1942 local_culture = culture;
1945 filename = g_strconcat (name, ".dll", NULL);
1946 len = strlen (filename);
1948 for (path = search_path; *path; path++) {
1949 if (**path == '\0') {
1951 continue; /* Ignore empty ApplicationBase */
1954 /* See test cases in bug #58992 and bug #57710 */
1955 /* 1st try: [culture]/[name].dll (culture may be empty) */
1956 strcpy (filename + len - 4, ".dll");
1957 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1960 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1961 strcpy (filename + len - 4, ".exe");
1962 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1965 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1966 strcpy (filename + len - 4, ".dll");
1967 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1970 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1971 strcpy (filename + len - 4, ".exe");
1972 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1981 * Try loading the assembly from ApplicationBase and PrivateBinPath
1982 * and then from assemblies_path if any.
1983 * LOCKING: This is called from the assembly loading code, which means the caller
1984 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1986 static MonoAssembly *
1987 mono_domain_assembly_preload (MonoAssemblyName *aname,
1988 gchar **assemblies_path,
1991 MonoDomain *domain = mono_domain_get ();
1992 MonoAssembly *result = NULL;
1993 gboolean refonly = GPOINTER_TO_UINT (user_data);
1995 set_domain_search_path (domain);
1997 if (domain->search_path && domain->search_path [0] != NULL) {
1998 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
2001 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2002 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
2009 * Check whenever a given assembly was already loaded in the current appdomain.
2011 static MonoAssembly *
2012 mono_domain_assembly_search (MonoAssemblyName *aname,
2015 MonoDomain *domain = mono_domain_get ();
2018 gboolean refonly = GPOINTER_TO_UINT (user_data);
2020 mono_domain_assemblies_lock (domain);
2021 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2022 ass = (MonoAssembly *)tmp->data;
2023 /* Dynamic assemblies can't match here in MS.NET */
2024 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2027 mono_domain_assemblies_unlock (domain);
2030 mono_domain_assemblies_unlock (domain);
2035 MonoReflectionAssemblyHandle
2036 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2039 MonoDomain *domain = mono_domain_get ();
2040 char *name, *filename;
2041 MonoImageOpenStatus status = MONO_IMAGE_OK;
2042 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2047 if (fname == NULL) {
2048 mono_error_set_argument_null (error, "assemblyFile", "");
2052 name = filename = mono_string_handle_to_utf8 (fname, error);
2056 MonoAssembly *ass = mono_assembly_open_full (filename, &status, refOnly);
2059 if (status == MONO_IMAGE_IMAGE_INVALID)
2060 mono_error_set_bad_image_name (error, g_strdup (name), "");
2062 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2066 result = mono_assembly_get_object_handle (domain, ass, error);
2073 MonoReflectionAssemblyHandle
2074 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2075 MonoArrayHandle raw_assembly,
2076 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2077 MonoBoolean refonly,
2082 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2083 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2084 MonoImageOpenStatus status;
2085 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2087 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2088 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2089 if (!assembly_data) {
2090 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2094 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2095 memcpy (assembly_data, raw_data, raw_assembly_len);
2096 mono_gchandle_free (gchandle); /* unpin */
2097 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2099 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2102 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2106 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2107 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2108 uint32_t symbol_gchandle;
2109 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2110 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2111 mono_gchandle_free (symbol_gchandle);
2114 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2118 mono_image_close (image);
2119 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2123 refass = mono_assembly_get_object_handle (domain, ass, error);
2124 if (!MONO_HANDLE_IS_NULL(refass))
2125 MONO_HANDLE_SET (refass, evidence, evidence);
2129 MonoReflectionAssemblyHandle
2130 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2133 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2134 MonoImageOpenStatus status = MONO_IMAGE_OK;
2136 MonoAssemblyName aname;
2142 name = mono_string_handle_to_utf8 (assRef, error);
2145 parsed = mono_assembly_name_parse (name, &aname);
2149 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2150 /* This is a parse error... */
2152 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2156 refass = mono_assembly_get_object_handle (domain, assm, error);
2164 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2165 mono_assembly_name_free (&aname);
2168 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2170 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2179 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2183 MONO_HANDLE_SET (refass, evidence, evidence);
2187 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2191 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2194 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2196 if (NULL == domain) {
2197 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2201 if (domain == mono_get_root_domain ()) {
2202 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2207 * Unloading seems to cause problems when running NUnit/NAnt, hence
2210 if (g_getenv ("MONO_NO_UNLOAD"))
2212 #ifdef __native_client__
2216 MonoException *exc = NULL;
2217 mono_domain_try_unload (domain, (MonoObject**)&exc);
2219 mono_error_set_exception_instance (error, exc);
2223 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2226 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2231 return mono_domain_is_unloading (domain);
2235 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2237 mono_unhandled_exception ((MonoObject*) exc);
2241 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2242 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2249 g_assert (!MONO_HANDLE_IS_NULL (refass));
2250 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2251 image = assembly->image;
2254 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2257 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2259 if (MONO_HANDLE_IS_NULL (args)) {
2260 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2261 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2262 mono_error_assert_ok (error);
2265 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2270 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2272 return ad->data->domain_id;
2276 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2279 MonoDomain *old_domain = mono_domain_get ();
2281 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2282 mono_error_set_appdomain_unloaded (error);
2283 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2286 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2290 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2292 MonoDomain *current_domain = mono_domain_get ();
2293 MonoDomain *domain = mono_domain_get_by_id (domainid);
2295 if (!domain || !mono_domain_set (domain, FALSE)) {
2296 mono_error_set_appdomain_unloaded (error);
2297 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2300 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2304 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2307 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2311 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2314 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2318 * Raise an exception to prevent the managed code from executing a pop
2321 mono_error_set_appdomain_unloaded (error);
2325 mono_thread_push_appdomain_ref (domain);
2329 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2332 mono_thread_pop_appdomain_ref ();
2336 ves_icall_System_AppDomain_InternalGetContext ()
2338 return mono_context_get ();
2342 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2344 return mono_domain_get ()->default_context;
2348 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2350 MonoAppContext *old_context = mono_context_get ();
2352 mono_context_set (mc);
2358 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2361 MonoDomain* mono_root_domain = mono_get_root_domain ();
2362 mono_domain_lock (mono_root_domain);
2363 if (process_guid_set) {
2364 mono_domain_unlock (mono_root_domain);
2365 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2367 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2368 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2369 mono_gchandle_free (gchandle);
2370 process_guid_set = TRUE;
2371 mono_domain_unlock (mono_root_domain);
2376 mono_domain_is_unloading (MonoDomain *domain)
2378 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2385 clear_cached_vtable (MonoVTable *vtable)
2387 MonoClass *klass = vtable->klass;
2388 MonoDomain *domain = vtable->domain;
2389 MonoClassRuntimeInfo *runtime_info;
2392 runtime_info = klass->runtime_info;
2393 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2394 runtime_info->domain_vtables [domain->domain_id] = NULL;
2395 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2396 mono_gc_free_fixed (data);
2399 static G_GNUC_UNUSED void
2400 zero_static_data (MonoVTable *vtable)
2402 MonoClass *klass = vtable->klass;
2405 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2406 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2409 typedef struct unload_data {
2412 char *failure_reason;
2417 unload_data_unref (unload_data *data)
2421 mono_atomic_load_acquire (count, gint32, &data->refcount);
2422 g_assert (count >= 1 && count <= 2);
2427 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2431 deregister_reflection_info_roots_from_list (MonoImage *image)
2433 GSList *list = image->reflection_info_unregister_classes;
2436 MonoClass *klass = (MonoClass *)list->data;
2438 mono_class_free_ref_info (klass);
2443 image->reflection_info_unregister_classes = NULL;
2447 deregister_reflection_info_roots (MonoDomain *domain)
2451 mono_domain_assemblies_lock (domain);
2452 for (list = domain->domain_assemblies; list; list = list->next) {
2453 MonoAssembly *assembly = (MonoAssembly *)list->data;
2454 MonoImage *image = assembly->image;
2458 * No need to take the image lock here since dynamic images are appdomain bound and
2459 * at this point the mutator is gone. Taking the image lock here would mean
2460 * promoting it from a simple lock to a complex lock, which we better avoid if
2463 if (image_is_dynamic (image))
2464 deregister_reflection_info_roots_from_list (image);
2466 for (i = 0; i < image->module_count; ++i) {
2467 MonoImage *module = image->modules [i];
2468 if (module && image_is_dynamic (module))
2469 deregister_reflection_info_roots_from_list (module);
2472 mono_domain_assemblies_unlock (domain);
2476 unload_thread_main (void *arg)
2479 unload_data *data = (unload_data*)arg;
2480 MonoDomain *domain = data->domain;
2484 /* Have to attach to the runtime so shutdown can wait for this thread */
2485 /* Force it to be attached to avoid racing during shutdown. */
2486 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2488 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, FALSE, &error);
2489 if (!is_ok (&error)) {
2490 data->failure_reason = g_strdup (mono_error_get_message (&error));
2491 mono_error_cleanup (&error);
2496 * FIXME: Abort our parent thread last, so we can return a failure
2497 * indication if aborting times out.
2499 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2500 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2504 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2505 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2509 /* Finalize all finalizable objects in the doomed appdomain */
2510 if (!mono_domain_finalize (domain, -1)) {
2511 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2515 /* Clear references to our vtables in class->runtime_info.
2516 * We also hold the loader lock because we're going to change
2517 * class->runtime_info.
2520 mono_loader_lock (); //FIXME why do we need the loader lock here?
2521 mono_domain_lock (domain);
2524 * We need to make sure that we don't have any remsets
2525 * pointing into static data of the to-be-freed domain because
2526 * at the next collections they would be invalid. So what we
2527 * do is we first zero all static data and then do a minor
2528 * collection. Because all references in the static data will
2529 * now be null we won't do any unnecessary copies and after
2530 * the collection there won't be any more remsets.
2532 for (i = 0; i < domain->class_vtable_array->len; ++i)
2533 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2534 mono_gc_collect (0);
2536 for (i = 0; i < domain->class_vtable_array->len; ++i)
2537 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2538 deregister_reflection_info_roots (domain);
2540 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2542 mono_domain_unlock (domain);
2543 mono_loader_unlock ();
2545 mono_threads_clear_cached_culture (domain);
2547 domain->state = MONO_APPDOMAIN_UNLOADED;
2549 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2551 /* remove from the handle table the items related to this domain */
2552 mono_gchandle_free_domain (domain);
2554 mono_domain_free (domain, FALSE);
2556 mono_gc_collect (mono_gc_max_generation ());
2558 mono_atomic_store_release (&data->done, TRUE);
2559 unload_data_unref (data);
2560 mono_thread_detach (thread);
2564 mono_atomic_store_release (&data->done, TRUE);
2565 unload_data_unref (data);
2566 mono_thread_detach (thread);
2571 * mono_domain_unload:
2572 * @domain: The domain to unload
2574 * Unloads an appdomain. Follows the process outlined in the comment
2575 * for mono_domain_try_unload.
2578 mono_domain_unload (MonoDomain *domain)
2580 MonoObject *exc = NULL;
2581 mono_domain_try_unload (domain, &exc);
2584 static MonoThreadInfoWaitRet
2585 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2587 MonoThreadInfoWaitRet result;
2590 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2597 * mono_domain_unload:
2598 * @domain: The domain to unload
2599 * @exc: Exception information
2601 * Unloads an appdomain. Follows the process outlined in:
2602 * http://blogs.gotdotnet.com/cbrumme
2604 * If doing things the 'right' way is too hard or complex, we do it the
2605 * 'simple' way, which means do everything needed to avoid crashes and
2606 * memory leaks, but not much else.
2608 * It is required to pass a valid reference to the exc argument, upon return
2609 * from this function *exc will be set to the exception thrown, if any.
2611 * If this method is not called from an icall (embedded scenario for instance),
2612 * it must not be called with any managed frames on the stack, since the unload
2613 * process could end up trying to abort the current thread.
2616 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2619 MonoThreadHandle *thread_handle;
2620 MonoAppDomainState prev_state;
2622 unload_data *thread_data;
2623 MonoNativeThreadId tid;
2624 MonoDomain *caller_domain = mono_domain_get ();
2626 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2628 /* Atomically change our state to UNLOADING */
2629 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2630 MONO_APPDOMAIN_UNLOADING_START,
2631 MONO_APPDOMAIN_CREATED);
2632 if (prev_state != MONO_APPDOMAIN_CREATED) {
2633 switch (prev_state) {
2634 case MONO_APPDOMAIN_UNLOADING_START:
2635 case MONO_APPDOMAIN_UNLOADING:
2636 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2638 case MONO_APPDOMAIN_UNLOADED:
2639 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2642 g_warning ("Invalid appdomain state %d", prev_state);
2643 g_assert_not_reached ();
2647 mono_domain_set (domain, FALSE);
2648 /* Notify OnDomainUnload listeners */
2649 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2652 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2654 if (!mono_error_ok (&error)) {
2656 mono_error_cleanup (&error);
2658 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2662 /* Roll back the state change */
2663 domain->state = MONO_APPDOMAIN_CREATED;
2664 mono_domain_set (caller_domain, FALSE);
2667 mono_domain_set (caller_domain, FALSE);
2669 thread_data = g_new0 (unload_data, 1);
2670 thread_data->domain = domain;
2671 thread_data->failure_reason = NULL;
2672 thread_data->done = FALSE;
2673 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2675 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2676 domain->state = MONO_APPDOMAIN_UNLOADING;
2678 * First we create a separate thread for unloading, since
2679 * we might have to abort some threads, including the current one.
2681 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, NULL, &tid);
2682 if (thread_handle == NULL)
2685 /* Wait for the thread */
2686 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2687 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2688 /* The unload thread tries to abort us */
2689 /* The icall wrapper will execute the abort */
2690 mono_threads_close_thread_handle (thread_handle);
2691 unload_data_unref (thread_data);
2696 mono_threads_close_thread_handle (thread_handle);
2698 if (thread_data->failure_reason) {
2699 /* Roll back the state change */
2700 domain->state = MONO_APPDOMAIN_CREATED;
2702 g_warning ("%s", thread_data->failure_reason);
2704 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2706 g_free (thread_data->failure_reason);
2707 thread_data->failure_reason = NULL;
2710 unload_data_unref (thread_data);