6 * Dietmar Maurer (dietmar@ximian.com)
8 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2012 Xamarin Inc
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #undef ASSEMBLY_LOAD_DEBUG
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_TIME_H
32 #ifdef HAVE_SYS_UTIME_H
33 #include <sys/utime.h>
37 #include <mono/metadata/gc-internals.h>
38 #include <mono/metadata/object.h>
39 #include <mono/metadata/appdomain-icalls.h>
40 #include <mono/metadata/domain-internals.h>
41 #include "mono/metadata/metadata-internals.h"
42 #include <mono/metadata/assembly-internals.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/exception-internals.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/marshal-internals.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
82 int assemblybinding_count;
87 static gunichar2 process_guid [36];
88 static gboolean process_guid_set = FALSE;
90 static gboolean no_exec = FALSE;
93 mono_domain_assembly_preload (MonoAssemblyName *aname,
94 gchar **assemblies_path,
98 mono_domain_assembly_search (MonoAssemblyName *aname,
102 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
105 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
107 static MonoAppDomainHandle
108 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
111 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
115 mono_context_set_default_context (MonoDomain *domain);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
125 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
128 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
131 mono_error_set_appdomain_unloaded (MonoError *error)
133 mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
137 mono_install_runtime_load (MonoLoadFunc func)
139 load_function = func;
143 mono_runtime_load (const char *filename, const char *runtime_version)
145 g_assert (load_function);
146 return load_function (filename, runtime_version);
150 * mono_runtime_set_no_exec:
152 * Instructs the runtime to operate in static mode, i.e. avoid/do not
153 * allow managed code execution. This is useful for running the AOT
154 * compiler on platforms which allow full-aot execution only. This
155 * should be called before mono_runtime_init ().
158 mono_runtime_set_no_exec (gboolean val)
164 * mono_runtime_get_no_exec:
166 * If true, then the runtime will not allow managed code execution.
169 mono_runtime_get_no_exec (void)
175 create_domain_objects (MonoDomain *domain)
178 MonoDomain *old_domain = mono_domain_get ();
180 MonoVTable *string_vt;
181 MonoClassField *string_empty_fld;
183 if (domain != old_domain) {
184 mono_thread_push_appdomain_ref (domain);
185 mono_domain_set_internal_with_options (domain, FALSE);
189 * Initialize String.Empty. This enables the removal of
190 * the static cctor of the String class.
192 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
193 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
194 g_assert (string_empty_fld);
195 MonoString *empty_str = mono_string_new_checked (domain, "", &error);
196 mono_error_assert_ok (&error);
197 empty_str = mono_string_intern_checked (empty_str, &error);
198 mono_error_assert_ok (&error);
199 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
200 domain->empty_string = empty_str;
203 * Create an instance early since we can't do it when there is no memory.
205 arg = mono_string_new_checked (domain, "Out of memory", &error);
206 mono_error_assert_ok (&error);
207 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
208 mono_error_assert_ok (&error);
211 * These two are needed because the signal handlers might be executing on
212 * an alternate stack, and Boehm GC can't handle that.
214 arg = mono_string_new_checked (domain, "A null value was found where an object instance was required", &error);
215 mono_error_assert_ok (&error);
216 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
217 mono_error_assert_ok (&error);
218 arg = mono_string_new_checked (domain, "The requested operation caused a stack overflow.", &error);
219 mono_error_assert_ok (&error);
220 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
221 mono_error_assert_ok (&error);
223 /*The ephemeron tombstone i*/
224 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
225 mono_error_assert_ok (&error);
227 if (domain != old_domain) {
228 mono_thread_pop_appdomain_ref ();
229 mono_domain_set_internal_with_options (old_domain, FALSE);
233 * This class is used during exception handling, so initialize it here, to prevent
234 * stack overflows while handling stack overflows.
236 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
241 * \param domain domain returned by \c mono_init
243 * Initialize the core AppDomain: this function will run also some
244 * IL initialization code, so it needs the execution engine to be fully
247 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
248 * we know the \c entry_assembly.
252 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
255 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
256 mono_error_cleanup (&error);
260 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
262 MonoAppDomainSetup *setup;
268 mono_portability_helpers_init ();
270 mono_gc_base_init ();
271 mono_monitor_init ();
272 mono_marshal_init ();
274 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
275 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
276 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
277 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
278 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
279 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
280 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
282 mono_thread_init (start_cb, attach_cb);
284 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
285 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
286 return_if_nok (error);
288 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
290 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
291 return_if_nok (error);
295 domain->setup = setup;
297 mono_thread_attach (domain);
299 mono_type_initialization_init ();
301 if (!mono_runtime_get_no_exec ())
302 create_domain_objects (domain);
304 /* GC init has to happen after thread init */
307 /* contexts use GC handles, so they must be initialized after the GC */
308 mono_context_init_checked (domain, error);
309 return_if_nok (error);
310 mono_context_set_default_context (domain);
312 #ifndef DISABLE_SOCKETS
313 mono_network_init ();
316 mono_console_init ();
319 mono_locks_tracer_init ();
321 /* mscorlib is loaded before we install the load hook */
322 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
328 mono_context_set_default_context (MonoDomain *domain)
330 HANDLE_FUNCTION_ENTER ();
331 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext, domain->default_context));
332 HANDLE_FUNCTION_RETURN ();
337 mono_get_corlib_version (void)
341 MonoClassField *field;
344 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
345 mono_class_init (klass);
346 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
349 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
351 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
352 mono_error_assert_ok (&error);
353 return *(gint32*)((gchar*)value + sizeof (MonoObject));
357 * mono_check_corlib_version:
358 * Checks that the corlib that is loaded matches the version of this runtime.
359 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
360 * allocated string with the error otherwise.
363 mono_check_corlib_version (void)
365 int version = mono_get_corlib_version ();
366 if (version != MONO_CORLIB_VERSION)
367 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
369 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
370 guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
371 guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
372 if (native_offset != managed_offset)
373 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
380 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
381 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
384 mono_context_init (MonoDomain *domain)
387 mono_context_init_checked (domain, &error);
388 mono_error_cleanup (&error);
392 mono_context_init_checked (MonoDomain *domain, MonoError *error)
395 MonoAppContext *context;
399 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
400 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
401 return_if_nok (error);
403 context->domain_id = domain->domain_id;
404 context->context_id = 0;
405 mono_threads_register_app_context (context, error);
406 mono_error_assert_ok (error);
407 domain->default_context = context;
411 * mono_runtime_cleanup:
412 * \param domain unused.
416 * This must not be called while there are still running threads executing
420 mono_runtime_cleanup (MonoDomain *domain)
422 mono_attach_cleanup ();
424 /* This ends up calling any pending pending (for at most 2 seconds) */
427 mono_thread_cleanup ();
429 #ifndef DISABLE_SOCKETS
430 mono_network_cleanup ();
432 mono_marshal_cleanup ();
434 mono_type_initialization_cleanup ();
436 mono_monitor_cleanup ();
439 static MonoDomainFunc quit_function = NULL;
442 * mono_install_runtime_cleanup:
445 mono_install_runtime_cleanup (MonoDomainFunc func)
447 quit_function = func;
456 if (quit_function != NULL)
457 quit_function (mono_get_root_domain (), NULL);
461 * mono_domain_create_appdomain:
462 * \param friendly_name The friendly name of the appdomain to create
463 * \param configuration_file The configuration file to initialize the appdomain with
464 * \returns a \c MonoDomain initialized with the appdomain
467 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
469 HANDLE_FUNCTION_ENTER ();
471 MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
472 mono_error_cleanup (&error);
473 HANDLE_FUNCTION_RETURN_VAL (domain);
477 * mono_domain_create_appdomain_checked:
478 * \param friendly_name The friendly name of the appdomain to create
479 * \param configuration_file The configuration file to initialize the appdomain with
480 * \param error Set on error.
482 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
485 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
487 HANDLE_FUNCTION_ENTER ();
489 MonoDomain *result = NULL;
491 MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
492 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
495 MonoStringHandle config_file;
496 if (configuration_file != NULL) {
497 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
501 config_file = MONO_HANDLE_NEW (MonoString, NULL);
503 MONO_HANDLE_SET (setup, configuration_file, config_file);
505 MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
509 result = mono_domain_from_appdomain_handle (ad);
511 HANDLE_FUNCTION_RETURN_VAL (result);
515 * mono_domain_set_config:
516 * \param domain \c MonoDomain initialized with the appdomain we want to change
517 * \param base_dir new base directory for the appdomain
518 * \param config_file_name path to the new configuration for the app domain
520 * Used to set the system configuration for an appdomain
522 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
523 * Error Initializing the configuration system. ---> System.ArgumentException:
524 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
527 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
529 HANDLE_FUNCTION_ENTER ();
531 mono_domain_set_config_checked (domain, base_dir, config_file_name, &error);
532 mono_error_cleanup (&error);
533 HANDLE_FUNCTION_RETURN ();
537 mono_domain_set_config_checked (MonoDomain *domain, const char *base_dir, const char *config_file_name, MonoError *error)
540 MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
541 MonoStringHandle base_dir_str = mono_string_new_handle (domain, base_dir, error);
544 MONO_HANDLE_SET (setup, application_base, base_dir_str);
545 MonoStringHandle config_file_name_str = mono_string_new_handle (domain, config_file_name, error);
548 MONO_HANDLE_SET (setup, configuration_file, config_file_name_str);
550 return is_ok (error);
553 static MonoAppDomainSetupHandle
554 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
556 HANDLE_FUNCTION_ENTER ();
557 MonoDomain *caller_domain;
558 MonoClass *ads_class;
559 MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
563 caller_domain = mono_domain_get ();
564 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
566 MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
570 mono_domain_set_internal (domain);
572 #define XCOPY_FIELD(dst,field,src,error) \
574 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
575 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
576 if (!is_ok (error)) \
578 MONO_HANDLE_SET ((dst),field,copied_val); \
581 #define COPY_VAL(dst,field,type,src) \
583 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
586 XCOPY_FIELD (copy, application_base, setup, error);
587 XCOPY_FIELD (copy, application_name, setup, error);
588 XCOPY_FIELD (copy, cache_path, setup, error);
589 XCOPY_FIELD (copy, configuration_file, setup, error);
590 XCOPY_FIELD (copy, dynamic_base, setup, error);
591 XCOPY_FIELD (copy, license_file, setup, error);
592 XCOPY_FIELD (copy, private_bin_path, setup, error);
593 XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
594 XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
595 XCOPY_FIELD (copy, shadow_copy_files, setup, error);
596 COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
597 COPY_VAL (copy, path_changed, MonoBoolean, setup);
598 COPY_VAL (copy, loader_optimization, int, setup);
599 COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
600 COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
601 XCOPY_FIELD (copy, domain_initializer_args, setup, error);
602 COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
603 XCOPY_FIELD (copy, application_trust, setup, error);
604 XCOPY_FIELD (copy, configuration_bytes, setup, error);
605 XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
610 mono_domain_set_internal (caller_domain);
612 MONO_HANDLE_ASSIGN (result, copy);
614 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
617 static MonoAppDomainHandle
618 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
620 HANDLE_FUNCTION_ENTER ();
621 MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
627 adclass = mono_class_get_appdomain_class ();
629 /* FIXME: pin all those objects */
630 data = mono_domain_create();
632 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, mono_object_new_checked (data, adclass, error));
635 MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
636 data->domain = MONO_HANDLE_RAW (ad);
637 data->friendly_name = g_strdup (friendly_name);
639 mono_profiler_appdomain_name (data, data->friendly_name);
641 MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
642 if (MONO_HANDLE_IS_NULL (app_base)) {
643 /* Inherit from the root domain since MS.NET does this */
644 MonoDomain *root = mono_get_root_domain ();
645 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
646 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
647 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
648 /* N.B. new string is in the new domain */
649 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
650 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);
651 mono_gchandle_free (gchandle);
652 if (!is_ok (error)) {
653 g_free (data->friendly_name);
656 MONO_HANDLE_SET (setup, application_base, s);
660 mono_context_init_checked (data, error);
664 data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
665 if (!mono_error_ok (error)) {
666 g_free (data->friendly_name);
670 mono_domain_set_options_from_config (data);
671 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
673 #ifndef DISABLE_SHADOW_COPY
674 /*FIXME, guard this for when the debugger is not running */
675 char *shadow_location = get_shadow_assembly_location_base (data, error);
676 if (!mono_error_ok (error)) {
677 g_free (data->friendly_name);
681 g_free (shadow_location);
684 create_domain_objects (data);
686 MONO_HANDLE_ASSIGN (result, ad);
688 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
692 * mono_domain_has_type_resolve:
693 * \param domain application domain being looked up
695 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
698 mono_domain_has_type_resolve (MonoDomain *domain)
700 static MonoClassField *field = NULL;
704 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
708 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
712 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
717 * mono_domain_try_type_resolve:
718 * \param domain application domainwhere the name where the type is going to be resolved
719 * \param name the name of the type to resolve or NULL.
720 * \param tb A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
722 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
723 * the assembly that matches name.
725 * If \p name is null, the value of \c ((TypeBuilder)tb).FullName is used instead
727 * \returns A \c MonoReflectionAssembly or NULL if not found
729 MonoReflectionAssembly *
730 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
733 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
734 mono_error_cleanup (&error);
739 MonoReflectionAssembly *
740 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
742 static MonoMethod *method = NULL;
743 MonoReflectionAssembly *ret;
748 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
750 if (method == NULL) {
751 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
752 if (method == NULL) {
753 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
759 *params = (MonoObject*)mono_string_new_checked (mono_domain_get (), name, error);
760 return_val_if_nok (error, NULL);
764 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
765 return_val_if_nok (error, NULL);
771 * mono_domain_owns_vtable_slot:
772 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
775 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
779 mono_domain_lock (domain);
780 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
781 mono_domain_unlock (domain);
787 * \param domain domain
788 * \param force force setting.
790 * Set the current appdomain to \p domain. If \p force is set, set it even
791 * if it is being unloaded.
793 * \returns TRUE on success; FALSE if the domain is unloaded
796 mono_domain_set (MonoDomain *domain, gboolean force)
798 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
801 mono_domain_set_internal (domain);
807 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
811 if (MONO_HANDLE_IS_NULL (name)) {
812 mono_error_set_argument_null (error, "name", "");
816 g_assert (!MONO_HANDLE_IS_NULL (ad));
817 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
820 char *str = mono_string_handle_to_utf8 (name, error);
821 return_val_if_nok (error, NULL_HANDLE);
823 mono_domain_lock (add);
825 MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
827 if (!strcmp (str, "APPBASE"))
828 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
829 else if (!strcmp (str, "APP_CONFIG_FILE"))
830 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
831 else if (!strcmp (str, "DYNAMIC_BASE"))
832 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
833 else if (!strcmp (str, "APP_NAME"))
834 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
835 else if (!strcmp (str, "CACHE_BASE"))
836 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
837 else if (!strcmp (str, "PRIVATE_BINPATH"))
838 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
839 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
840 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
841 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
842 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
843 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
844 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
846 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
848 mono_domain_unlock (add);
851 return MONO_HANDLE_CAST (MonoObject, o);
855 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
859 if (MONO_HANDLE_IS_NULL (name)) {
860 mono_error_set_argument_null (error, "name", "");
864 g_assert (!MONO_HANDLE_IS_NULL (ad));
865 MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
868 mono_domain_lock (add);
870 mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
872 mono_domain_unlock (add);
875 MonoAppDomainSetupHandle
876 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
879 g_assert (!MONO_HANDLE_IS_NULL (ad));
880 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
883 return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
887 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
890 g_assert (!MONO_HANDLE_IS_NULL (ad));
891 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
894 return mono_string_new_handle (domain, domain->friendly_name, error);
898 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
901 MonoDomain *add = mono_domain_get ();
903 return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
907 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
910 MonoDomain *root = mono_get_root_domain ();
912 return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
916 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
918 MonoDomain *domain = mono_domain_get ();
920 return domain->throw_unobserved_task_exceptions;
924 get_attribute_value (const gchar **attribute_names,
925 const gchar **attribute_values,
926 const char *att_name)
929 for (n = 0; attribute_names [n] != NULL; n++) {
930 if (strcmp (attribute_names [n], att_name) == 0)
931 return g_strdup (attribute_values [n]);
937 start_element (GMarkupParseContext *context,
938 const gchar *element_name,
939 const gchar **attribute_names,
940 const gchar **attribute_values,
944 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
946 if (strcmp (element_name, "runtime") == 0) {
947 runtime_config->runtime_count++;
951 if (strcmp (element_name, "assemblyBinding") == 0) {
952 runtime_config->assemblybinding_count++;
956 if (runtime_config->runtime_count != 1)
959 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
960 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
962 if (value && g_ascii_strcasecmp (value, "true") == 0)
963 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
966 if (runtime_config->assemblybinding_count != 1)
969 if (strcmp (element_name, "probing") != 0)
972 g_free (runtime_config->domain->private_bin_path);
973 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
974 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
975 g_free (runtime_config->domain->private_bin_path);
976 runtime_config->domain->private_bin_path = NULL;
982 end_element (GMarkupParseContext *context,
983 const gchar *element_name,
987 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
988 if (strcmp (element_name, "runtime") == 0)
989 runtime_config->runtime_count--;
990 else if (strcmp (element_name, "assemblyBinding") == 0)
991 runtime_config->assemblybinding_count--;
995 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
997 RuntimeConfig *state = (RuntimeConfig *)user_data;
999 const gchar *filename;
1001 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
1002 msg = error && error->message ? error->message : "";
1003 g_warning ("Error parsing %s: %s", filename, msg);
1006 static const GMarkupParser
1016 mono_domain_set_options_from_config (MonoDomain *domain)
1019 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
1021 GMarkupParseContext *context;
1022 RuntimeConfig runtime_config;
1025 if (!domain || !domain->setup || !domain->setup->configuration_file)
1028 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
1029 if (!mono_error_ok (&error)) {
1030 mono_error_cleanup (&error);
1034 config_file_path = mono_portability_find_file (config_file_name, TRUE);
1035 if (!config_file_path)
1036 config_file_path = config_file_name;
1038 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1041 runtime_config.runtime_count = 0;
1042 runtime_config.assemblybinding_count = 0;
1043 runtime_config.domain = domain;
1044 runtime_config.filename = config_file_path;
1047 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1048 offset = 3; /* Skip UTF-8 BOM */
1050 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1051 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1052 g_markup_parse_context_end_parse (context, NULL);
1053 g_markup_parse_context_free (context);
1057 if (config_file_name != config_file_path)
1058 g_free (config_file_name);
1059 g_free (config_file_path);
1063 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1066 MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1068 #ifdef DISABLE_APPDOMAINS
1069 mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1073 fname = mono_string_handle_to_utf8 (friendly_name, error);
1074 return_val_if_nok (error, ad);
1075 ad = mono_domain_create_appdomain_internal (fname, setup, error);
1082 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1084 HANDLE_FUNCTION_ENTER ();
1086 MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1089 MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1091 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1095 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1098 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1102 GPtrArray *assemblies;
1105 * Make a copy of the list of assemblies because we can't hold the assemblies
1106 * lock while creating objects etc.
1108 assemblies = g_ptr_array_new ();
1109 /* Need to skip internal assembly builders created by remoting */
1110 mono_domain_assemblies_lock (domain);
1111 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1112 ass = (MonoAssembly *)tmp->data;
1113 if (refonly != ass->ref_only)
1115 if (ass->corlib_internal)
1117 g_ptr_array_add (assemblies, ass);
1119 mono_domain_assemblies_unlock (domain);
1121 MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1124 for (i = 0; i < assemblies->len; ++i) {
1125 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1130 g_ptr_array_free (assemblies, TRUE);
1135 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1137 HANDLE_FUNCTION_ENTER ();
1139 MonoAssembly *result = NULL;
1140 MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1143 result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1145 HANDLE_FUNCTION_RETURN_VAL (result);
1149 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1151 MonoAssembly *ret = NULL;
1153 MonoBoolean isrefonly;
1154 gpointer params [3];
1158 if (mono_runtime_get_no_exec ())
1161 g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1163 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1164 g_assert (method != NULL);
1166 isrefonly = refonly ? 1 : 0;
1167 MonoReflectionAssemblyHandle requesting_handle;
1169 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1170 return_val_if_nok (error, ret);
1172 params [0] = MONO_HANDLE_RAW (fname);
1173 params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1174 params [2] = &isrefonly;
1175 MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1176 ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1181 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1185 MonoAssembly *assembly;
1186 MonoDomain *domain = mono_domain_get ();
1189 aname_str = mono_stringify_assembly_name (aname);
1191 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1193 assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1195 mono_error_cleanup (&error);
1201 * LOCKING: assumes assemblies_lock in the domain is already locked.
1204 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1208 gboolean destroy_ht = FALSE;
1210 if (!ass->aname.name)
1214 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1216 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1217 g_hash_table_insert (ht, tmp->data, tmp->data);
1221 /* FIXME: handle lazy loaded assemblies */
1223 if (!g_hash_table_lookup (ht, ass)) {
1224 mono_assembly_addref (ass);
1225 g_hash_table_insert (ht, ass, ass);
1226 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1227 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);
1230 if (ass->image->references) {
1231 for (i = 0; i < ass->image->nreferences; i++) {
1232 if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1233 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1234 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1240 g_hash_table_destroy (ht);
1244 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1246 static MonoClassField *assembly_load_field;
1247 static MonoMethod *assembly_load_method;
1249 MonoDomain *domain = mono_domain_get ();
1251 gpointer load_value;
1254 if (!domain->domain)
1255 /* This can happen during startup */
1257 #ifdef ASSEMBLY_LOAD_DEBUG
1258 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1260 klass = domain->domain->mbr.obj.vtable->klass;
1262 mono_domain_assemblies_lock (domain);
1263 add_assemblies_to_domain (domain, assembly, NULL);
1264 mono_domain_assemblies_unlock (domain);
1266 if (assembly_load_field == NULL) {
1267 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1268 g_assert (assembly_load_field);
1271 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1272 if (load_value == NULL) {
1273 /* No events waiting to be triggered */
1277 MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1278 mono_error_assert_ok (&error);
1280 if (assembly_load_method == NULL) {
1281 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1282 g_assert (assembly_load_method);
1285 *params = MONO_HANDLE_RAW(ref_assembly);
1287 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1288 mono_error_cleanup (&error);
1292 * LOCKING: Acquires the domain assemblies lock.
1295 set_domain_search_path (MonoDomain *domain)
1298 MonoAppDomainSetup *setup;
1300 gchar *search_path = NULL;
1303 gchar **pvt_split = NULL;
1304 GError *gerror = NULL;
1305 gint appbaselen = -1;
1308 * We use the low-level domain assemblies lock, since this is called from
1309 * assembly loads hooks, which means this thread might hold the loader lock.
1311 mono_domain_assemblies_lock (domain);
1313 if (!domain->setup) {
1314 mono_domain_assemblies_unlock (domain);
1318 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1319 mono_domain_assemblies_unlock (domain);
1322 setup = domain->setup;
1323 if (!setup->application_base) {
1324 mono_domain_assemblies_unlock (domain);
1325 return; /* Must set application base to get private path working */
1330 if (setup->private_bin_path) {
1331 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1332 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1333 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1334 mono_error_cleanup (&error);
1335 mono_domain_assemblies_unlock (domain);
1340 if (domain->private_bin_path) {
1341 if (search_path == NULL)
1342 search_path = domain->private_bin_path;
1344 gchar *tmp2 = search_path;
1345 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1352 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1353 * directories relative to ApplicationBase separated by semicolons (see
1354 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1355 * The loop below copes with the fact that some Unix applications may use ':' (or
1356 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1357 * ';' for the subsequent split.
1359 * The issue was reported in bug #81446
1362 #ifndef TARGET_WIN32
1365 slen = strlen (search_path);
1366 for (i = 0; i < slen; i++)
1367 if (search_path [i] == ':')
1368 search_path [i] = ';';
1371 pvt_split = g_strsplit (search_path, ";", 1000);
1372 g_free (search_path);
1373 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1378 g_strfreev (pvt_split);
1380 * Don't do this because the first time is called, the domain
1381 * setup is not finished.
1383 * domain->search_path = g_malloc (sizeof (char *));
1384 * domain->search_path [0] = NULL;
1386 mono_domain_assemblies_unlock (domain);
1390 if (domain->search_path)
1391 g_strfreev (domain->search_path);
1393 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1394 tmp [npaths] = NULL;
1396 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1397 if (!mono_error_ok (&error)) {
1398 mono_error_cleanup (&error);
1399 g_strfreev (pvt_split);
1402 mono_domain_assemblies_unlock (domain);
1406 domain->search_path = tmp;
1408 /* FIXME: is this needed? */
1409 if (strncmp (*tmp, "file://", 7) == 0) {
1415 uri = g_strdup_printf ("file:///%s", uri + 7);
1418 uri = mono_escape_uri_string (tmpuri);
1419 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1425 if (gerror != NULL) {
1426 g_warning ("%s\n", gerror->message);
1427 g_error_free (gerror);
1434 for (i = 1; pvt_split && i < npaths; i++) {
1435 if (g_path_is_absolute (pvt_split [i - 1])) {
1436 tmp [i] = g_strdup (pvt_split [i - 1]);
1438 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1441 if (strchr (tmp [i], '.')) {
1445 reduced = mono_path_canonicalize (tmp [i]);
1446 if (appbaselen == -1)
1447 appbaselen = strlen (tmp [0]);
1449 if (strncmp (tmp [0], reduced, appbaselen)) {
1452 tmp [i] = g_strdup ("");
1462 if (setup->private_bin_path_probe != NULL) {
1464 tmp [0] = g_strdup ("");
1467 domain->setup->path_changed = FALSE;
1469 g_strfreev (pvt_split);
1471 mono_domain_assemblies_unlock (domain);
1474 #ifdef DISABLE_SHADOW_COPY
1476 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1482 mono_make_shadow_copy (const char *filename, MonoError *error)
1485 return (char *) filename;
1489 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1491 guint16 *orig, *dest;
1492 gboolean copy_result;
1495 strcpy (src + srclen - tail_len, extension);
1497 if (IS_PORTABILITY_CASE) {
1498 gchar *file = mono_portability_find_file (src, TRUE);
1504 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1508 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1510 strcpy (target + targetlen - tail_len, extension);
1511 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1513 mono_w32file_delete (dest);
1515 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1517 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1518 * overwritten when updated in their original locations. */
1520 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1529 get_cstring_hash (const char *str)
1535 if (!str || !str [0])
1540 for (i = 0; i < len; i++) {
1541 h = (h << 5) - h + *p;
1549 * Returned memory is malloc'd. Called must free it
1552 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1554 MonoAppDomainSetup *setup;
1555 char *cache_path, *appname;
1561 setup = domain->setup;
1562 if (setup->cache_path != NULL && setup->application_name != NULL) {
1563 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1564 return_val_if_nok (error, NULL);
1566 #ifndef TARGET_WIN32
1569 for (i = strlen (cache_path) - 1; i >= 0; i--)
1570 if (cache_path [i] == '\\')
1571 cache_path [i] = '/';
1575 appname = mono_string_to_utf8_checked (setup->application_name, error);
1576 if (!mono_error_ok (error)) {
1577 g_free (cache_path);
1581 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1583 g_free (cache_path);
1585 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1586 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1593 get_shadow_assembly_location (const char *filename, MonoError *error)
1595 gint32 hash = 0, hash2 = 0;
1597 char path_hash [30];
1598 char *bname = g_path_get_basename (filename);
1599 char *dirname = g_path_get_dirname (filename);
1600 char *location, *tmploc;
1601 MonoDomain *domain = mono_domain_get ();
1605 hash = get_cstring_hash (bname);
1606 hash2 = get_cstring_hash (dirname);
1607 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1608 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1609 tmploc = get_shadow_assembly_location_base (domain, error);
1610 if (!mono_error_ok (error)) {
1616 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1624 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1626 struct stat sbuf_dest;
1628 gchar *real_src = mono_portability_find_file (src, TRUE);
1631 stat_src = (gchar*)src;
1633 stat_src = real_src;
1635 if (stat (stat_src, sbuf_src) == -1) {
1636 time_t tnow = time (NULL);
1641 memset (sbuf_src, 0, sizeof (*sbuf_src));
1642 sbuf_src->st_mtime = tnow;
1643 sbuf_src->st_atime = tnow;
1650 if (stat (dest, &sbuf_dest) == -1)
1653 if (sbuf_src->st_size == sbuf_dest.st_size &&
1654 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1661 shadow_copy_create_ini (const char *shadow, const char *filename)
1671 dir_name = g_path_get_dirname (shadow);
1672 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1674 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1679 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1684 handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1686 if (handle == INVALID_HANDLE_VALUE) {
1690 full_path = mono_path_resolve_symlinks (filename);
1691 result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1693 mono_w32file_close (handle);
1698 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1701 MonoAppDomainSetup *setup;
1704 gchar **directories;
1705 gchar *shadow_status_string;
1707 gboolean shadow_enabled;
1708 gboolean found = FALSE;
1713 setup = domain->setup;
1714 if (setup == NULL || setup->shadow_copy_files == NULL)
1717 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1718 if (!mono_error_ok (&error)) {
1719 mono_error_cleanup (&error);
1722 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1723 g_free (shadow_status_string);
1725 if (!shadow_enabled)
1728 if (setup->shadow_copy_directories == NULL)
1731 /* Is dir_name a shadow_copy destination already? */
1732 base_dir = get_shadow_assembly_location_base (domain, &error);
1733 if (!mono_error_ok (&error)) {
1734 mono_error_cleanup (&error);
1738 if (strstr (dir_name, base_dir)) {
1744 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1745 if (!mono_error_ok (&error)) {
1746 mono_error_cleanup (&error);
1750 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1751 dir_ptr = directories;
1753 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1759 g_strfreev (directories);
1765 This function raises exceptions so it can cause as sorts of nasty stuff if called
1766 while holding a lock.
1767 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1768 or NULL if source file not found.
1769 FIXME bubble up the error instead of raising it here
1772 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1775 gchar *sibling_source, *sibling_target;
1776 gint sibling_source_len, sibling_target_len;
1777 guint16 *orig, *dest;
1780 gboolean copy_result;
1781 struct stat src_sbuf;
1782 struct utimbuf utbuf;
1783 char *dir_name = g_path_get_dirname (filename);
1784 MonoDomain *domain = mono_domain_get ();
1788 error_init (oerror);
1790 set_domain_search_path (domain);
1792 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1794 return (char *) filename;
1797 /* Is dir_name a shadow_copy destination already? */
1798 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1799 if (!mono_error_ok (&error)) {
1800 mono_error_cleanup (&error);
1802 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1806 if (strstr (dir_name, shadow_dir)) {
1807 g_free (shadow_dir);
1809 return (char *) filename;
1811 g_free (shadow_dir);
1814 shadow = get_shadow_assembly_location (filename, &error);
1815 if (!mono_error_ok (&error)) {
1816 mono_error_cleanup (&error);
1817 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1821 if (g_ensure_directory_exists (shadow) == FALSE) {
1823 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1827 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1828 return (char*) shadow;
1830 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1831 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1832 mono_w32file_delete (dest);
1834 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1835 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1836 * and not have it runtime error" */
1837 attrs = mono_w32file_get_attributes (orig);
1838 if (attrs == INVALID_FILE_ATTRIBUTES) {
1840 return (char *)filename;
1843 copy_result = mono_w32file_copy (orig, dest, TRUE, ©_error);
1845 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1846 * overwritten when updated in their original locations. */
1848 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1853 if (copy_result == FALSE) {
1856 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1857 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1858 return NULL; /* file not found, shadow copy failed */
1860 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1864 /* attempt to copy .mdb, .config if they exist */
1865 sibling_source = g_strconcat (filename, ".config", NULL);
1866 sibling_source_len = strlen (sibling_source);
1867 sibling_target = g_strconcat (shadow, ".config", NULL);
1868 sibling_target_len = strlen (sibling_target);
1870 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1872 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".pdb", sibling_target, sibling_target_len, 11);
1874 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1876 g_free (sibling_source);
1877 g_free (sibling_target);
1881 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1885 /* Create a .ini file containing the original assembly location */
1886 if (!shadow_copy_create_ini (shadow, filename)) {
1888 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1892 utbuf.actime = src_sbuf.st_atime;
1893 utbuf.modtime = src_sbuf.st_mtime;
1894 utime (shadow, &utbuf);
1898 #endif /* DISABLE_SHADOW_COPY */
1901 * mono_domain_from_appdomain:
1904 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1906 HANDLE_FUNCTION_ENTER ();
1907 MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1908 MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1909 HANDLE_FUNCTION_RETURN_VAL (result);
1913 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1915 HANDLE_FUNCTION_ENTER ();
1916 MonoDomain *dom = NULL;
1917 if (MONO_HANDLE_IS_NULL (appdomain))
1920 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1921 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1922 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1924 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1926 dom = MONO_HANDLE_GETVAL (appdomain, data);
1929 HANDLE_FUNCTION_RETURN_VAL (dom);
1934 try_load_from (MonoAssembly **assembly,
1935 const gchar *path1, const gchar *path2,
1936 const gchar *path3, const gchar *path4,
1937 gboolean refonly, gboolean is_private,
1938 MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1941 gboolean found = FALSE;
1944 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1946 if (IS_PORTABILITY_SET) {
1947 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1950 fullpath = new_fullpath;
1954 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1957 *assembly = mono_assembly_open_predicate (fullpath, refonly, FALSE, predicate, user_data, NULL);
1960 return (*assembly != NULL);
1963 static MonoAssembly *
1964 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly, MonoAssemblyCandidatePredicate predicate, gpointer user_data)
1966 MonoAssembly *result = NULL;
1969 const gchar *local_culture;
1971 gboolean is_private = FALSE;
1973 if (!culture || *culture == '\0') {
1976 local_culture = culture;
1979 filename = g_strconcat (name, ".dll", NULL);
1980 len = strlen (filename);
1982 for (path = search_path; *path; path++) {
1983 if (**path == '\0') {
1985 continue; /* Ignore empty ApplicationBase */
1988 /* See test cases in bug #58992 and bug #57710 */
1989 /* 1st try: [culture]/[name].dll (culture may be empty) */
1990 strcpy (filename + len - 4, ".dll");
1991 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1994 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1995 strcpy (filename + len - 4, ".exe");
1996 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private, predicate, user_data))
1999 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2000 strcpy (filename + len - 4, ".dll");
2001 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2004 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2005 strcpy (filename + len - 4, ".exe");
2006 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private, predicate, user_data))
2015 * Try loading the assembly from ApplicationBase and PrivateBinPath
2016 * and then from assemblies_path if any.
2017 * LOCKING: This is called from the assembly loading code, which means the caller
2018 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2020 static MonoAssembly *
2021 mono_domain_assembly_preload (MonoAssemblyName *aname,
2022 gchar **assemblies_path,
2025 MonoDomain *domain = mono_domain_get ();
2026 MonoAssembly *result = NULL;
2027 gboolean refonly = GPOINTER_TO_UINT (user_data);
2029 set_domain_search_path (domain);
2031 MonoAssemblyCandidatePredicate predicate = NULL;
2032 void* predicate_ud = NULL;
2033 #if !defined(DISABLE_DESKTOP_LOADER)
2034 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2035 predicate = &mono_assembly_candidate_predicate_sn_same_name;
2036 predicate_ud = aname;
2039 if (domain->search_path && domain->search_path [0] != NULL) {
2040 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY)) {
2041 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Domain %s search path is:", domain->friendly_name);
2042 for (int i = 0; domain->search_path [i]; i++) {
2043 const char *p = domain->search_path[i];
2044 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "\tpath[%d] = '%s'", i, p);
2046 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "End of domain %s search path.", domain->friendly_name);
2048 result = real_load (domain->search_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2051 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
2052 result = real_load (assemblies_path, aname->culture, aname->name, refonly, predicate, predicate_ud);
2059 * Check whenever a given assembly was already loaded in the current appdomain.
2061 static MonoAssembly *
2062 mono_domain_assembly_search (MonoAssemblyName *aname,
2065 MonoDomain *domain = mono_domain_get ();
2068 gboolean refonly = GPOINTER_TO_UINT (user_data);
2070 mono_domain_assemblies_lock (domain);
2071 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2072 ass = (MonoAssembly *)tmp->data;
2073 /* Dynamic assemblies can't match here in MS.NET */
2074 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2077 mono_domain_assemblies_unlock (domain);
2080 mono_domain_assemblies_unlock (domain);
2085 MonoReflectionAssemblyHandle
2086 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2089 MonoDomain *domain = mono_domain_get ();
2090 char *name, *filename;
2091 MonoImageOpenStatus status = MONO_IMAGE_OK;
2092 MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2097 if (fname == NULL) {
2098 mono_error_set_argument_null (error, "assemblyFile", "");
2102 name = filename = mono_string_handle_to_utf8 (fname, error);
2106 MonoAssembly *ass = mono_assembly_open_predicate (filename, refOnly, TRUE, NULL, NULL, &status);
2109 if (status == MONO_IMAGE_IMAGE_INVALID)
2110 mono_error_set_bad_image_name (error, g_strdup (name), "");
2112 mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2116 result = mono_assembly_get_object_handle (domain, ass, error);
2123 MonoReflectionAssemblyHandle
2124 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad,
2125 MonoArrayHandle raw_assembly,
2126 MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2127 MonoBoolean refonly,
2132 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2133 MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2134 MonoImageOpenStatus status;
2135 guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2137 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2138 char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2139 if (!assembly_data) {
2140 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2144 mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2145 memcpy (assembly_data, raw_data, raw_assembly_len);
2146 mono_gchandle_free (gchandle); /* unpin */
2147 MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2149 MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2152 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2156 if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2157 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2158 uint32_t symbol_gchandle;
2159 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2160 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2161 mono_gchandle_free (symbol_gchandle);
2164 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2168 mono_image_close (image);
2169 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2173 refass = mono_assembly_get_object_handle (domain, ass, error);
2174 if (!MONO_HANDLE_IS_NULL(refass))
2175 MONO_HANDLE_SET (refass, evidence, evidence);
2179 MonoReflectionAssemblyHandle
2180 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2183 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2184 MonoImageOpenStatus status = MONO_IMAGE_OK;
2186 MonoAssemblyName aname;
2192 name = mono_string_handle_to_utf8 (assRef, error);
2195 parsed = mono_assembly_name_parse (name, &aname);
2199 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2200 /* This is a parse error... */
2202 MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2206 refass = mono_assembly_get_object_handle (domain, assm, error);
2214 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2215 mono_assembly_name_free (&aname);
2218 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2220 ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2229 MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2233 MONO_HANDLE_SET (refass, evidence, evidence);
2237 return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2241 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2244 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2246 if (NULL == domain) {
2247 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2251 if (domain == mono_get_root_domain ()) {
2252 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2257 * Unloading seems to cause problems when running NUnit/NAnt, hence
2260 if (g_hasenv ("MONO_NO_UNLOAD"))
2263 #ifdef __native_client__
2267 MonoException *exc = NULL;
2268 mono_domain_try_unload (domain, (MonoObject**)&exc);
2270 mono_error_set_exception_instance (error, exc);
2274 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2277 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2282 return mono_domain_is_unloading (domain);
2286 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc, MonoError *error)
2289 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject, exc), error);
2290 mono_error_assert_ok (error);
2294 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2295 MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2302 g_assert (!MONO_HANDLE_IS_NULL (refass));
2303 MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2304 image = assembly->image;
2307 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2310 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2312 if (MONO_HANDLE_IS_NULL (args)) {
2313 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2314 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2315 mono_error_assert_ok (error);
2318 int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2323 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2325 return ad->data->domain_id;
2329 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2332 MonoDomain *old_domain = mono_domain_get ();
2334 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2335 mono_error_set_appdomain_unloaded (error);
2336 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2339 return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2343 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2345 MonoDomain *current_domain = mono_domain_get ();
2346 MonoDomain *domain = mono_domain_get_by_id (domainid);
2348 if (!domain || !mono_domain_set (domain, FALSE)) {
2349 mono_error_set_appdomain_unloaded (error);
2350 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2353 return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2357 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2360 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2364 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2367 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2371 * Raise an exception to prevent the managed code from executing a pop
2374 mono_error_set_appdomain_unloaded (error);
2378 mono_thread_push_appdomain_ref (domain);
2382 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2385 mono_thread_pop_appdomain_ref ();
2388 MonoAppContextHandle
2389 ves_icall_System_AppDomain_InternalGetContext (MonoError *error)
2392 return mono_context_get_handle ();
2395 MonoAppContextHandle
2396 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError *error)
2399 return MONO_HANDLE_NEW (MonoAppContext, mono_domain_get ()->default_context);
2402 MonoAppContextHandle
2403 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc, MonoError *error)
2406 MonoAppContextHandle old_context = mono_context_get_handle ();
2408 mono_context_set_handle (mc);
2414 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2417 MonoDomain* mono_root_domain = mono_get_root_domain ();
2418 mono_domain_lock (mono_root_domain);
2419 if (process_guid_set) {
2420 mono_domain_unlock (mono_root_domain);
2421 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2423 uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2424 memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2425 mono_gchandle_free (gchandle);
2426 process_guid_set = TRUE;
2427 mono_domain_unlock (mono_root_domain);
2432 * mono_domain_is_unloading:
2435 mono_domain_is_unloading (MonoDomain *domain)
2437 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2444 clear_cached_vtable (MonoVTable *vtable)
2446 MonoClass *klass = vtable->klass;
2447 MonoDomain *domain = vtable->domain;
2448 MonoClassRuntimeInfo *runtime_info;
2451 runtime_info = klass->runtime_info;
2452 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2453 runtime_info->domain_vtables [domain->domain_id] = NULL;
2454 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2455 mono_gc_free_fixed (data);
2458 static G_GNUC_UNUSED void
2459 zero_static_data (MonoVTable *vtable)
2461 MonoClass *klass = vtable->klass;
2464 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2465 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2468 typedef struct unload_data {
2471 char *failure_reason;
2476 unload_data_unref (unload_data *data)
2480 mono_atomic_load_acquire (count, gint32, &data->refcount);
2481 g_assert (count >= 1 && count <= 2);
2486 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2490 deregister_reflection_info_roots_from_list (MonoImage *image)
2492 GSList *list = image->reflection_info_unregister_classes;
2495 MonoClass *klass = (MonoClass *)list->data;
2497 mono_class_free_ref_info (klass);
2502 image->reflection_info_unregister_classes = NULL;
2506 deregister_reflection_info_roots (MonoDomain *domain)
2510 mono_domain_assemblies_lock (domain);
2511 for (list = domain->domain_assemblies; list; list = list->next) {
2512 MonoAssembly *assembly = (MonoAssembly *)list->data;
2513 MonoImage *image = assembly->image;
2517 * No need to take the image lock here since dynamic images are appdomain bound and
2518 * at this point the mutator is gone. Taking the image lock here would mean
2519 * promoting it from a simple lock to a complex lock, which we better avoid if
2522 if (image_is_dynamic (image))
2523 deregister_reflection_info_roots_from_list (image);
2525 for (i = 0; i < image->module_count; ++i) {
2526 MonoImage *module = image->modules [i];
2527 if (module && image_is_dynamic (module))
2528 deregister_reflection_info_roots_from_list (module);
2531 mono_domain_assemblies_unlock (domain);
2535 unload_thread_main (void *arg)
2538 unload_data *data = (unload_data*)arg;
2539 MonoDomain *domain = data->domain;
2540 MonoInternalThread *internal;
2543 internal = mono_thread_internal_current ();
2545 MonoString *thread_name_str = mono_string_new_checked (mono_domain_get (), "Domain unloader", &error);
2547 mono_thread_set_name_internal (internal, thread_name_str, TRUE, FALSE, &error);
2548 if (!is_ok (&error)) {
2549 data->failure_reason = g_strdup (mono_error_get_message (&error));
2550 mono_error_cleanup (&error);
2555 * FIXME: Abort our parent thread last, so we can return a failure
2556 * indication if aborting times out.
2558 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2559 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2563 if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2564 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2568 /* Finalize all finalizable objects in the doomed appdomain */
2569 if (!mono_domain_finalize (domain, -1)) {
2570 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2574 /* Clear references to our vtables in class->runtime_info.
2575 * We also hold the loader lock because we're going to change
2576 * class->runtime_info.
2579 mono_loader_lock (); //FIXME why do we need the loader lock here?
2580 mono_domain_lock (domain);
2583 * We need to make sure that we don't have any remsets
2584 * pointing into static data of the to-be-freed domain because
2585 * at the next collections they would be invalid. So what we
2586 * do is we first zero all static data and then do a minor
2587 * collection. Because all references in the static data will
2588 * now be null we won't do any unnecessary copies and after
2589 * the collection there won't be any more remsets.
2591 for (i = 0; i < domain->class_vtable_array->len; ++i)
2592 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2593 mono_gc_collect (0);
2595 for (i = 0; i < domain->class_vtable_array->len; ++i)
2596 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2597 deregister_reflection_info_roots (domain);
2599 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2601 mono_domain_unlock (domain);
2602 mono_loader_unlock ();
2604 domain->state = MONO_APPDOMAIN_UNLOADED;
2606 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2608 /* remove from the handle table the items related to this domain */
2609 mono_gchandle_free_domain (domain);
2611 mono_domain_free (domain, FALSE);
2613 mono_gc_collect (mono_gc_max_generation ());
2615 mono_atomic_store_release (&data->done, TRUE);
2616 unload_data_unref (data);
2620 mono_atomic_store_release (&data->done, TRUE);
2621 unload_data_unref (data);
2626 * mono_domain_unload:
2627 * \param domain The domain to unload
2629 * Unloads an appdomain. Follows the process outlined in the comment
2630 * for \c mono_domain_try_unload.
2633 mono_domain_unload (MonoDomain *domain)
2635 MonoObject *exc = NULL;
2636 mono_domain_try_unload (domain, &exc);
2639 static MonoThreadInfoWaitRet
2640 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2642 MonoThreadInfoWaitRet result;
2645 result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2652 * mono_domain_unload:
2653 * \param domain The domain to unload
2654 * \param exc Exception information
2656 * Unloads an appdomain. Follows the process outlined in:
2657 * http://blogs.gotdotnet.com/cbrumme
2659 * If doing things the 'right' way is too hard or complex, we do it the
2660 * 'simple' way, which means do everything needed to avoid crashes and
2661 * memory leaks, but not much else.
2663 * It is required to pass a valid reference to the exc argument, upon return
2664 * from this function *exc will be set to the exception thrown, if any.
2666 * If this method is not called from an icall (embedded scenario for instance),
2667 * it must not be called with any managed frames on the stack, since the unload
2668 * process could end up trying to abort the current thread.
2671 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2674 MonoThreadHandle *thread_handle;
2675 MonoAppDomainState prev_state;
2677 unload_data *thread_data;
2678 MonoInternalThread *internal;
2679 MonoDomain *caller_domain = mono_domain_get ();
2681 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2683 /* Atomically change our state to UNLOADING */
2684 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2685 MONO_APPDOMAIN_UNLOADING_START,
2686 MONO_APPDOMAIN_CREATED);
2687 if (prev_state != MONO_APPDOMAIN_CREATED) {
2688 switch (prev_state) {
2689 case MONO_APPDOMAIN_UNLOADING_START:
2690 case MONO_APPDOMAIN_UNLOADING:
2691 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2693 case MONO_APPDOMAIN_UNLOADED:
2694 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2697 g_warning ("Invalid appdomain state %d", prev_state);
2698 g_assert_not_reached ();
2702 mono_domain_set (domain, FALSE);
2703 /* Notify OnDomainUnload listeners */
2704 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2707 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2709 if (!mono_error_ok (&error)) {
2711 mono_error_cleanup (&error);
2713 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2717 /* Roll back the state change */
2718 domain->state = MONO_APPDOMAIN_CREATED;
2719 mono_domain_set (caller_domain, FALSE);
2722 mono_domain_set (caller_domain, FALSE);
2724 thread_data = g_new0 (unload_data, 1);
2725 thread_data->domain = domain;
2726 thread_data->failure_reason = NULL;
2727 thread_data->done = FALSE;
2728 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2730 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2731 domain->state = MONO_APPDOMAIN_UNLOADING;
2733 * First we create a separate thread for unloading, since
2734 * we might have to abort some threads, including the current one.
2736 * Have to attach to the runtime so shutdown can wait for this thread.
2738 * Force it to be attached to avoid racing during shutdown.
2740 internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2741 mono_error_assert_ok (&error);
2743 thread_handle = mono_threads_open_thread_handle (internal->handle);
2745 /* Wait for the thread */
2746 while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2747 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2748 /* The unload thread tries to abort us */
2749 /* The icall wrapper will execute the abort */
2750 mono_threads_close_thread_handle (thread_handle);
2751 unload_data_unref (thread_data);
2756 mono_threads_close_thread_handle (thread_handle);
2758 if (thread_data->failure_reason) {
2759 /* Roll back the state change */
2760 domain->state = MONO_APPDOMAIN_CREATED;
2762 g_warning ("%s", thread_data->failure_reason);
2764 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2766 g_free (thread_data->failure_reason);
2767 thread_data->failure_reason = NULL;
2770 unload_data_unref (thread_data);