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>
80 * This is the version number of the corlib-runtime interface. When
81 * making changes to this interface (by changing the layout
82 * of classes the runtime knows about, changing icall signature or
83 * semantics etc), increment this variable. Also increment the
84 * pair of this variable in mscorlib in:
85 * mcs/class/corlib/System/Environment.cs
87 * Changes which are already detected at runtime, like the addition
88 * of icalls, do not require an increment.
90 #define MONO_CORLIB_VERSION 164
95 int assemblybinding_count;
100 static gunichar2 process_guid [36];
101 static gboolean process_guid_set = FALSE;
103 static gboolean no_exec = FALSE;
105 static MonoAssembly *
106 mono_domain_assembly_preload (MonoAssemblyName *aname,
107 gchar **assemblies_path,
110 static MonoAssembly *
111 mono_domain_assembly_search (MonoAssemblyName *aname,
115 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
118 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
120 static MonoAppDomainHandle
121 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
124 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
128 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
130 static MonoLoadFunc load_function = NULL;
132 /* Lazy class loading functions */
133 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
135 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
138 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
141 mono_error_set_appdomain_unloaded (MonoError *error)
143 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
147 mono_install_runtime_load (MonoLoadFunc func)
149 load_function = func;
153 mono_runtime_load (const char *filename, const char *runtime_version)
155 g_assert (load_function);
156 return load_function (filename, runtime_version);
160 * mono_runtime_set_no_exec:
162 * Instructs the runtime to operate in static mode, i.e. avoid/do not
163 * allow managed code execution. This is useful for running the AOT
164 * compiler on platforms which allow full-aot execution only. This
165 * should be called before mono_runtime_init ().
168 mono_runtime_set_no_exec (gboolean val)
174 * mono_runtime_get_no_exec:
176 * If true, then the runtime will not allow managed code execution.
179 mono_runtime_get_no_exec (void)
185 create_domain_objects (MonoDomain *domain)
188 MonoDomain *old_domain = mono_domain_get ();
190 MonoVTable *string_vt;
191 MonoClassField *string_empty_fld;
193 if (domain != old_domain) {
194 mono_thread_push_appdomain_ref (domain);
195 mono_domain_set_internal_with_options (domain, FALSE);
199 * Initialize String.Empty. This enables the removal of
200 * the static cctor of the String class.
202 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
203 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
204 g_assert (string_empty_fld);
205 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
206 mono_error_assert_ok (&error);
207 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
208 domain->empty_string = empty_str;
211 * Create an instance early since we can't do it when there is no memory.
213 arg = mono_string_new (domain, "Out of memory");
214 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
215 mono_error_assert_ok (&error);
218 * These two are needed because the signal handlers might be executing on
219 * an alternate stack, and Boehm GC can't handle that.
221 arg = mono_string_new (domain, "A null value was found where an object instance was required");
222 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
223 mono_error_assert_ok (&error);
224 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
225 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
226 mono_error_assert_ok (&error);
228 /*The ephemeron tombstone i*/
229 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
230 mono_error_assert_ok (&error);
232 if (domain != old_domain) {
233 mono_thread_pop_appdomain_ref ();
234 mono_domain_set_internal_with_options (old_domain, FALSE);
238 * This class is used during exception handling, so initialize it here, to prevent
239 * stack overflows while handling stack overflows.
241 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
246 * @domain: domain returned by mono_init ()
248 * Initialize the core AppDomain: this function will run also some
249 * IL initialization code, so it needs the execution engine to be fully
252 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
253 * we know the entry_assembly.
257 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
260 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
261 mono_error_cleanup (&error);
265 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
267 MonoAppDomainSetup *setup;
273 mono_portability_helpers_init ();
275 mono_gc_base_init ();
276 mono_monitor_init ();
277 mono_marshal_init ();
279 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
280 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
281 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
282 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
283 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
284 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
285 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
287 mono_thread_init (start_cb, attach_cb);
289 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
290 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
291 return_if_nok (error);
293 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
295 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
296 return_if_nok (error);
300 domain->setup = setup;
302 mono_thread_attach (domain);
304 mono_type_initialization_init ();
306 if (!mono_runtime_get_no_exec ())
307 create_domain_objects (domain);
309 /* GC init has to happen after thread init */
312 /* contexts use GC handles, so they must be initialized after the GC */
313 mono_context_init_checked (domain, error);
314 return_if_nok (error);
315 mono_context_set (domain->default_context);
317 #ifndef DISABLE_SOCKETS
318 mono_network_init ();
321 mono_console_init ();
324 mono_locks_tracer_init ();
326 /* mscorlib is loaded before we install the load hook */
327 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
333 mono_get_corlib_version (void)
337 MonoClassField *field;
340 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
341 mono_class_init (klass);
342 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
345 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
347 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
348 mono_error_assert_ok (&error);
349 return *(gint32*)((gchar*)value + sizeof (MonoObject));
353 * mono_check_corlib_version
355 * Checks that the corlib that is loaded matches the version of this runtime.
357 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
358 * allocated string with the error otherwise.
361 mono_check_corlib_version (void)
363 int version = mono_get_corlib_version ();
364 if (version != MONO_CORLIB_VERSION)
365 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
367 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
368 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
369 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
370 if (native_offset != managed_offset)
371 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
378 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
380 * Initializes the @domain's default System.Runtime.Remoting's Context.
383 mono_context_init (MonoDomain *domain)
386 mono_context_init_checked (domain, &error);
387 mono_error_cleanup (&error);
391 mono_context_init_checked (MonoDomain *domain, MonoError *error)
394 MonoAppContext *context;
398 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
399 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
400 return_if_nok (error);
402 context->domain_id = domain->domain_id;
403 context->context_id = 0;
404 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
405 domain->default_context = context;
409 * mono_runtime_cleanup:
414 * This must not be called while there are still running threads executing
418 mono_runtime_cleanup (MonoDomain *domain)
420 mono_attach_cleanup ();
422 /* This ends up calling any pending pending (for at most 2 seconds) */
425 mono_thread_cleanup ();
427 #ifndef DISABLE_SOCKETS
428 mono_network_cleanup ();
430 mono_marshal_cleanup ();
432 mono_type_initialization_cleanup ();
434 mono_monitor_cleanup ();
437 static MonoDomainFunc quit_function = NULL;
440 mono_install_runtime_cleanup (MonoDomainFunc func)
442 quit_function = func;
448 if (quit_function != NULL)
449 quit_function (mono_get_root_domain (), NULL);
453 * mono_domain_create_appdomain:
454 * @friendly_name: The friendly name of the appdomain to create
455 * @configuration_file: The configuration file to initialize the appdomain with
457 * Returns a MonoDomain initialized with the appdomain
460 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
462 HANDLE_FUNCTION_ENTER ();
464 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
465 mono_error_cleanup (&error);
466 HANDLE_FUNCTION_RETURN_VAL (domain);
470 * mono_domain_create_appdomain_checked:
471 * @friendly_name: The friendly name of the appdomain to create
472 * @configuration_file: The configuration file to initialize the appdomain with
473 * @error: Set on error.
475 * Returns a MonoDomain initialized with the appdomain. On failure sets @error and returns NULL.
478 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
480 HANDLE_FUNCTION_ENTER ();
482 MonoDomain *result = NULL;
484 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
485 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
488 MonoStringHandle config_file;
489 if (configuration_file != NULL) {
490 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
494 config_file = MONO_HANDLE_NEW (MonoString, NULL);
496 MONO_HANDLE_SET (setup, configuration_file, config_file);
498 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
502 result = mono_domain_from_appdomain_handle (ad);
504 HANDLE_FUNCTION_RETURN_VAL (result);
508 * mono_domain_set_config:
509 * @domain: MonoDomain initialized with the appdomain we want to change
510 * @base_dir: new base directory for the appdomain
511 * @config_file_name: path to the new configuration for the app domain
513 * Used to set the system configuration for an appdomain
515 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
516 * Error Initializing the configuration system. ---> System.ArgumentException:
517 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
520 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
522 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
523 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
526 static MonoAppDomainSetupHandle
527 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
529 HANDLE_FUNCTION_ENTER ();
530 MonoDomain *caller_domain;
531 MonoClass *ads_class;
532 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
536 caller_domain = mono_domain_get ();
537 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
539 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
543 mono_domain_set_internal (domain);
545 #define XCOPY_FIELD(dst,field,src,error) \
547 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
548 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
549 if (!is_ok (error)) \
551 MONO_HANDLE_SET ((dst),field,copied_val); \
554 #define COPY_VAL(dst,field,type,src) \
556 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
559 XCOPY_FIELD (copy, application_base, setup, error);
560 XCOPY_FIELD (copy, application_name, setup, error);
561 XCOPY_FIELD (copy, cache_path, setup, error);
562 XCOPY_FIELD (copy, configuration_file, setup, error);
563 XCOPY_FIELD (copy, dynamic_base, setup, error);
564 XCOPY_FIELD (copy, license_file, setup, error);
565 XCOPY_FIELD (copy, private_bin_path, setup, error);
566 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
567 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
568 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
569 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
570 COPY_VAL (copy, path_changed, MonoBoolean, setup);
571 COPY_VAL (copy, loader_optimization, int, setup);
572 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
573 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
574 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
575 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
576 XCOPY_FIELD (copy, application_trust, setup, error);
577 XCOPY_FIELD (copy, configuration_bytes, setup, error);
578 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
583 mono_domain_set_internal (caller_domain);
585 MONO_HANDLE_ASSIGN (result, copy);
587 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
590 static MonoAppDomainHandle
591 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
593 HANDLE_FUNCTION_ENTER ();
594 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
600 adclass = mono_class_get_appdomain_class ();
602 /* FIXME: pin all those objects */
603 data = mono_domain_create();
605 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
608 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
609 data->domain = MONO_HANDLE_RAW (ad);
610 data->friendly_name = g_strdup (friendly_name);
612 mono_profiler_appdomain_name (data, data->friendly_name);
614 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
615 if (MONO_HANDLE_IS_NULL (app_base)) {
616 /* Inherit from the root domain since MS.NET does this */
617 MonoDomain *root = mono_get_root_domain ();
618 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
619 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
620 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
621 /* N.B. new string is in the new domain */
622 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
623 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);
624 mono_gchandle_free (gchandle);
625 if (!is_ok (error)) {
626 g_free (data->friendly_name);
629 MONO_HANDLE_SET (setup, application_base, s);
633 mono_context_init_checked (data, error);
637 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
638 if (!mono_error_ok (error)) {
639 g_free (data->friendly_name);
643 mono_domain_set_options_from_config (data);
644 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
646 #ifndef DISABLE_SHADOW_COPY
647 /*FIXME, guard this for when the debugger is not running */
648 char *shadow_location = get_shadow_assembly_location_base (data, error);
649 if (!mono_error_ok (error)) {
650 g_free (data->friendly_name);
654 g_free (shadow_location);
657 create_domain_objects (data);
659 MONO_HANDLE_ASSIGN (result, ad);
661 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
665 * mono_domain_has_type_resolve:
666 * @domain: application domains being looked up
668 * Returns: TRUE if the AppDomain.TypeResolve field has been
672 mono_domain_has_type_resolve (MonoDomain *domain)
674 static MonoClassField *field = NULL;
678 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
682 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
686 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
691 * mono_domain_try_type_resolve:
692 * @domain: application domainwhere the name where the type is going to be resolved
693 * @name: the name of the type to resolve or NULL.
694 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
696 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
697 * the assembly that matches name.
699 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
701 * Returns: A MonoReflectionAssembly or NULL if not found
703 MonoReflectionAssembly *
704 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
707 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
708 mono_error_cleanup (&error);
713 MonoReflectionAssembly *
714 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
716 static MonoMethod *method = NULL;
717 MonoReflectionAssembly *ret;
722 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
724 if (method == NULL) {
725 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
726 if (method == NULL) {
727 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
733 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
737 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
738 return_val_if_nok (error, NULL);
744 * mono_domain_owns_vtable_slot:
746 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
749 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
753 mono_domain_lock (domain);
754 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
755 mono_domain_unlock (domain);
762 * @force: force setting.
764 * Set the current appdomain to @domain. If @force is set, set it even
765 * if it is being unloaded.
769 * FALSE if the domain is unloaded
772 mono_domain_set (MonoDomain *domain, gboolean force)
774 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
777 mono_domain_set_internal (domain);
783 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
787 if (MONO_HANDLE_IS_NULL (name)) {
788 mono_error_set_argument_null (error, "name", "");
792 g_assert (!MONO_HANDLE_IS_NULL (ad));
793 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
796 char *str = mono_string_handle_to_utf8 (name, error);
797 return_val_if_nok (error, NULL_HANDLE);
799 mono_domain_lock (add);
801 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
803 if (!strcmp (str, "APPBASE"))
804 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
805 else if (!strcmp (str, "APP_CONFIG_FILE"))
806 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
807 else if (!strcmp (str, "DYNAMIC_BASE"))
808 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
809 else if (!strcmp (str, "APP_NAME"))
810 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
811 else if (!strcmp (str, "CACHE_BASE"))
812 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
813 else if (!strcmp (str, "PRIVATE_BINPATH"))
814 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
815 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
816 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
817 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
818 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
819 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
820 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
822 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
824 mono_domain_unlock (add);
827 return MONO_HANDLE_CAST (MonoObject, o);
831 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
835 if (MONO_HANDLE_IS_NULL (name)) {
836 mono_error_set_argument_null (error, "name", "");
840 g_assert (!MONO_HANDLE_IS_NULL (ad));
841 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
844 mono_domain_lock (add);
846 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
848 mono_domain_unlock (add);
851 MonoAppDomainSetupHandle
852 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
855 g_assert (!MONO_HANDLE_IS_NULL (ad));
856 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
859 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
863 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
866 g_assert (!MONO_HANDLE_IS_NULL (ad));
867 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
870 return mono_string_new_handle (domain, domain->friendly_name, error);
874 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
877 MonoDomain *add = mono_domain_get ();
879 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
883 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
886 MonoDomain *root = mono_get_root_domain ();
888 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
892 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
894 MonoDomain *domain = mono_domain_get ();
896 return domain->throw_unobserved_task_exceptions;
900 get_attribute_value (const gchar **attribute_names,
901 const gchar **attribute_values,
902 const char *att_name)
905 for (n = 0; attribute_names [n] != NULL; n++) {
906 if (strcmp (attribute_names [n], att_name) == 0)
907 return g_strdup (attribute_values [n]);
913 start_element (GMarkupParseContext *context,
914 const gchar *element_name,
915 const gchar **attribute_names,
916 const gchar **attribute_values,
920 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
922 if (strcmp (element_name, "runtime") == 0) {
923 runtime_config->runtime_count++;
927 if (strcmp (element_name, "assemblyBinding") == 0) {
928 runtime_config->assemblybinding_count++;
932 if (runtime_config->runtime_count != 1)
935 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
936 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
938 if (value && g_ascii_strcasecmp (value, "true") == 0)
939 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
942 if (runtime_config->assemblybinding_count != 1)
945 if (strcmp (element_name, "probing") != 0)
948 g_free (runtime_config->domain->private_bin_path);
949 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
950 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
951 g_free (runtime_config->domain->private_bin_path);
952 runtime_config->domain->private_bin_path = NULL;
958 end_element (GMarkupParseContext *context,
959 const gchar *element_name,
963 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
964 if (strcmp (element_name, "runtime") == 0)
965 runtime_config->runtime_count--;
966 else if (strcmp (element_name, "assemblyBinding") == 0)
967 runtime_config->assemblybinding_count--;
971 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
973 RuntimeConfig *state = (RuntimeConfig *)user_data;
975 const gchar *filename;
977 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
978 msg = error && error->message ? error->message : "";
979 g_warning ("Error parsing %s: %s", filename, msg);
982 static const GMarkupParser
992 mono_domain_set_options_from_config (MonoDomain *domain)
995 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
997 GMarkupParseContext *context;
998 RuntimeConfig runtime_config;
1001 if (!domain || !domain->setup || !domain->setup->configuration_file)
1004 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1005 if (!mono_error_ok (&error)) {
1006 mono_error_cleanup (&error);
1010 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1011 if (!config_file_path)
1012 config_file_path = config_file_name;
1014 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1017 runtime_config.runtime_count = 0;
1018 runtime_config.assemblybinding_count = 0;
1019 runtime_config.domain = domain;
1020 runtime_config.filename = config_file_path;
1023 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1024 offset = 3; /* Skip UTF-8 BOM */
1026 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1027 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1028 g_markup_parse_context_end_parse (context, NULL);
1029 g_markup_parse_context_free (context);
1033 if (config_file_name != config_file_path)
1034 g_free (config_file_name);
1035 g_free (config_file_path);
1039 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1042 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1044 #ifdef DISABLE_APPDOMAINS
1045 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1049 fname = mono_string_handle_to_utf8 (friendly_name, error);
1050 return_val_if_nok (error, ad);
1051 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1058 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1060 HANDLE_FUNCTION_ENTER ();
1062 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1065 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1067 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1071 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1074 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1078 GPtrArray *assemblies;
1081 * Make a copy of the list of assemblies because we can't hold the assemblies
1082 * lock while creating objects etc.
1084 assemblies = g_ptr_array_new ();
1085 /* Need to skip internal assembly builders created by remoting */
1086 mono_domain_assemblies_lock (domain);
1087 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1088 ass = (MonoAssembly *)tmp->data;
1089 if (refonly != ass->ref_only)
1091 if (ass->corlib_internal)
1093 g_ptr_array_add (assemblies, ass);
1095 mono_domain_assemblies_unlock (domain);
1097 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1100 for (i = 0; i < assemblies->len; ++i) {
1101 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1106 g_ptr_array_free (assemblies, TRUE);
1111 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1113 HANDLE_FUNCTION_ENTER ();
1115 MonoAssembly *result = NULL;
1116 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1119 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1121 HANDLE_FUNCTION_RETURN_VAL (result);
1125 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1127 MonoAssembly *ret = NULL;
1129 MonoBoolean isrefonly;
1130 gpointer params [3];
1134 if (mono_runtime_get_no_exec ())
1137 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1139 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1140 g_assert (method != NULL);
1142 isrefonly = refonly ? 1 : 0;
1143 MonoReflectionAssemblyHandle requesting_handle;
1145 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1146 return_val_if_nok (error, ret);
1148 params [0] = MONO_HANDLE_RAW (fname);
1149 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1150 params [2] = &isrefonly;
1151 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1152 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1157 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1161 MonoAssembly *assembly;
1162 MonoDomain *domain = mono_domain_get ();
1165 aname_str = mono_stringify_assembly_name (aname);
1167 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1169 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1171 mono_error_cleanup (&error);
1177 * LOCKING: assumes assemblies_lock in the domain is already locked.
1180 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1184 gboolean destroy_ht = FALSE;
1186 if (!ass->aname.name)
1190 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1192 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1193 g_hash_table_insert (ht, tmp->data, tmp->data);
1197 /* FIXME: handle lazy loaded assemblies */
1199 if (!g_hash_table_lookup (ht, ass)) {
1200 mono_assembly_addref (ass);
1201 g_hash_table_insert (ht, ass, ass);
1202 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1203 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s[%p] added to domain %s, ref_count=%d", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
1206 if (ass->image->references) {
1207 for (i = 0; i < ass->image->nreferences; i++) {
1208 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1209 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1210 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1216 g_hash_table_destroy (ht);
1220 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1222 static MonoClassField *assembly_load_field;
1223 static MonoMethod *assembly_load_method;
1225 MonoDomain *domain = mono_domain_get ();
1227 gpointer load_value;
1230 if (!domain->domain)
1231 /* This can happen during startup */
1233 #ifdef ASSEMBLY_LOAD_DEBUG
1234 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1236 klass = domain->domain->mbr.obj.vtable->klass;
1238 mono_domain_assemblies_lock (domain);
1239 add_assemblies_to_domain (domain, assembly, NULL);
1240 mono_domain_assemblies_unlock (domain);
1242 if (assembly_load_field == NULL) {
1243 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1244 g_assert (assembly_load_field);
1247 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1248 if (load_value == NULL) {
1249 /* No events waiting to be triggered */
1253 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1254 mono_error_assert_ok (&error);
1256 if (assembly_load_method == NULL) {
1257 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1258 g_assert (assembly_load_method);
1261 *params = MONO_HANDLE_RAW(ref_assembly);
1263 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1264 mono_error_cleanup (&error);
1268 * LOCKING: Acquires the domain assemblies lock.
1271 set_domain_search_path (MonoDomain *domain)
1274 MonoAppDomainSetup *setup;
1276 gchar *search_path = NULL;
1279 gchar **pvt_split = NULL;
1280 GError *gerror = NULL;
1281 gint appbaselen = -1;
1284 * We use the low-level domain assemblies lock, since this is called from
1285 * assembly loads hooks, which means this thread might hold the loader lock.
1287 mono_domain_assemblies_lock (domain);
1289 if (!domain->setup) {
1290 mono_domain_assemblies_unlock (domain);
1294 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1295 mono_domain_assemblies_unlock (domain);
1298 setup = domain->setup;
1299 if (!setup->application_base) {
1300 mono_domain_assemblies_unlock (domain);
1301 return; /* Must set application base to get private path working */
1306 if (setup->private_bin_path) {
1307 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1308 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1309 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1310 mono_error_cleanup (&error);
1311 mono_domain_assemblies_unlock (domain);
1316 if (domain->private_bin_path) {
1317 if (search_path == NULL)
1318 search_path = domain->private_bin_path;
1320 gchar *tmp2 = search_path;
1321 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1328 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1329 * directories relative to ApplicationBase separated by semicolons (see
1330 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1331 * The loop below copes with the fact that some Unix applications may use ':' (or
1332 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1333 * ';' for the subsequent split.
1335 * The issue was reported in bug #81446
1338 #ifndef TARGET_WIN32
1341 slen = strlen (search_path);
1342 for (i = 0; i < slen; i++)
1343 if (search_path [i] == ':')
1344 search_path [i] = ';';
1347 pvt_split = g_strsplit (search_path, ";", 1000);
1348 g_free (search_path);
1349 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1354 g_strfreev (pvt_split);
1356 * Don't do this because the first time is called, the domain
1357 * setup is not finished.
1359 * domain->search_path = g_malloc (sizeof (char *));
1360 * domain->search_path [0] = NULL;
1362 mono_domain_assemblies_unlock (domain);
1366 if (domain->search_path)
1367 g_strfreev (domain->search_path);
1369 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1370 tmp [npaths] = NULL;
1372 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1373 if (!mono_error_ok (&error)) {
1374 mono_error_cleanup (&error);
1375 g_strfreev (pvt_split);
1378 mono_domain_assemblies_unlock (domain);
1382 domain->search_path = tmp;
1384 /* FIXME: is this needed? */
1385 if (strncmp (*tmp, "file://", 7) == 0) {
1391 uri = g_strdup_printf ("file:///%s", uri + 7);
1394 uri = mono_escape_uri_string (tmpuri);
1395 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1401 if (gerror != NULL) {
1402 g_warning ("%s\n", gerror->message);
1403 g_error_free (gerror);
1410 for (i = 1; pvt_split && i < npaths; i++) {
1411 if (g_path_is_absolute (pvt_split [i - 1])) {
1412 tmp [i] = g_strdup (pvt_split [i - 1]);
1414 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1417 if (strchr (tmp [i], '.')) {
1421 reduced = mono_path_canonicalize (tmp [i]);
1422 if (appbaselen == -1)
1423 appbaselen = strlen (tmp [0]);
1425 if (strncmp (tmp [0], reduced, appbaselen)) {
1428 tmp [i] = g_strdup ("");
1438 if (setup->private_bin_path_probe != NULL) {
1440 tmp [0] = g_strdup ("");
1443 domain->setup->path_changed = FALSE;
1445 g_strfreev (pvt_split);
1447 mono_domain_assemblies_unlock (domain);
1450 #ifdef DISABLE_SHADOW_COPY
1452 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1458 mono_make_shadow_copy (const char *filename, MonoError *error)
1461 return (char *) filename;
1465 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1467 guint16 *orig, *dest;
1468 gboolean copy_result;
1471 strcpy (src + srclen - tail_len, extension);
1473 if (IS_PORTABILITY_CASE) {
1474 gchar *file = mono_portability_find_file (src, TRUE);
1480 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1484 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1486 strcpy (target + targetlen - tail_len, extension);
1487 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1489 mono_w32file_delete (dest);
1491 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1493 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1494 * overwritten when updated in their original locations. */
1496 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1505 get_cstring_hash (const char *str)
1511 if (!str || !str [0])
1516 for (i = 0; i < len; i++) {
1517 h = (h << 5) - h + *p;
1525 * Returned memory is malloc'd. Called must free it
1528 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1530 MonoAppDomainSetup *setup;
1531 char *cache_path, *appname;
1537 setup = domain->setup;
1538 if (setup->cache_path != NULL && setup->application_name != NULL) {
1539 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1540 return_val_if_nok (error, NULL);
1542 #ifndef TARGET_WIN32
1545 for (i = strlen (cache_path) - 1; i >= 0; i--)
1546 if (cache_path [i] == '\\')
1547 cache_path [i] = '/';
1551 appname = mono_string_to_utf8_checked (setup->application_name, error);
1552 if (!mono_error_ok (error)) {
1553 g_free (cache_path);
1557 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1559 g_free (cache_path);
1561 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1562 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1569 get_shadow_assembly_location (const char *filename, MonoError *error)
1571 gint32 hash = 0, hash2 = 0;
1573 char path_hash [30];
1574 char *bname = g_path_get_basename (filename);
1575 char *dirname = g_path_get_dirname (filename);
1576 char *location, *tmploc;
1577 MonoDomain *domain = mono_domain_get ();
1581 hash = get_cstring_hash (bname);
1582 hash2 = get_cstring_hash (dirname);
1583 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1584 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1585 tmploc = get_shadow_assembly_location_base (domain, error);
1586 if (!mono_error_ok (error)) {
1592 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1600 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1602 struct stat sbuf_dest;
1604 gchar *real_src = mono_portability_find_file (src, TRUE);
1607 stat_src = (gchar*)src;
1609 stat_src = real_src;
1611 if (stat (stat_src, sbuf_src) == -1) {
1612 time_t tnow = time (NULL);
1617 memset (sbuf_src, 0, sizeof (*sbuf_src));
1618 sbuf_src->st_mtime = tnow;
1619 sbuf_src->st_atime = tnow;
1626 if (stat (dest, &sbuf_dest) == -1)
1629 if (sbuf_src->st_size == sbuf_dest.st_size &&
1630 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1637 shadow_copy_create_ini (const char *shadow, const char *filename)
1647 dir_name = g_path_get_dirname (shadow);
1648 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1650 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1655 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1660 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1662 if (handle == INVALID_HANDLE_VALUE) {
1666 full_path = mono_path_resolve_symlinks (filename);
1667 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1669 mono_w32file_close (handle);
1674 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1677 MonoAppDomainSetup *setup;
1680 gchar **directories;
1681 gchar *shadow_status_string;
1683 gboolean shadow_enabled;
1684 gboolean found = FALSE;
1689 setup = domain->setup;
1690 if (setup == NULL || setup->shadow_copy_files == NULL)
1693 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1694 if (!mono_error_ok (&error)) {
1695 mono_error_cleanup (&error);
1698 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1699 g_free (shadow_status_string);
1701 if (!shadow_enabled)
1704 if (setup->shadow_copy_directories == NULL)
1707 /* Is dir_name a shadow_copy destination already? */
1708 base_dir = get_shadow_assembly_location_base (domain, &error);
1709 if (!mono_error_ok (&error)) {
1710 mono_error_cleanup (&error);
1714 if (strstr (dir_name, base_dir)) {
1720 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1721 if (!mono_error_ok (&error)) {
1722 mono_error_cleanup (&error);
1726 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1727 dir_ptr = directories;
1729 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1735 g_strfreev (directories);
1741 This function raises exceptions so it can cause as sorts of nasty stuff if called
1742 while holding a lock.
1743 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1744 or NULL if source file not found.
1745 FIXME bubble up the error instead of raising it here
1748 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1751 gchar *sibling_source, *sibling_target;
1752 gint sibling_source_len, sibling_target_len;
1753 guint16 *orig, *dest;
1756 gboolean copy_result;
1757 struct stat src_sbuf;
1758 struct utimbuf utbuf;
1759 char *dir_name = g_path_get_dirname (filename);
1760 MonoDomain *domain = mono_domain_get ();
1764 error_init (oerror);
1766 set_domain_search_path (domain);
1768 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1770 return (char *) filename;
1773 /* Is dir_name a shadow_copy destination already? */
1774 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1775 if (!mono_error_ok (&error)) {
1776 mono_error_cleanup (&error);
1778 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1782 if (strstr (dir_name, shadow_dir)) {
1783 g_free (shadow_dir);
1785 return (char *) filename;
1787 g_free (shadow_dir);
1790 shadow = get_shadow_assembly_location (filename, &error);
1791 if (!mono_error_ok (&error)) {
1792 mono_error_cleanup (&error);
1793 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1797 if (g_ensure_directory_exists (shadow) == FALSE) {
1799 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1803 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1804 return (char*) shadow;
1806 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1807 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1808 mono_w32file_delete (dest);
1810 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1811 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1812 * and not have it runtime error" */
1813 attrs = mono_w32file_get_attributes (orig);
1814 if (attrs == INVALID_FILE_ATTRIBUTES) {
1816 return (char *)filename;
1819 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1821 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1822 * overwritten when updated in their original locations. */
1824 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1829 if (copy_result == FALSE) {
1832 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1833 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1834 return NULL; /* file not found, shadow copy failed */
1836 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1840 /* attempt to copy .mdb, .config if they exist */
1841 sibling_source = g_strconcat (filename, ".config", NULL);
1842 sibling_source_len = strlen (sibling_source);
1843 sibling_target = g_strconcat (shadow, ".config", NULL);
1844 sibling_target_len = strlen (sibling_target);
1846 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1848 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1850 g_free (sibling_source);
1851 g_free (sibling_target);
1855 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1859 /* Create a .ini file containing the original assembly location */
1860 if (!shadow_copy_create_ini (shadow, filename)) {
1862 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1866 utbuf.actime = src_sbuf.st_atime;
1867 utbuf.modtime = src_sbuf.st_mtime;
1868 utime (shadow, &utbuf);
1872 #endif /* DISABLE_SHADOW_COPY */
1875 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1877 HANDLE_FUNCTION_ENTER ();
1878 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1879 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1880 HANDLE_FUNCTION_RETURN_VAL (result);
1884 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1886 HANDLE_FUNCTION_ENTER ();
1887 MonoDomain *dom = NULL;
1888 if (MONO_HANDLE_IS_NULL (appdomain))
1891 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1892 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1893 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1895 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1897 dom = MONO_HANDLE_GETVAL (appdomain, data);
1900 HANDLE_FUNCTION_RETURN_VAL (dom);
1905 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1906 const gchar *path3, const gchar *path4,
1907 gboolean refonly, gboolean is_private)
1910 gboolean found = FALSE;
1913 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1915 if (IS_PORTABILITY_SET) {
1916 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1919 fullpath = new_fullpath;
1923 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1926 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1929 return (*assembly != NULL);
1932 static MonoAssembly *
1933 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1935 MonoAssembly *result = NULL;
1938 const gchar *local_culture;
1940 gboolean is_private = FALSE;
1942 if (!culture || *culture == '\0') {
1945 local_culture = culture;
1948 filename = g_strconcat (name, ".dll", NULL);
1949 len = strlen (filename);
1951 for (path = search_path; *path; path++) {
1952 if (**path == '\0') {
1954 continue; /* Ignore empty ApplicationBase */
1957 /* See test cases in bug #58992 and bug #57710 */
1958 /* 1st try: [culture]/[name].dll (culture may be empty) */
1959 strcpy (filename + len - 4, ".dll");
1960 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1963 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1964 strcpy (filename + len - 4, ".exe");
1965 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1968 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1969 strcpy (filename + len - 4, ".dll");
1970 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1973 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1974 strcpy (filename + len - 4, ".exe");
1975 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1984 * Try loading the assembly from ApplicationBase and PrivateBinPath
1985 * and then from assemblies_path if any.
1986 * LOCKING: This is called from the assembly loading code, which means the caller
1987 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1989 static MonoAssembly *
1990 mono_domain_assembly_preload (MonoAssemblyName *aname,
1991 gchar **assemblies_path,
1994 MonoDomain *domain = mono_domain_get ();
1995 MonoAssembly *result = NULL;
1996 gboolean refonly = GPOINTER_TO_UINT (user_data);
1998 set_domain_search_path (domain);
2000 if (domain->search_path && domain->search_path [0] != NULL) {
2001 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
2004 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2005 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
2012 * Check whenever a given assembly was already loaded in the current appdomain.
2014 static MonoAssembly *
2015 mono_domain_assembly_search (MonoAssemblyName *aname,
2018 MonoDomain *domain = mono_domain_get ();
2021 gboolean refonly = GPOINTER_TO_UINT (user_data);
2023 mono_domain_assemblies_lock (domain);
2024 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2025 ass = (MonoAssembly *)tmp->data;
2026 /* Dynamic assemblies can't match here in MS.NET */
2027 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2030 mono_domain_assemblies_unlock (domain);
2033 mono_domain_assemblies_unlock (domain);
2038 MonoReflectionAssemblyHandle
2039 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2042 MonoDomain *domain = mono_domain_get ();
2043 char *name, *filename;
2044 MonoImageOpenStatus status = MONO_IMAGE_OK;
2045 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2050 if (fname == NULL) {
2051 mono_error_set_argument_null (error, "assemblyFile", "");
2055 name = filename = mono_string_handle_to_utf8 (fname, error);
2059 MonoAssembly *ass = mono_assembly_open_a_lot (filename, &status, refOnly, TRUE);
2062 if (status == MONO_IMAGE_IMAGE_INVALID)
2063 mono_error_set_bad_image_name (error, g_strdup (name), "");
2065 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2069 result = mono_assembly_get_object_handle (domain, ass, error);
2076 MonoReflectionAssemblyHandle
2077 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2078 MonoArrayHandle raw_assembly,
2079 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2080 MonoBoolean refonly,
2085 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2086 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2087 MonoImageOpenStatus status;
2088 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2090 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2091 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2092 if (!assembly_data) {
2093 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2097 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2098 memcpy (assembly_data, raw_data, raw_assembly_len);
2099 mono_gchandle_free (gchandle); /* unpin */
2100 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2102 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2105 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2109 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2110 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2111 uint32_t symbol_gchandle;
2112 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2113 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2114 mono_gchandle_free (symbol_gchandle);
2117 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2121 mono_image_close (image);
2122 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2126 refass = mono_assembly_get_object_handle (domain, ass, error);
2127 if (!MONO_HANDLE_IS_NULL(refass))
2128 MONO_HANDLE_SET (refass, evidence, evidence);
2132 MonoReflectionAssemblyHandle
2133 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2136 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2137 MonoImageOpenStatus status = MONO_IMAGE_OK;
2139 MonoAssemblyName aname;
2145 name = mono_string_handle_to_utf8 (assRef, error);
2148 parsed = mono_assembly_name_parse (name, &aname);
2152 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2153 /* This is a parse error... */
2155 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2159 refass = mono_assembly_get_object_handle (domain, assm, error);
2167 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2168 mono_assembly_name_free (&aname);
2171 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2173 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2182 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2186 MONO_HANDLE_SET (refass, evidence, evidence);
2190 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2194 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2197 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2199 if (NULL == domain) {
2200 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2204 if (domain == mono_get_root_domain ()) {
2205 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2210 * Unloading seems to cause problems when running NUnit/NAnt, hence
2213 if (g_getenv ("MONO_NO_UNLOAD"))
2215 #ifdef __native_client__
2219 MonoException *exc = NULL;
2220 mono_domain_try_unload (domain, (MonoObject**)&exc);
2222 mono_error_set_exception_instance (error, exc);
2226 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2229 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2234 return mono_domain_is_unloading (domain);
2238 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2240 mono_unhandled_exception ((MonoObject*) exc);
2244 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2245 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2252 g_assert (!MONO_HANDLE_IS_NULL (refass));
2253 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2254 image = assembly->image;
2257 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2260 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2262 if (MONO_HANDLE_IS_NULL (args)) {
2263 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2264 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2265 mono_error_assert_ok (error);
2268 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2273 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2275 return ad->data->domain_id;
2279 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2282 MonoDomain *old_domain = mono_domain_get ();
2284 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2285 mono_error_set_appdomain_unloaded (error);
2286 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2289 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2293 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2295 MonoDomain *current_domain = mono_domain_get ();
2296 MonoDomain *domain = mono_domain_get_by_id (domainid);
2298 if (!domain || !mono_domain_set (domain, FALSE)) {
2299 mono_error_set_appdomain_unloaded (error);
2300 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2303 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2307 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2310 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2314 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2317 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2321 * Raise an exception to prevent the managed code from executing a pop
2324 mono_error_set_appdomain_unloaded (error);
2328 mono_thread_push_appdomain_ref (domain);
2332 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2335 mono_thread_pop_appdomain_ref ();
2339 ves_icall_System_AppDomain_InternalGetContext ()
2341 return mono_context_get ();
2345 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2347 return mono_domain_get ()->default_context;
2351 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2353 MonoAppContext *old_context = mono_context_get ();
2355 mono_context_set (mc);
2361 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2364 MonoDomain* mono_root_domain = mono_get_root_domain ();
2365 mono_domain_lock (mono_root_domain);
2366 if (process_guid_set) {
2367 mono_domain_unlock (mono_root_domain);
2368 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2370 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2371 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2372 mono_gchandle_free (gchandle);
2373 process_guid_set = TRUE;
2374 mono_domain_unlock (mono_root_domain);
2379 mono_domain_is_unloading (MonoDomain *domain)
2381 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2388 clear_cached_vtable (MonoVTable *vtable)
2390 MonoClass *klass = vtable->klass;
2391 MonoDomain *domain = vtable->domain;
2392 MonoClassRuntimeInfo *runtime_info;
2395 runtime_info = klass->runtime_info;
2396 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2397 runtime_info->domain_vtables [domain->domain_id] = NULL;
2398 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2399 mono_gc_free_fixed (data);
2402 static G_GNUC_UNUSED void
2403 zero_static_data (MonoVTable *vtable)
2405 MonoClass *klass = vtable->klass;
2408 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2409 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2412 typedef struct unload_data {
2415 char *failure_reason;
2420 unload_data_unref (unload_data *data)
2424 mono_atomic_load_acquire (count, gint32, &data->refcount);
2425 g_assert (count >= 1 && count <= 2);
2430 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2434 deregister_reflection_info_roots_from_list (MonoImage *image)
2436 GSList *list = image->reflection_info_unregister_classes;
2439 MonoClass *klass = (MonoClass *)list->data;
2441 mono_class_free_ref_info (klass);
2446 image->reflection_info_unregister_classes = NULL;
2450 deregister_reflection_info_roots (MonoDomain *domain)
2454 mono_domain_assemblies_lock (domain);
2455 for (list = domain->domain_assemblies; list; list = list->next) {
2456 MonoAssembly *assembly = (MonoAssembly *)list->data;
2457 MonoImage *image = assembly->image;
2461 * No need to take the image lock here since dynamic images are appdomain bound and
2462 * at this point the mutator is gone. Taking the image lock here would mean
2463 * promoting it from a simple lock to a complex lock, which we better avoid if
2466 if (image_is_dynamic (image))
2467 deregister_reflection_info_roots_from_list (image);
2469 for (i = 0; i < image->module_count; ++i) {
2470 MonoImage *module = image->modules [i];
2471 if (module && image_is_dynamic (module))
2472 deregister_reflection_info_roots_from_list (module);
2475 mono_domain_assemblies_unlock (domain);
2479 unload_thread_main (void *arg)
2482 unload_data *data = (unload_data*)arg;
2483 MonoDomain *domain = data->domain;
2484 MonoInternalThread *internal;
2487 internal = mono_thread_internal_current ();
2489 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2490 if (!is_ok (&error)) {
2491 data->failure_reason = g_strdup (mono_error_get_message (&error));
2492 mono_error_cleanup (&error);
2497 * FIXME: Abort our parent thread last, so we can return a failure
2498 * indication if aborting times out.
2500 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2501 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2505 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2506 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2510 /* Finalize all finalizable objects in the doomed appdomain */
2511 if (!mono_domain_finalize (domain, -1)) {
2512 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2516 /* Clear references to our vtables in class->runtime_info.
2517 * We also hold the loader lock because we're going to change
2518 * class->runtime_info.
2521 mono_loader_lock (); //FIXME why do we need the loader lock here?
2522 mono_domain_lock (domain);
2525 * We need to make sure that we don't have any remsets
2526 * pointing into static data of the to-be-freed domain because
2527 * at the next collections they would be invalid. So what we
2528 * do is we first zero all static data and then do a minor
2529 * collection. Because all references in the static data will
2530 * now be null we won't do any unnecessary copies and after
2531 * the collection there won't be any more remsets.
2533 for (i = 0; i < domain->class_vtable_array->len; ++i)
2534 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2535 mono_gc_collect (0);
2537 for (i = 0; i < domain->class_vtable_array->len; ++i)
2538 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2539 deregister_reflection_info_roots (domain);
2541 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2543 mono_domain_unlock (domain);
2544 mono_loader_unlock ();
2546 domain->state = MONO_APPDOMAIN_UNLOADED;
2548 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2550 /* remove from the handle table the items related to this domain */
2551 mono_gchandle_free_domain (domain);
2553 mono_domain_free (domain, FALSE);
2555 mono_gc_collect (mono_gc_max_generation ());
2557 mono_atomic_store_release (&data->done, TRUE);
2558 unload_data_unref (data);
2562 mono_atomic_store_release (&data->done, TRUE);
2563 unload_data_unref (data);
2568 * mono_domain_unload:
2569 * @domain: The domain to unload
2571 * Unloads an appdomain. Follows the process outlined in the comment
2572 * for mono_domain_try_unload.
2575 mono_domain_unload (MonoDomain *domain)
2577 MonoObject *exc = NULL;
2578 mono_domain_try_unload (domain, &exc);
2581 static MonoThreadInfoWaitRet
2582 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2584 MonoThreadInfoWaitRet result;
2587 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2594 * mono_domain_unload:
2595 * @domain: The domain to unload
2596 * @exc: Exception information
2598 * Unloads an appdomain. Follows the process outlined in:
2599 * http://blogs.gotdotnet.com/cbrumme
2601 * If doing things the 'right' way is too hard or complex, we do it the
2602 * 'simple' way, which means do everything needed to avoid crashes and
2603 * memory leaks, but not much else.
2605 * It is required to pass a valid reference to the exc argument, upon return
2606 * from this function *exc will be set to the exception thrown, if any.
2608 * If this method is not called from an icall (embedded scenario for instance),
2609 * it must not be called with any managed frames on the stack, since the unload
2610 * process could end up trying to abort the current thread.
2613 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2616 MonoThreadHandle *thread_handle;
2617 MonoAppDomainState prev_state;
2619 unload_data *thread_data;
2620 MonoInternalThread *internal;
2621 MonoDomain *caller_domain = mono_domain_get ();
2623 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2625 /* Atomically change our state to UNLOADING */
2626 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2627 MONO_APPDOMAIN_UNLOADING_START,
2628 MONO_APPDOMAIN_CREATED);
2629 if (prev_state != MONO_APPDOMAIN_CREATED) {
2630 switch (prev_state) {
2631 case MONO_APPDOMAIN_UNLOADING_START:
2632 case MONO_APPDOMAIN_UNLOADING:
2633 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2635 case MONO_APPDOMAIN_UNLOADED:
2636 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2639 g_warning ("Invalid appdomain state %d", prev_state);
2640 g_assert_not_reached ();
2644 mono_domain_set (domain, FALSE);
2645 /* Notify OnDomainUnload listeners */
2646 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2649 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2651 if (!mono_error_ok (&error)) {
2653 mono_error_cleanup (&error);
2655 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2659 /* Roll back the state change */
2660 domain->state = MONO_APPDOMAIN_CREATED;
2661 mono_domain_set (caller_domain, FALSE);
2664 mono_domain_set (caller_domain, FALSE);
2666 thread_data = g_new0 (unload_data, 1);
2667 thread_data->domain = domain;
2668 thread_data->failure_reason = NULL;
2669 thread_data->done = FALSE;
2670 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2672 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2673 domain->state = MONO_APPDOMAIN_UNLOADING;
2675 * First we create a separate thread for unloading, since
2676 * we might have to abort some threads, including the current one.
2678 * Have to attach to the runtime so shutdown can wait for this thread.
2680 * Force it to be attached to avoid racing during shutdown.
2682 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2683 mono_error_assert_ok (&error);
2685 thread_handle = mono_threads_open_thread_handle (internal->handle);
2687 /* Wait for the thread */
2688 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2689 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2690 /* The unload thread tries to abort us */
2691 /* The icall wrapper will execute the abort */
2692 mono_threads_close_thread_handle (thread_handle);
2693 unload_data_unref (thread_data);
2698 mono_threads_close_thread_handle (thread_handle);
2700 if (thread_data->failure_reason) {
2701 /* Roll back the state change */
2702 domain->state = MONO_APPDOMAIN_CREATED;
2704 g_warning ("%s", thread_data->failure_reason);
2706 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2708 g_free (thread_data->failure_reason);
2709 thread_data->failure_reason = NULL;
2712 unload_data_unref (thread_data);