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);
1194 /* FIXME: handle lazy loaded assemblies */
1195 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1196 g_hash_table_insert (ht, tmp->data, tmp->data);
1198 if (!g_hash_table_lookup (ht, ass)) {
1199 mono_assembly_addref (ass);
1200 g_hash_table_insert (ht, ass, ass);
1201 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1202 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);
1205 if (ass->image->references) {
1206 for (i = 0; ass->image->references [i] != NULL; i++) {
1207 if (ass->image->references [i] != REFERENCE_MISSING)
1208 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1209 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1214 g_hash_table_destroy (ht);
1218 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1220 static MonoClassField *assembly_load_field;
1221 static MonoMethod *assembly_load_method;
1223 MonoDomain *domain = mono_domain_get ();
1225 gpointer load_value;
1228 if (!domain->domain)
1229 /* This can happen during startup */
1231 #ifdef ASSEMBLY_LOAD_DEBUG
1232 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1234 klass = domain->domain->mbr.obj.vtable->klass;
1236 mono_domain_assemblies_lock (domain);
1237 add_assemblies_to_domain (domain, assembly, NULL);
1238 mono_domain_assemblies_unlock (domain);
1240 if (assembly_load_field == NULL) {
1241 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1242 g_assert (assembly_load_field);
1245 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1246 if (load_value == NULL) {
1247 /* No events waiting to be triggered */
1251 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1252 mono_error_assert_ok (&error);
1254 if (assembly_load_method == NULL) {
1255 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1256 g_assert (assembly_load_method);
1259 *params = MONO_HANDLE_RAW(ref_assembly);
1261 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1262 mono_error_cleanup (&error);
1266 * LOCKING: Acquires the domain assemblies lock.
1269 set_domain_search_path (MonoDomain *domain)
1272 MonoAppDomainSetup *setup;
1274 gchar *search_path = NULL;
1277 gchar **pvt_split = NULL;
1278 GError *gerror = NULL;
1279 gint appbaselen = -1;
1282 * We use the low-level domain assemblies lock, since this is called from
1283 * assembly loads hooks, which means this thread might hold the loader lock.
1285 mono_domain_assemblies_lock (domain);
1287 if (!domain->setup) {
1288 mono_domain_assemblies_unlock (domain);
1292 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1293 mono_domain_assemblies_unlock (domain);
1296 setup = domain->setup;
1297 if (!setup->application_base) {
1298 mono_domain_assemblies_unlock (domain);
1299 return; /* Must set application base to get private path working */
1304 if (setup->private_bin_path) {
1305 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1306 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1307 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1308 mono_error_cleanup (&error);
1309 mono_domain_assemblies_unlock (domain);
1314 if (domain->private_bin_path) {
1315 if (search_path == NULL)
1316 search_path = domain->private_bin_path;
1318 gchar *tmp2 = search_path;
1319 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1326 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1327 * directories relative to ApplicationBase separated by semicolons (see
1328 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1329 * The loop below copes with the fact that some Unix applications may use ':' (or
1330 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1331 * ';' for the subsequent split.
1333 * The issue was reported in bug #81446
1336 #ifndef TARGET_WIN32
1339 slen = strlen (search_path);
1340 for (i = 0; i < slen; i++)
1341 if (search_path [i] == ':')
1342 search_path [i] = ';';
1345 pvt_split = g_strsplit (search_path, ";", 1000);
1346 g_free (search_path);
1347 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1352 g_strfreev (pvt_split);
1354 * Don't do this because the first time is called, the domain
1355 * setup is not finished.
1357 * domain->search_path = g_malloc (sizeof (char *));
1358 * domain->search_path [0] = NULL;
1360 mono_domain_assemblies_unlock (domain);
1364 if (domain->search_path)
1365 g_strfreev (domain->search_path);
1367 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1368 tmp [npaths] = NULL;
1370 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1371 if (!mono_error_ok (&error)) {
1372 mono_error_cleanup (&error);
1373 g_strfreev (pvt_split);
1376 mono_domain_assemblies_unlock (domain);
1380 domain->search_path = tmp;
1382 /* FIXME: is this needed? */
1383 if (strncmp (*tmp, "file://", 7) == 0) {
1389 uri = g_strdup_printf ("file:///%s", uri + 7);
1392 uri = mono_escape_uri_string (tmpuri);
1393 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1399 if (gerror != NULL) {
1400 g_warning ("%s\n", gerror->message);
1401 g_error_free (gerror);
1408 for (i = 1; pvt_split && i < npaths; i++) {
1409 if (g_path_is_absolute (pvt_split [i - 1])) {
1410 tmp [i] = g_strdup (pvt_split [i - 1]);
1412 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1415 if (strchr (tmp [i], '.')) {
1419 reduced = mono_path_canonicalize (tmp [i]);
1420 if (appbaselen == -1)
1421 appbaselen = strlen (tmp [0]);
1423 if (strncmp (tmp [0], reduced, appbaselen)) {
1426 tmp [i] = g_strdup ("");
1436 if (setup->private_bin_path_probe != NULL) {
1438 tmp [0] = g_strdup ("");
1441 domain->setup->path_changed = FALSE;
1443 g_strfreev (pvt_split);
1445 mono_domain_assemblies_unlock (domain);
1448 #ifdef DISABLE_SHADOW_COPY
1450 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1456 mono_make_shadow_copy (const char *filename, MonoError *error)
1459 return (char *) filename;
1463 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1465 guint16 *orig, *dest;
1466 gboolean copy_result;
1469 strcpy (src + srclen - tail_len, extension);
1471 if (IS_PORTABILITY_CASE) {
1472 gchar *file = mono_portability_find_file (src, TRUE);
1478 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1482 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1484 strcpy (target + targetlen - tail_len, extension);
1485 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1487 mono_w32file_delete (dest);
1489 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1491 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1492 * overwritten when updated in their original locations. */
1494 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1503 get_cstring_hash (const char *str)
1509 if (!str || !str [0])
1514 for (i = 0; i < len; i++) {
1515 h = (h << 5) - h + *p;
1523 * Returned memory is malloc'd. Called must free it
1526 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1528 MonoAppDomainSetup *setup;
1529 char *cache_path, *appname;
1535 setup = domain->setup;
1536 if (setup->cache_path != NULL && setup->application_name != NULL) {
1537 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1538 return_val_if_nok (error, NULL);
1540 #ifndef TARGET_WIN32
1543 for (i = strlen (cache_path) - 1; i >= 0; i--)
1544 if (cache_path [i] == '\\')
1545 cache_path [i] = '/';
1549 appname = mono_string_to_utf8_checked (setup->application_name, error);
1550 if (!mono_error_ok (error)) {
1551 g_free (cache_path);
1555 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1557 g_free (cache_path);
1559 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1560 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1567 get_shadow_assembly_location (const char *filename, MonoError *error)
1569 gint32 hash = 0, hash2 = 0;
1571 char path_hash [30];
1572 char *bname = g_path_get_basename (filename);
1573 char *dirname = g_path_get_dirname (filename);
1574 char *location, *tmploc;
1575 MonoDomain *domain = mono_domain_get ();
1579 hash = get_cstring_hash (bname);
1580 hash2 = get_cstring_hash (dirname);
1581 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1582 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1583 tmploc = get_shadow_assembly_location_base (domain, error);
1584 if (!mono_error_ok (error)) {
1590 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1598 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1600 struct stat sbuf_dest;
1602 gchar *real_src = mono_portability_find_file (src, TRUE);
1605 stat_src = (gchar*)src;
1607 stat_src = real_src;
1609 if (stat (stat_src, sbuf_src) == -1) {
1610 time_t tnow = time (NULL);
1615 memset (sbuf_src, 0, sizeof (*sbuf_src));
1616 sbuf_src->st_mtime = tnow;
1617 sbuf_src->st_atime = tnow;
1624 if (stat (dest, &sbuf_dest) == -1)
1627 if (sbuf_src->st_size == sbuf_dest.st_size &&
1628 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1635 shadow_copy_create_ini (const char *shadow, const char *filename)
1645 dir_name = g_path_get_dirname (shadow);
1646 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1648 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1653 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1658 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1660 if (handle == INVALID_HANDLE_VALUE) {
1664 full_path = mono_path_resolve_symlinks (filename);
1665 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1667 mono_w32file_close (handle);
1672 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1675 MonoAppDomainSetup *setup;
1678 gchar **directories;
1679 gchar *shadow_status_string;
1681 gboolean shadow_enabled;
1682 gboolean found = FALSE;
1687 setup = domain->setup;
1688 if (setup == NULL || setup->shadow_copy_files == NULL)
1691 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1692 if (!mono_error_ok (&error)) {
1693 mono_error_cleanup (&error);
1696 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1697 g_free (shadow_status_string);
1699 if (!shadow_enabled)
1702 if (setup->shadow_copy_directories == NULL)
1705 /* Is dir_name a shadow_copy destination already? */
1706 base_dir = get_shadow_assembly_location_base (domain, &error);
1707 if (!mono_error_ok (&error)) {
1708 mono_error_cleanup (&error);
1712 if (strstr (dir_name, base_dir)) {
1718 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1719 if (!mono_error_ok (&error)) {
1720 mono_error_cleanup (&error);
1724 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1725 dir_ptr = directories;
1727 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1733 g_strfreev (directories);
1739 This function raises exceptions so it can cause as sorts of nasty stuff if called
1740 while holding a lock.
1741 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1742 or NULL if source file not found.
1743 FIXME bubble up the error instead of raising it here
1746 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1749 gchar *sibling_source, *sibling_target;
1750 gint sibling_source_len, sibling_target_len;
1751 guint16 *orig, *dest;
1754 gboolean copy_result;
1755 struct stat src_sbuf;
1756 struct utimbuf utbuf;
1757 char *dir_name = g_path_get_dirname (filename);
1758 MonoDomain *domain = mono_domain_get ();
1762 error_init (oerror);
1764 set_domain_search_path (domain);
1766 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1768 return (char *) filename;
1771 /* Is dir_name a shadow_copy destination already? */
1772 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1773 if (!mono_error_ok (&error)) {
1774 mono_error_cleanup (&error);
1776 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1780 if (strstr (dir_name, shadow_dir)) {
1781 g_free (shadow_dir);
1783 return (char *) filename;
1785 g_free (shadow_dir);
1788 shadow = get_shadow_assembly_location (filename, &error);
1789 if (!mono_error_ok (&error)) {
1790 mono_error_cleanup (&error);
1791 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1795 if (g_ensure_directory_exists (shadow) == FALSE) {
1797 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1801 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1802 return (char*) shadow;
1804 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1805 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1806 mono_w32file_delete (dest);
1808 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1809 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1810 * and not have it runtime error" */
1811 attrs = mono_w32file_get_attributes (orig);
1812 if (attrs == INVALID_FILE_ATTRIBUTES) {
1814 return (char *)filename;
1817 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1819 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1820 * overwritten when updated in their original locations. */
1822 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1827 if (copy_result == FALSE) {
1830 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1831 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1832 return NULL; /* file not found, shadow copy failed */
1834 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1838 /* attempt to copy .mdb, .config if they exist */
1839 sibling_source = g_strconcat (filename, ".config", NULL);
1840 sibling_source_len = strlen (sibling_source);
1841 sibling_target = g_strconcat (shadow, ".config", NULL);
1842 sibling_target_len = strlen (sibling_target);
1844 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1846 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1848 g_free (sibling_source);
1849 g_free (sibling_target);
1853 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1857 /* Create a .ini file containing the original assembly location */
1858 if (!shadow_copy_create_ini (shadow, filename)) {
1860 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1864 utbuf.actime = src_sbuf.st_atime;
1865 utbuf.modtime = src_sbuf.st_mtime;
1866 utime (shadow, &utbuf);
1870 #endif /* DISABLE_SHADOW_COPY */
1873 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1875 HANDLE_FUNCTION_ENTER ();
1876 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1877 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1878 HANDLE_FUNCTION_RETURN_VAL (result);
1882 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1884 HANDLE_FUNCTION_ENTER ();
1885 MonoDomain *dom = NULL;
1886 if (MONO_HANDLE_IS_NULL (appdomain))
1889 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1890 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1891 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1893 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1895 dom = MONO_HANDLE_GETVAL (appdomain, data);
1898 HANDLE_FUNCTION_RETURN_VAL (dom);
1903 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1904 const gchar *path3, const gchar *path4,
1905 gboolean refonly, gboolean is_private)
1908 gboolean found = FALSE;
1911 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1913 if (IS_PORTABILITY_SET) {
1914 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1917 fullpath = new_fullpath;
1921 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1924 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1927 return (*assembly != NULL);
1930 static MonoAssembly *
1931 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1933 MonoAssembly *result = NULL;
1936 const gchar *local_culture;
1938 gboolean is_private = FALSE;
1940 if (!culture || *culture == '\0') {
1943 local_culture = culture;
1946 filename = g_strconcat (name, ".dll", NULL);
1947 len = strlen (filename);
1949 for (path = search_path; *path; path++) {
1950 if (**path == '\0') {
1952 continue; /* Ignore empty ApplicationBase */
1955 /* See test cases in bug #58992 and bug #57710 */
1956 /* 1st try: [culture]/[name].dll (culture may be empty) */
1957 strcpy (filename + len - 4, ".dll");
1958 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1961 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1962 strcpy (filename + len - 4, ".exe");
1963 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1966 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1967 strcpy (filename + len - 4, ".dll");
1968 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1971 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1972 strcpy (filename + len - 4, ".exe");
1973 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1982 * Try loading the assembly from ApplicationBase and PrivateBinPath
1983 * and then from assemblies_path if any.
1984 * LOCKING: This is called from the assembly loading code, which means the caller
1985 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1987 static MonoAssembly *
1988 mono_domain_assembly_preload (MonoAssemblyName *aname,
1989 gchar **assemblies_path,
1992 MonoDomain *domain = mono_domain_get ();
1993 MonoAssembly *result = NULL;
1994 gboolean refonly = GPOINTER_TO_UINT (user_data);
1996 set_domain_search_path (domain);
1998 if (domain->search_path && domain->search_path [0] != NULL) {
1999 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
2002 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2003 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
2010 * Check whenever a given assembly was already loaded in the current appdomain.
2012 static MonoAssembly *
2013 mono_domain_assembly_search (MonoAssemblyName *aname,
2016 MonoDomain *domain = mono_domain_get ();
2019 gboolean refonly = GPOINTER_TO_UINT (user_data);
2021 mono_domain_assemblies_lock (domain);
2022 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2023 ass = (MonoAssembly *)tmp->data;
2024 /* Dynamic assemblies can't match here in MS.NET */
2025 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2028 mono_domain_assemblies_unlock (domain);
2031 mono_domain_assemblies_unlock (domain);
2036 MonoReflectionAssemblyHandle
2037 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2040 MonoDomain *domain = mono_domain_get ();
2041 char *name, *filename;
2042 MonoImageOpenStatus status = MONO_IMAGE_OK;
2043 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2048 if (fname == NULL) {
2049 mono_error_set_argument_null (error, "assemblyFile", "");
2053 name = filename = mono_string_handle_to_utf8 (fname, error);
2057 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2060 if (status == MONO_IMAGE_IMAGE_INVALID)
2061 mono_error_set_bad_image_name (error, g_strdup (name), "");
2063 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2067 result = mono_assembly_get_object_handle (domain, ass, error);
2074 MonoReflectionAssemblyHandle
2075 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2076 MonoArrayHandle raw_assembly,
2077 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2078 MonoBoolean refonly,
2083 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2084 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2085 MonoImageOpenStatus status;
2086 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2088 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2089 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2090 if (!assembly_data) {
2091 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2095 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2096 memcpy (assembly_data, raw_data, raw_assembly_len);
2097 mono_gchandle_free (gchandle); /* unpin */
2098 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2100 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2103 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2107 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2108 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2109 uint32_t symbol_gchandle;
2110 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2111 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2112 mono_gchandle_free (symbol_gchandle);
2115 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2119 mono_image_close (image);
2120 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2124 refass = mono_assembly_get_object_handle (domain, ass, error);
2125 if (!MONO_HANDLE_IS_NULL(refass))
2126 MONO_HANDLE_SET (refass, evidence, evidence);
2130 MonoReflectionAssemblyHandle
2131 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2134 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2135 MonoImageOpenStatus status = MONO_IMAGE_OK;
2137 MonoAssemblyName aname;
2143 name = mono_string_handle_to_utf8 (assRef, error);
2146 parsed = mono_assembly_name_parse (name, &aname);
2150 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2151 /* This is a parse error... */
2153 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2157 refass = mono_assembly_get_object_handle (domain, assm, error);
2165 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2166 mono_assembly_name_free (&aname);
2169 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2171 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2180 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2184 MONO_HANDLE_SET (refass, evidence, evidence);
2188 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2192 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2195 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2197 if (NULL == domain) {
2198 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2202 if (domain == mono_get_root_domain ()) {
2203 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2208 * Unloading seems to cause problems when running NUnit/NAnt, hence
2211 if (g_getenv ("MONO_NO_UNLOAD"))
2213 #ifdef __native_client__
2217 MonoException *exc = NULL;
2218 mono_domain_try_unload (domain, (MonoObject**)&exc);
2220 mono_error_set_exception_instance (error, exc);
2224 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2227 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2232 return mono_domain_is_unloading (domain);
2236 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2238 mono_unhandled_exception ((MonoObject*) exc);
2242 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2243 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2250 g_assert (!MONO_HANDLE_IS_NULL (refass));
2251 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2252 image = assembly->image;
2255 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2258 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2260 if (MONO_HANDLE_IS_NULL (args)) {
2261 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2262 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2263 mono_error_assert_ok (error);
2266 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2271 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2273 return ad->data->domain_id;
2277 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2280 MonoDomain *old_domain = mono_domain_get ();
2282 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2283 mono_error_set_appdomain_unloaded (error);
2284 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2287 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2291 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2293 MonoDomain *current_domain = mono_domain_get ();
2294 MonoDomain *domain = mono_domain_get_by_id (domainid);
2296 if (!domain || !mono_domain_set (domain, FALSE)) {
2297 mono_error_set_appdomain_unloaded (error);
2298 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2301 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2305 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2308 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2312 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2315 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2319 * Raise an exception to prevent the managed code from executing a pop
2322 mono_error_set_appdomain_unloaded (error);
2326 mono_thread_push_appdomain_ref (domain);
2330 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2333 mono_thread_pop_appdomain_ref ();
2337 ves_icall_System_AppDomain_InternalGetContext ()
2339 return mono_context_get ();
2343 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2345 return mono_domain_get ()->default_context;
2349 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2351 MonoAppContext *old_context = mono_context_get ();
2353 mono_context_set (mc);
2359 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2362 MonoDomain* mono_root_domain = mono_get_root_domain ();
2363 mono_domain_lock (mono_root_domain);
2364 if (process_guid_set) {
2365 mono_domain_unlock (mono_root_domain);
2366 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2368 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2369 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2370 mono_gchandle_free (gchandle);
2371 process_guid_set = TRUE;
2372 mono_domain_unlock (mono_root_domain);
2377 mono_domain_is_unloading (MonoDomain *domain)
2379 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2386 clear_cached_vtable (MonoVTable *vtable)
2388 MonoClass *klass = vtable->klass;
2389 MonoDomain *domain = vtable->domain;
2390 MonoClassRuntimeInfo *runtime_info;
2393 runtime_info = klass->runtime_info;
2394 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2395 runtime_info->domain_vtables [domain->domain_id] = NULL;
2396 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2397 mono_gc_free_fixed (data);
2400 static G_GNUC_UNUSED void
2401 zero_static_data (MonoVTable *vtable)
2403 MonoClass *klass = vtable->klass;
2406 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2407 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2410 typedef struct unload_data {
2413 char *failure_reason;
2418 unload_data_unref (unload_data *data)
2422 mono_atomic_load_acquire (count, gint32, &data->refcount);
2423 g_assert (count >= 1 && count <= 2);
2428 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2432 deregister_reflection_info_roots_from_list (MonoImage *image)
2434 GSList *list = image->reflection_info_unregister_classes;
2437 MonoClass *klass = (MonoClass *)list->data;
2439 mono_class_free_ref_info (klass);
2444 image->reflection_info_unregister_classes = NULL;
2448 deregister_reflection_info_roots (MonoDomain *domain)
2452 mono_domain_assemblies_lock (domain);
2453 for (list = domain->domain_assemblies; list; list = list->next) {
2454 MonoAssembly *assembly = (MonoAssembly *)list->data;
2455 MonoImage *image = assembly->image;
2459 * No need to take the image lock here since dynamic images are appdomain bound and
2460 * at this point the mutator is gone. Taking the image lock here would mean
2461 * promoting it from a simple lock to a complex lock, which we better avoid if
2464 if (image_is_dynamic (image))
2465 deregister_reflection_info_roots_from_list (image);
2467 for (i = 0; i < image->module_count; ++i) {
2468 MonoImage *module = image->modules [i];
2469 if (module && image_is_dynamic (module))
2470 deregister_reflection_info_roots_from_list (module);
2473 mono_domain_assemblies_unlock (domain);
2477 unload_thread_main (void *arg)
2480 unload_data *data = (unload_data*)arg;
2481 MonoDomain *domain = data->domain;
2482 MonoInternalThread *internal;
2485 internal = mono_thread_internal_current ();
2487 mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2488 if (!is_ok (&error)) {
2489 data->failure_reason = g_strdup (mono_error_get_message (&error));
2490 mono_error_cleanup (&error);
2495 * FIXME: Abort our parent thread last, so we can return a failure
2496 * indication if aborting times out.
2498 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2499 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2503 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2504 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2508 /* Finalize all finalizable objects in the doomed appdomain */
2509 if (!mono_domain_finalize (domain, -1)) {
2510 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2514 /* Clear references to our vtables in class->runtime_info.
2515 * We also hold the loader lock because we're going to change
2516 * class->runtime_info.
2519 mono_loader_lock (); //FIXME why do we need the loader lock here?
2520 mono_domain_lock (domain);
2523 * We need to make sure that we don't have any remsets
2524 * pointing into static data of the to-be-freed domain because
2525 * at the next collections they would be invalid. So what we
2526 * do is we first zero all static data and then do a minor
2527 * collection. Because all references in the static data will
2528 * now be null we won't do any unnecessary copies and after
2529 * the collection there won't be any more remsets.
2531 for (i = 0; i < domain->class_vtable_array->len; ++i)
2532 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2533 mono_gc_collect (0);
2535 for (i = 0; i < domain->class_vtable_array->len; ++i)
2536 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2537 deregister_reflection_info_roots (domain);
2539 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2541 mono_domain_unlock (domain);
2542 mono_loader_unlock ();
2544 domain->state = MONO_APPDOMAIN_UNLOADED;
2546 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2548 /* remove from the handle table the items related to this domain */
2549 mono_gchandle_free_domain (domain);
2551 mono_domain_free (domain, FALSE);
2553 mono_gc_collect (mono_gc_max_generation ());
2555 mono_atomic_store_release (&data->done, TRUE);
2556 unload_data_unref (data);
2560 mono_atomic_store_release (&data->done, TRUE);
2561 unload_data_unref (data);
2566 * mono_domain_unload:
2567 * @domain: The domain to unload
2569 * Unloads an appdomain. Follows the process outlined in the comment
2570 * for mono_domain_try_unload.
2573 mono_domain_unload (MonoDomain *domain)
2575 MonoObject *exc = NULL;
2576 mono_domain_try_unload (domain, &exc);
2579 static MonoThreadInfoWaitRet
2580 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2582 MonoThreadInfoWaitRet result;
2585 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2592 * mono_domain_unload:
2593 * @domain: The domain to unload
2594 * @exc: Exception information
2596 * Unloads an appdomain. Follows the process outlined in:
2597 * http://blogs.gotdotnet.com/cbrumme
2599 * If doing things the 'right' way is too hard or complex, we do it the
2600 * 'simple' way, which means do everything needed to avoid crashes and
2601 * memory leaks, but not much else.
2603 * It is required to pass a valid reference to the exc argument, upon return
2604 * from this function *exc will be set to the exception thrown, if any.
2606 * If this method is not called from an icall (embedded scenario for instance),
2607 * it must not be called with any managed frames on the stack, since the unload
2608 * process could end up trying to abort the current thread.
2611 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2614 MonoThreadHandle *thread_handle;
2615 MonoAppDomainState prev_state;
2617 unload_data *thread_data;
2618 MonoInternalThread *internal;
2619 MonoDomain *caller_domain = mono_domain_get ();
2621 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2623 /* Atomically change our state to UNLOADING */
2624 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2625 MONO_APPDOMAIN_UNLOADING_START,
2626 MONO_APPDOMAIN_CREATED);
2627 if (prev_state != MONO_APPDOMAIN_CREATED) {
2628 switch (prev_state) {
2629 case MONO_APPDOMAIN_UNLOADING_START:
2630 case MONO_APPDOMAIN_UNLOADING:
2631 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2633 case MONO_APPDOMAIN_UNLOADED:
2634 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2637 g_warning ("Invalid appdomain state %d", prev_state);
2638 g_assert_not_reached ();
2642 mono_domain_set (domain, FALSE);
2643 /* Notify OnDomainUnload listeners */
2644 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2647 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2649 if (!mono_error_ok (&error)) {
2651 mono_error_cleanup (&error);
2653 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2657 /* Roll back the state change */
2658 domain->state = MONO_APPDOMAIN_CREATED;
2659 mono_domain_set (caller_domain, FALSE);
2662 mono_domain_set (caller_domain, FALSE);
2664 thread_data = g_new0 (unload_data, 1);
2665 thread_data->domain = domain;
2666 thread_data->failure_reason = NULL;
2667 thread_data->done = FALSE;
2668 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2670 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2671 domain->state = MONO_APPDOMAIN_UNLOADING;
2673 * First we create a separate thread for unloading, since
2674 * we might have to abort some threads, including the current one.
2676 * Have to attach to the runtime so shutdown can wait for this thread.
2678 * Force it to be attached to avoid racing during shutdown.
2680 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2681 mono_error_assert_ok (&error);
2683 thread_handle = mono_threads_open_thread_handle (internal->handle);
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);