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/class-init.h>
41 #include <mono/metadata/domain-internals.h>
42 #include "mono/metadata/metadata-internals.h"
43 #include <mono/metadata/assembly-internals.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/exception-internals.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/marshal-internals.h>
52 #include <mono/metadata/monitor.h>
53 #include <mono/metadata/mono-debug.h>
54 #include <mono/metadata/attach.h>
55 #include <mono/metadata/w32file.h>
56 #include <mono/metadata/lock-tracer.h>
57 #include <mono/metadata/console-io.h>
58 #include <mono/metadata/threads-types.h>
59 #include <mono/metadata/tokentype.h>
60 #include <mono/metadata/profiler-private.h>
61 #include <mono/metadata/reflection-internals.h>
62 #include <mono/metadata/abi-details.h>
63 #include <mono/metadata/w32socket.h>
64 #include <mono/utils/mono-uri.h>
65 #include <mono/utils/mono-logger-internals.h>
66 #include <mono/utils/mono-path.h>
67 #include <mono/utils/mono-stdlib.h>
68 #include <mono/utils/mono-io-portability.h>
69 #include <mono/utils/mono-error-internals.h>
70 #include <mono/utils/atomic.h>
71 #include <mono/utils/mono-memory-model.h>
72 #include <mono/utils/mono-threads.h>
73 #include <mono/metadata/w32handle.h>
74 #include <mono/metadata/w32error.h>
75 #include <mono/utils/w32api.h>
83 int assemblybinding_count
;
88 static gunichar2 process_guid
[36];
89 static gboolean process_guid_set
= FALSE
;
91 static gboolean no_exec
= FALSE
;
94 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
95 gchar
**assemblies_path
,
99 mono_domain_assembly_search (MonoAssemblyName
*aname
,
103 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
);
106 mono_domain_asmctx_from_path (const char *fname
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
);
109 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*hash
);
111 static MonoAppDomainHandle
112 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetupHandle setup
, MonoError
*error
);
115 mono_domain_create_appdomain_checked (char *friendly_name
, char *configuration_file
, MonoError
*error
);
119 mono_context_set_default_context (MonoDomain
*domain
);
122 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
);
124 static MonoLoadFunc load_function
= NULL
;
126 /* Lazy class loading functions */
127 static GENERATE_GET_CLASS_WITH_CACHE (assembly
, "System.Reflection", "Assembly");
129 static GENERATE_GET_CLASS_WITH_CACHE (appdomain
, "System", "AppDomain");
132 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain
);
135 mono_error_set_appdomain_unloaded (MonoError
*error
)
137 mono_error_set_generic_error (error
, "System", "AppDomainUnloadedException", "");
141 mono_install_runtime_load (MonoLoadFunc func
)
143 load_function
= func
;
147 mono_runtime_load (const char *filename
, const char *runtime_version
)
149 g_assert (load_function
);
150 return load_function (filename
, runtime_version
);
154 * mono_runtime_set_no_exec:
156 * Instructs the runtime to operate in static mode, i.e. avoid/do not
157 * allow managed code execution. This is useful for running the AOT
158 * compiler on platforms which allow full-aot execution only. This
159 * should be called before mono_runtime_init ().
162 mono_runtime_set_no_exec (gboolean val
)
168 * mono_runtime_get_no_exec:
170 * If true, then the runtime will not allow managed code execution.
173 mono_runtime_get_no_exec (void)
179 create_domain_objects (MonoDomain
*domain
)
182 MonoDomain
*old_domain
= mono_domain_get ();
184 MonoVTable
*string_vt
;
185 MonoClassField
*string_empty_fld
;
187 if (domain
!= old_domain
) {
188 mono_thread_push_appdomain_ref (domain
);
189 mono_domain_set_internal_with_options (domain
, FALSE
);
193 * Initialize String.Empty. This enables the removal of
194 * the static cctor of the String class.
196 string_vt
= mono_class_vtable_checked (domain
, mono_defaults
.string_class
, error
);
197 mono_error_assert_ok (error
);
198 string_empty_fld
= mono_class_get_field_from_name (mono_defaults
.string_class
, "Empty");
199 g_assert (string_empty_fld
);
200 MonoString
*empty_str
= mono_string_new_checked (domain
, "", error
);
201 mono_error_assert_ok (error
);
202 empty_str
= mono_string_intern_checked (empty_str
, error
);
203 mono_error_assert_ok (error
);
204 mono_field_static_set_value (string_vt
, string_empty_fld
, empty_str
);
205 domain
->empty_string
= empty_str
;
208 * Create an instance early since we can't do it when there is no memory.
210 arg
= mono_string_new_checked (domain
, "Out of memory", error
);
211 mono_error_assert_ok (error
);
212 domain
->out_of_memory_ex
= mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "OutOfMemoryException", arg
, NULL
, error
);
213 mono_error_assert_ok (error
);
216 * These two are needed because the signal handlers might be executing on
217 * an alternate stack, and Boehm GC can't handle that.
219 arg
= mono_string_new_checked (domain
, "A null value was found where an object instance was required", error
);
220 mono_error_assert_ok (error
);
221 domain
->null_reference_ex
= mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "NullReferenceException", arg
, NULL
, error
);
222 mono_error_assert_ok (error
);
223 arg
= mono_string_new_checked (domain
, "The requested operation caused a stack overflow.", error
);
224 mono_error_assert_ok (error
);
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_class_create_array (mono_defaults
.int_class
, 1));
246 * \param domain domain returned by \c 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 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
253 * we know the \c 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
);
286 mono_install_assembly_asmctx_from_path_hook (mono_domain_asmctx_from_path
, NULL
);
288 mono_thread_init (start_cb
, attach_cb
);
290 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
291 setup
= (MonoAppDomainSetup
*) mono_object_new_pinned (domain
, klass
, error
);
292 return_if_nok (error
);
294 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomain");
296 ad
= (MonoAppDomain
*) mono_object_new_pinned (domain
, klass
, error
);
297 return_if_nok (error
);
301 domain
->setup
= setup
;
303 mono_thread_attach (domain
);
305 mono_type_initialization_init ();
307 if (!mono_runtime_get_no_exec ())
308 create_domain_objects (domain
);
310 /* GC init has to happen after thread init */
313 /* contexts use GC handles, so they must be initialized after the GC */
314 mono_context_init_checked (domain
, error
);
315 return_if_nok (error
);
316 mono_context_set_default_context (domain
);
318 #ifndef DISABLE_SOCKETS
319 mono_network_init ();
322 mono_console_init ();
325 mono_locks_tracer_init ();
327 /* mscorlib is loaded before we install the load hook */
328 mono_domain_fire_assembly_load (mono_defaults
.corlib
->assembly
, NULL
);
334 mono_context_set_default_context (MonoDomain
*domain
)
336 HANDLE_FUNCTION_ENTER ();
337 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext
, domain
->default_context
));
338 HANDLE_FUNCTION_RETURN ();
343 mono_get_corlib_version (void)
347 MonoClassField
*field
;
350 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "Environment");
351 mono_class_init (klass
);
352 field
= mono_class_get_field_from_name (klass
, "mono_corlib_version");
355 if (! (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
357 value
= mono_field_get_value_object_checked (mono_domain_get (), field
, NULL
, error
);
358 mono_error_assert_ok (error
);
359 return *(gint32
*)((gchar
*)value
+ sizeof (MonoObject
));
363 * mono_check_corlib_version:
364 * Checks that the corlib that is loaded matches the version of this runtime.
365 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
366 * allocated string with the error otherwise.
369 mono_check_corlib_version (void)
371 int version
= mono_get_corlib_version ();
372 if (version
!= MONO_CORLIB_VERSION
)
373 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION
, version
);
375 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
376 guint32 native_offset
= (guint32
) MONO_STRUCT_OFFSET (MonoInternalThread
, last
);
377 guint32 managed_offset
= mono_field_get_offset (mono_class_get_field_from_name (mono_defaults
.internal_thread_class
, "last"));
378 if (native_offset
!= managed_offset
)
379 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset
, managed_offset
);
386 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
387 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
390 mono_context_init (MonoDomain
*domain
)
393 mono_context_init_checked (domain
, error
);
394 mono_error_cleanup (error
);
398 mono_context_init_checked (MonoDomain
*domain
, MonoError
*error
)
401 MonoAppContext
*context
;
405 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Contexts", "Context");
406 context
= (MonoAppContext
*) mono_object_new_pinned (domain
, klass
, error
);
407 return_if_nok (error
);
409 context
->domain_id
= domain
->domain_id
;
410 context
->context_id
= 0;
411 mono_threads_register_app_context (context
, error
);
412 mono_error_assert_ok (error
);
413 domain
->default_context
= context
;
417 * mono_runtime_cleanup:
418 * \param domain unused.
422 * This must not be called while there are still running threads executing
426 mono_runtime_cleanup (MonoDomain
*domain
)
428 mono_attach_cleanup ();
430 /* This ends up calling any pending pending (for at most 2 seconds) */
433 mono_thread_cleanup ();
435 #ifndef DISABLE_SOCKETS
436 mono_network_cleanup ();
438 mono_marshal_cleanup ();
440 mono_type_initialization_cleanup ();
442 mono_monitor_cleanup ();
445 static MonoDomainFunc quit_function
= NULL
;
448 * mono_install_runtime_cleanup:
451 mono_install_runtime_cleanup (MonoDomainFunc func
)
453 quit_function
= func
;
462 if (quit_function
!= NULL
)
463 quit_function (mono_get_root_domain (), NULL
);
467 * mono_domain_create_appdomain:
468 * \param friendly_name The friendly name of the appdomain to create
469 * \param configuration_file The configuration file to initialize the appdomain with
470 * \returns a \c MonoDomain initialized with the appdomain
473 mono_domain_create_appdomain (char *friendly_name
, char *configuration_file
)
475 HANDLE_FUNCTION_ENTER ();
477 MonoDomain
*domain
= mono_domain_create_appdomain_checked (friendly_name
, configuration_file
, error
);
478 mono_error_cleanup (error
);
479 HANDLE_FUNCTION_RETURN_VAL (domain
);
483 * mono_domain_create_appdomain_checked:
484 * \param friendly_name The friendly name of the appdomain to create
485 * \param configuration_file The configuration file to initialize the appdomain with
486 * \param error Set on error.
488 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
491 mono_domain_create_appdomain_checked (char *friendly_name
, char *configuration_file
, MonoError
*error
)
493 HANDLE_FUNCTION_ENTER ();
495 MonoDomain
*result
= NULL
;
497 MonoClass
*klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
498 MonoAppDomainSetupHandle setup
= (MonoAppDomainSetupHandle
)mono_object_new_handle (mono_domain_get (), klass
, error
);
499 goto_if_nok (error
, leave
);
500 MonoStringHandle config_file
;
501 if (configuration_file
!= NULL
) {
502 config_file
= mono_string_new_handle (mono_domain_get (), configuration_file
, error
);
503 goto_if_nok (error
, leave
);
505 config_file
= MONO_HANDLE_NEW (MonoString
, NULL
);
507 MONO_HANDLE_SET (setup
, configuration_file
, config_file
);
509 MonoAppDomainHandle ad
= mono_domain_create_appdomain_internal (friendly_name
, setup
, error
);
510 goto_if_nok (error
, leave
);
512 result
= mono_domain_from_appdomain_handle (ad
);
514 HANDLE_FUNCTION_RETURN_VAL (result
);
518 * mono_domain_set_config:
519 * \param domain \c MonoDomain initialized with the appdomain we want to change
520 * \param base_dir new base directory for the appdomain
521 * \param config_file_name path to the new configuration for the app domain
523 * Used to set the system configuration for an appdomain
525 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
526 * Error Initializing the configuration system. ---> System.ArgumentException:
527 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
530 mono_domain_set_config (MonoDomain
*domain
, const char *base_dir
, const char *config_file_name
)
532 HANDLE_FUNCTION_ENTER ();
534 mono_domain_set_config_checked (domain
, base_dir
, config_file_name
, error
);
535 mono_error_cleanup (error
);
536 HANDLE_FUNCTION_RETURN ();
540 mono_domain_set_config_checked (MonoDomain
*domain
, const char *base_dir
, const char *config_file_name
, MonoError
*error
)
543 MonoAppDomainSetupHandle setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
);
544 MonoStringHandle base_dir_str
= mono_string_new_handle (domain
, base_dir
, error
);
545 goto_if_nok (error
, leave
);
546 MONO_HANDLE_SET (setup
, application_base
, base_dir_str
);
547 MonoStringHandle config_file_name_str
= mono_string_new_handle (domain
, config_file_name
, error
);
548 goto_if_nok (error
, leave
);
549 MONO_HANDLE_SET (setup
, configuration_file
, config_file_name_str
);
551 return is_ok (error
);
554 static MonoAppDomainSetupHandle
555 copy_app_domain_setup (MonoDomain
*domain
, MonoAppDomainSetupHandle setup
, MonoError
*error
)
557 HANDLE_FUNCTION_ENTER ();
558 MonoDomain
*caller_domain
;
559 MonoClass
*ads_class
;
560 MonoAppDomainSetupHandle result
= MONO_HANDLE_NEW (MonoAppDomainSetup
, NULL
);
564 caller_domain
= mono_domain_get ();
565 ads_class
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
567 MonoAppDomainSetupHandle copy
= (MonoAppDomainSetupHandle
)mono_object_new_handle(domain
, ads_class
, error
);
568 goto_if_nok (error
, leave
);
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 goto_if_nok (error, leave); \
577 MONO_HANDLE_SET ((dst),field,copied_val); \
580 #define COPY_VAL(dst,field,type,src) \
582 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
585 XCOPY_FIELD (copy
, application_base
, setup
, error
);
586 XCOPY_FIELD (copy
, application_name
, setup
, error
);
587 XCOPY_FIELD (copy
, cache_path
, setup
, error
);
588 XCOPY_FIELD (copy
, configuration_file
, setup
, error
);
589 XCOPY_FIELD (copy
, dynamic_base
, setup
, error
);
590 XCOPY_FIELD (copy
, license_file
, setup
, error
);
591 XCOPY_FIELD (copy
, private_bin_path
, setup
, error
);
592 XCOPY_FIELD (copy
, private_bin_path_probe
, setup
, error
);
593 XCOPY_FIELD (copy
, shadow_copy_directories
, setup
, error
);
594 XCOPY_FIELD (copy
, shadow_copy_files
, setup
, error
);
595 COPY_VAL (copy
, publisher_policy
, MonoBoolean
, setup
);
596 COPY_VAL (copy
, path_changed
, MonoBoolean
, setup
);
597 COPY_VAL (copy
, loader_optimization
, int, setup
);
598 COPY_VAL (copy
, disallow_binding_redirects
, MonoBoolean
, setup
);
599 COPY_VAL (copy
, disallow_code_downloads
, MonoBoolean
, setup
);
600 XCOPY_FIELD (copy
, domain_initializer_args
, setup
, error
);
601 COPY_VAL (copy
, disallow_appbase_probe
, MonoBoolean
, setup
);
602 XCOPY_FIELD (copy
, application_trust
, setup
, error
);
603 XCOPY_FIELD (copy
, configuration_bytes
, setup
, error
);
604 XCOPY_FIELD (copy
, serialized_non_primitives
, setup
, error
);
609 mono_domain_set_internal (caller_domain
);
611 MONO_HANDLE_ASSIGN (result
, copy
);
613 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup
, result
);
616 static MonoAppDomainHandle
617 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetupHandle setup
, MonoError
*error
)
619 HANDLE_FUNCTION_ENTER ();
620 MonoAppDomainHandle result
= MONO_HANDLE_NEW (MonoAppDomain
, NULL
);
626 adclass
= mono_class_get_appdomain_class ();
628 /* FIXME: pin all those objects */
629 data
= mono_domain_create();
631 MonoAppDomainHandle ad
= (MonoAppDomainHandle
)mono_object_new_handle (data
, adclass
, error
);
632 goto_if_nok (error
, leave
);
633 MONO_HANDLE_SETVAL (ad
, data
, MonoDomain
*, data
);
634 data
->domain
= MONO_HANDLE_RAW (ad
);
635 data
->friendly_name
= g_strdup (friendly_name
);
637 MONO_PROFILER_RAISE (domain_name
, (data
, data
->friendly_name
));
639 MonoStringHandle app_base
= MONO_HANDLE_NEW_GET (MonoString
, setup
, application_base
);
640 if (MONO_HANDLE_IS_NULL (app_base
)) {
641 /* Inherit from the root domain since MS.NET does this */
642 MonoDomain
*root
= mono_get_root_domain ();
643 MonoAppDomainSetupHandle root_setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, root
->setup
);
644 MonoStringHandle root_app_base
= MONO_HANDLE_NEW_GET (MonoString
, root_setup
, application_base
);
645 if (!MONO_HANDLE_IS_NULL (root_app_base
)) {
646 /* N.B. new string is in the new domain */
647 uint32_t gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, root_app_base
), TRUE
);
648 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
);
649 mono_gchandle_free (gchandle
);
650 if (!is_ok (error
)) {
651 g_free (data
->friendly_name
);
654 MONO_HANDLE_SET (setup
, application_base
, s
);
658 mono_context_init_checked (data
, error
);
659 goto_if_nok (error
, leave
);
661 data
->setup
= MONO_HANDLE_RAW (copy_app_domain_setup (data
, setup
, error
));
662 if (!mono_error_ok (error
)) {
663 g_free (data
->friendly_name
);
667 mono_domain_set_options_from_config (data
);
668 add_assemblies_to_domain (data
, mono_defaults
.corlib
->assembly
, NULL
);
670 #ifndef DISABLE_SHADOW_COPY
671 /*FIXME, guard this for when the debugger is not running */
672 char *shadow_location
= get_shadow_assembly_location_base (data
, error
);
673 if (!mono_error_ok (error
)) {
674 g_free (data
->friendly_name
);
678 g_free (shadow_location
);
681 create_domain_objects (data
);
683 MONO_HANDLE_ASSIGN (result
, ad
);
685 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain
, result
);
689 * mono_domain_has_type_resolve:
690 * \param domain application domain being looked up
692 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
695 mono_domain_has_type_resolve (MonoDomain
*domain
)
697 static MonoClassField
*field
= NULL
;
701 field
= mono_class_get_field_from_name (mono_defaults
.appdomain_class
, "TypeResolve");
705 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
709 mono_field_get_value ((MonoObject
*)(domain
->domain
), field
, &o
);
714 * mono_domain_try_type_resolve:
715 * \param domain application domain in which to resolve the type
716 * \param name the name of the type to resolve or NULL.
717 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
719 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
720 * the assembly that matches name, or ((TypeBuilder)typebuilder).FullName.
722 * \returns A \c MonoReflectionAssembly or NULL if not found
724 MonoReflectionAssembly
*
725 mono_domain_try_type_resolve (MonoDomain
*domain
, char *name
, MonoObject
*typebuilder
)
728 g_assert (name
|| typebuilder
);
733 MonoReflectionAssembly
* const ret
= name
734 ? mono_domain_try_type_resolve_name (domain
, name
, error
)
735 : mono_domain_try_type_resolve_typebuilder (domain
, (MonoReflectionTypeBuilder
*)typebuilder
, error
);
737 mono_error_cleanup (error
);
742 * mono_class_get_appdomain_do_type_resolve_method:
744 * This routine returns System.AppDomain.DoTypeResolve.
747 mono_class_get_appdomain_do_type_resolve_method (MonoError
*error
)
749 static MonoMethod
*method
; // cache
754 // not cached yet, fill cache under caller's lock
756 method
= mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeResolve", -1, 0, error
);
759 g_warning ("%s method AppDomain.DoTypeResolve not found. %s\n", __func__
, mono_error_get_message (error
));
765 * mono_domain_try_type_resolve_name:
766 * \param domain application domain in which to resolve the type
767 * \param name the name of the type to resolve.
769 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
770 * the assembly that matches name.
772 * \returns A \c MonoReflectionAssembly or NULL if not found
774 MonoReflectionAssembly
*
775 mono_domain_try_type_resolve_name (MonoDomain
*domain
, const char *name
, MonoError
*error
)
783 void *params
[] = { mono_string_new_checked (mono_domain_get (), name
, error
) };
784 return_val_if_nok (error
, NULL
);
786 MonoMethod
* const method
= mono_class_get_appdomain_do_type_resolve_method (error
);
787 return_val_if_nok (error
, NULL
);
789 MonoObject
* const ret
= mono_runtime_invoke_checked (method
, domain
->domain
, params
, error
);
790 return_val_if_nok (error
, NULL
);
792 return (MonoReflectionAssembly
*)ret
;
796 * mono_domain_try_type_resolve_typebuilder:
797 * \param domain application domain in which to resolve the type
798 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder; typebuilder.FullName is the name of the type to resolve.
800 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
801 * the assembly that matches typebuilder.FullName.
803 * \returns A \c MonoReflectionAssembly or NULL if not found
805 MonoReflectionAssembly
*
806 mono_domain_try_type_resolve_typebuilder (MonoDomain
*domain
, MonoReflectionTypeBuilder
*typebuilder
, MonoError
*error
)
809 g_assert (typebuilder
);
814 MonoMethod
* const method
= mono_class_get_appdomain_do_type_resolve_method (error
);
815 return_val_if_nok (error
, NULL
);
817 MonoObject
* const ret
= mono_runtime_invoke_checked (method
, domain
->domain
, (void**)&typebuilder
, error
);
818 return_val_if_nok (error
, NULL
);
820 return (MonoReflectionAssembly
*)ret
;
824 * mono_domain_owns_vtable_slot:
825 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
828 mono_domain_owns_vtable_slot (MonoDomain
*domain
, gpointer vtable_slot
)
832 mono_domain_lock (domain
);
833 res
= mono_mempool_contains_addr (domain
->mp
, vtable_slot
);
834 mono_domain_unlock (domain
);
840 * \param domain domain
841 * \param force force setting.
843 * Set the current appdomain to \p domain. If \p force is set, set it even
844 * if it is being unloaded.
846 * \returns TRUE on success; FALSE if the domain is unloaded
849 mono_domain_set (MonoDomain
*domain
, gboolean force
)
851 if (!force
&& domain
->state
== MONO_APPDOMAIN_UNLOADED
)
854 mono_domain_set_internal (domain
);
860 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad
, MonoStringHandle name
, MonoError
*error
)
864 if (MONO_HANDLE_IS_NULL (name
)) {
865 mono_error_set_argument_null (error
, "name", "");
869 g_assert (!MONO_HANDLE_IS_NULL (ad
));
870 MonoDomain
*add
= MONO_HANDLE_GETVAL (ad
, data
);
873 char *str
= mono_string_handle_to_utf8 (name
, error
);
874 return_val_if_nok (error
, NULL_HANDLE
);
876 mono_domain_lock (add
);
878 MonoAppDomainSetupHandle ad_setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, add
->setup
);
880 if (!strcmp (str
, "APPBASE"))
881 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, application_base
);
882 else if (!strcmp (str
, "APP_CONFIG_FILE"))
883 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, configuration_file
);
884 else if (!strcmp (str
, "DYNAMIC_BASE"))
885 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, dynamic_base
);
886 else if (!strcmp (str
, "APP_NAME"))
887 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, application_name
);
888 else if (!strcmp (str
, "CACHE_BASE"))
889 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, cache_path
);
890 else if (!strcmp (str
, "PRIVATE_BINPATH"))
891 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, private_bin_path
);
892 else if (!strcmp (str
, "BINPATH_PROBE_ONLY"))
893 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, private_bin_path_probe
);
894 else if (!strcmp (str
, "SHADOW_COPY_DIRS"))
895 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, shadow_copy_directories
);
896 else if (!strcmp (str
, "FORCE_CACHE_INSTALL"))
897 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, shadow_copy_files
);
899 o
= MONO_HANDLE_NEW (MonoString
, mono_g_hash_table_lookup (add
->env
, MONO_HANDLE_RAW (name
)));
901 mono_domain_unlock (add
);
904 return MONO_HANDLE_CAST (MonoObject
, o
);
908 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad
, MonoStringHandle name
, MonoObjectHandle data
, MonoError
*error
)
912 if (MONO_HANDLE_IS_NULL (name
)) {
913 mono_error_set_argument_null (error
, "name", "");
917 g_assert (!MONO_HANDLE_IS_NULL (ad
));
918 MonoDomain
*add
= MONO_HANDLE_GETVAL (ad
, data
);
921 mono_domain_lock (add
);
923 mono_g_hash_table_insert (add
->env
, MONO_HANDLE_RAW (name
), MONO_HANDLE_RAW (data
));
925 mono_domain_unlock (add
);
928 MonoAppDomainSetupHandle
929 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad
, MonoError
*error
)
932 g_assert (!MONO_HANDLE_IS_NULL (ad
));
933 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
936 return MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
);
940 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad
, MonoError
*error
)
943 g_assert (!MONO_HANDLE_IS_NULL (ad
));
944 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
947 return mono_string_new_handle (domain
, domain
->friendly_name
, error
);
951 ves_icall_System_AppDomain_getCurDomain (MonoError
*error
)
954 MonoDomain
*add
= mono_domain_get ();
956 return MONO_HANDLE_NEW (MonoAppDomain
, add
->domain
);
960 ves_icall_System_AppDomain_getRootDomain (MonoError
*error
)
963 MonoDomain
*root
= mono_get_root_domain ();
965 return MONO_HANDLE_NEW (MonoAppDomain
, root
->domain
);
969 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions (MonoError
*error
)
971 MonoDomain
*domain
= mono_domain_get ();
973 return domain
->throw_unobserved_task_exceptions
;
977 get_attribute_value (const gchar
**attribute_names
,
978 const gchar
**attribute_values
,
979 const char *att_name
)
982 for (n
= 0; attribute_names
[n
] != NULL
; n
++) {
983 if (strcmp (attribute_names
[n
], att_name
) == 0)
984 return g_strdup (attribute_values
[n
]);
990 start_element (GMarkupParseContext
*context
,
991 const gchar
*element_name
,
992 const gchar
**attribute_names
,
993 const gchar
**attribute_values
,
997 RuntimeConfig
*runtime_config
= (RuntimeConfig
*)user_data
;
999 if (strcmp (element_name
, "runtime") == 0) {
1000 runtime_config
->runtime_count
++;
1004 if (strcmp (element_name
, "assemblyBinding") == 0) {
1005 runtime_config
->assemblybinding_count
++;
1009 if (runtime_config
->runtime_count
!= 1)
1012 if (strcmp (element_name
, "ThrowUnobservedTaskExceptions") == 0) {
1013 const char *value
= get_attribute_value (attribute_names
, attribute_values
, "enabled");
1015 if (value
&& g_ascii_strcasecmp (value
, "true") == 0)
1016 runtime_config
->domain
->throw_unobserved_task_exceptions
= TRUE
;
1019 if (runtime_config
->assemblybinding_count
!= 1)
1022 if (strcmp (element_name
, "probing") != 0)
1025 g_free (runtime_config
->domain
->private_bin_path
);
1026 runtime_config
->domain
->private_bin_path
= get_attribute_value (attribute_names
, attribute_values
, "privatePath");
1027 if (runtime_config
->domain
->private_bin_path
&& !runtime_config
->domain
->private_bin_path
[0]) {
1028 g_free (runtime_config
->domain
->private_bin_path
);
1029 runtime_config
->domain
->private_bin_path
= NULL
;
1035 end_element (GMarkupParseContext
*context
,
1036 const gchar
*element_name
,
1040 RuntimeConfig
*runtime_config
= (RuntimeConfig
*)user_data
;
1041 if (strcmp (element_name
, "runtime") == 0)
1042 runtime_config
->runtime_count
--;
1043 else if (strcmp (element_name
, "assemblyBinding") == 0)
1044 runtime_config
->assemblybinding_count
--;
1048 parse_error (GMarkupParseContext
*context
, GError
*gerror
, gpointer user_data
)
1050 RuntimeConfig
*state
= (RuntimeConfig
*)user_data
;
1052 const gchar
*filename
;
1054 filename
= state
&& state
->filename
? (gchar
*) state
->filename
: "<unknown>";
1055 msg
= gerror
&& gerror
->message
? gerror
->message
: "";
1056 g_warning ("Error parsing %s: %s", filename
, msg
);
1059 static const GMarkupParser
1069 mono_domain_set_options_from_config (MonoDomain
*domain
)
1072 gchar
*config_file_name
= NULL
, *text
= NULL
, *config_file_path
= NULL
;
1074 GMarkupParseContext
*context
;
1075 RuntimeConfig runtime_config
;
1078 if (!domain
|| !domain
->setup
|| !domain
->setup
->configuration_file
)
1081 config_file_name
= mono_string_to_utf8_checked (domain
->setup
->configuration_file
, error
);
1082 if (!mono_error_ok (error
)) {
1083 mono_error_cleanup (error
);
1087 config_file_path
= mono_portability_find_file (config_file_name
, TRUE
);
1088 if (!config_file_path
)
1089 config_file_path
= config_file_name
;
1091 if (!g_file_get_contents (config_file_path
, &text
, &len
, NULL
))
1094 runtime_config
.runtime_count
= 0;
1095 runtime_config
.assemblybinding_count
= 0;
1096 runtime_config
.domain
= domain
;
1097 runtime_config
.filename
= config_file_path
;
1100 if (len
> 3 && text
[0] == '\xef' && text
[1] == (gchar
) '\xbb' && text
[2] == '\xbf')
1101 offset
= 3; /* Skip UTF-8 BOM */
1103 context
= g_markup_parse_context_new (&mono_parser
, (GMarkupParseFlags
)0, &runtime_config
, NULL
);
1104 if (g_markup_parse_context_parse (context
, text
+ offset
, len
- offset
, NULL
))
1105 g_markup_parse_context_end_parse (context
, NULL
);
1106 g_markup_parse_context_free (context
);
1110 if (config_file_name
!= config_file_path
)
1111 g_free (config_file_name
);
1112 g_free (config_file_path
);
1116 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name
, MonoAppDomainSetupHandle setup
, MonoError
*error
)
1119 MonoAppDomainHandle ad
= MONO_HANDLE_NEW (MonoAppDomain
, NULL
);
1121 #ifdef DISABLE_APPDOMAINS
1122 mono_error_set_not_supported (error
, "AppDomain creation is not supported on this runtime.");
1126 fname
= mono_string_handle_to_utf8 (friendly_name
, error
);
1127 return_val_if_nok (error
, ad
);
1128 ad
= mono_domain_create_appdomain_internal (fname
, setup
, error
);
1135 add_assembly_to_array (MonoDomain
*domain
, MonoArrayHandle dest
, int dest_idx
, MonoAssembly
* assm
, MonoError
*error
)
1137 HANDLE_FUNCTION_ENTER ();
1139 MonoReflectionAssemblyHandle assm_obj
= mono_assembly_get_object_handle (domain
, assm
, error
);
1140 goto_if_nok (error
, leave
);
1141 MONO_HANDLE_ARRAY_SETREF (dest
, dest_idx
, assm_obj
);
1143 HANDLE_FUNCTION_RETURN_VAL (is_ok (error
));
1147 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad
, MonoBoolean refonly
, MonoError
*error
)
1150 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
1154 GPtrArray
*assemblies
;
1157 * Make a copy of the list of assemblies because we can't hold the assemblies
1158 * lock while creating objects etc.
1160 assemblies
= g_ptr_array_new ();
1161 /* Need to skip internal assembly builders created by remoting */
1162 mono_domain_assemblies_lock (domain
);
1163 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1164 ass
= (MonoAssembly
*)tmp
->data
;
1165 MonoBoolean ass_refonly
= mono_asmctx_get_kind (&ass
->context
) == MONO_ASMCTX_REFONLY
;
1166 /* .NET Framework GetAssemblies() includes LoadFrom and Load(byte[]) assemblies, too */
1167 if (refonly
!= ass_refonly
)
1169 if (ass
->corlib_internal
)
1171 g_ptr_array_add (assemblies
, ass
);
1173 mono_domain_assemblies_unlock (domain
);
1175 MonoArrayHandle res
= mono_array_new_handle (domain
, mono_class_get_assembly_class (), assemblies
->len
, error
);
1176 goto_if_nok (error
, leave
);
1177 for (i
= 0; i
< assemblies
->len
; ++i
) {
1178 if (!add_assembly_to_array (domain
, res
, i
, (MonoAssembly
*)g_ptr_array_index (assemblies
, i
), error
))
1183 g_ptr_array_free (assemblies
, TRUE
);
1188 mono_try_assembly_resolve (MonoDomain
*domain
, const char *fname_raw
, MonoAssembly
*requesting
, gboolean refonly
, MonoError
*error
)
1190 HANDLE_FUNCTION_ENTER ();
1192 MonoAssembly
*result
= NULL
;
1193 MonoStringHandle fname
= mono_string_new_handle (domain
, fname_raw
, error
);
1194 goto_if_nok (error
, leave
);
1195 result
= mono_try_assembly_resolve_handle (domain
, fname
, requesting
, refonly
, error
);
1197 HANDLE_FUNCTION_RETURN_VAL (result
);
1201 mono_try_assembly_resolve_handle (MonoDomain
*domain
, MonoStringHandle fname
, MonoAssembly
*requesting
, gboolean refonly
, MonoError
*error
)
1203 HANDLE_FUNCTION_ENTER ();
1204 MonoAssembly
*ret
= NULL
;
1206 MonoBoolean isrefonly
;
1207 gpointer params
[3];
1211 if (mono_runtime_get_no_exec ())
1214 g_assert (domain
!= NULL
&& !MONO_HANDLE_IS_NULL (fname
));
1216 method
= mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1, 0, error
);
1217 g_assert (method
!= NULL
);
1219 isrefonly
= refonly
? 1 : 0;
1220 MonoReflectionAssemblyHandle requesting_handle
;
1222 requesting_handle
= mono_assembly_get_object_handle (domain
, requesting
, error
);
1223 goto_if_nok (error
, leave
);
1225 params
[0] = MONO_HANDLE_RAW (fname
);
1226 params
[1] = requesting
? MONO_HANDLE_RAW (requesting_handle
) : NULL
;
1227 params
[2] = &isrefonly
;
1228 MonoObject
*exc
= NULL
;
1229 MonoReflectionAssemblyHandle result
= MONO_HANDLE_NEW (MonoReflectionAssembly
, mono_runtime_try_invoke (method
, domain
->domain
, params
, &exc
, error
));
1230 if (!is_ok (error
) || exc
!= NULL
) {
1232 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
1235 ret
= !MONO_HANDLE_IS_NULL (result
) ? MONO_HANDLE_GETVAL (result
, assembly
) : NULL
;
1237 if (ret
&& !refonly
&& mono_asmctx_get_kind (&ret
->context
) == MONO_ASMCTX_REFONLY
) {
1238 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1239 mono_error_set_file_not_found (error
, NULL
, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1244 HANDLE_FUNCTION_RETURN_VAL (ret
);
1248 mono_domain_assembly_postload_search (MonoAssemblyName
*aname
, MonoAssembly
*requesting
,
1252 MonoAssembly
*assembly
;
1253 MonoDomain
*domain
= mono_domain_get ();
1256 aname_str
= mono_stringify_assembly_name (aname
);
1258 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1260 assembly
= mono_try_assembly_resolve (domain
, aname_str
, requesting
, refonly
, error
);
1262 mono_error_cleanup (error
);
1268 * LOCKING: assumes assemblies_lock in the domain is already locked.
1271 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*ht
)
1275 gboolean destroy_ht
= FALSE
;
1277 if (!ass
->aname
.name
)
1281 ht
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1283 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1284 g_hash_table_insert (ht
, tmp
->data
, tmp
->data
);
1288 /* FIXME: handle lazy loaded assemblies */
1290 if (!g_hash_table_lookup (ht
, ass
)) {
1291 mono_assembly_addref (ass
);
1292 g_hash_table_insert (ht
, ass
, ass
);
1293 domain
->domain_assemblies
= g_slist_append (domain
->domain_assemblies
, ass
);
1294 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
);
1297 if (ass
->image
->references
) {
1298 for (i
= 0; i
< ass
->image
->nreferences
; i
++) {
1299 if (ass
->image
->references
[i
] && ass
->image
->references
[i
] != REFERENCE_MISSING
) {
1300 if (!g_hash_table_lookup (ht
, ass
->image
->references
[i
])) {
1301 add_assemblies_to_domain (domain
, ass
->image
->references
[i
], ht
);
1307 g_hash_table_destroy (ht
);
1311 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
)
1313 HANDLE_FUNCTION_ENTER ();
1314 static MonoClassField
*assembly_load_field
;
1315 static MonoMethod
*assembly_load_method
;
1317 MonoDomain
*domain
= mono_domain_get ();
1319 gpointer load_value
;
1322 if (!domain
->domain
)
1323 /* This can happen during startup */
1325 #ifdef ASSEMBLY_LOAD_DEBUG
1326 fprintf (stderr
, "Loading %s into domain %s\n", assembly
->aname
.name
, domain
->friendly_name
);
1328 klass
= domain
->domain
->mbr
.obj
.vtable
->klass
;
1332 mono_domain_assemblies_lock (domain
);
1333 add_assemblies_to_domain (domain
, assembly
, NULL
);
1334 mono_domain_assemblies_unlock (domain
);
1336 if (assembly_load_field
== NULL
) {
1337 assembly_load_field
= mono_class_get_field_from_name (klass
, "AssemblyLoad");
1338 g_assert (assembly_load_field
);
1341 mono_field_get_value ((MonoObject
*) domain
->domain
, assembly_load_field
, &load_value
);
1342 if (load_value
== NULL
) {
1343 /* No events waiting to be triggered */
1347 MonoReflectionAssemblyHandle ref_assembly
= mono_assembly_get_object_handle (domain
, assembly
, error
);
1348 mono_error_assert_ok (error
);
1350 if (assembly_load_method
== NULL
) {
1351 assembly_load_method
= mono_class_get_method_from_name_checked (klass
, "DoAssemblyLoad", -1, 0, error
);
1352 g_assert (assembly_load_method
);
1355 *params
= MONO_HANDLE_RAW(ref_assembly
);
1357 mono_runtime_invoke_checked (assembly_load_method
, domain
->domain
, params
, error
);
1358 mono_error_cleanup (error
);
1360 HANDLE_FUNCTION_RETURN ();
1364 mono_domain_asmctx_from_path (const char *fname
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
)
1366 MonoDomain
*domain
= mono_domain_get ();
1367 char **search_path
= NULL
;
1369 for (search_path
= domain
->search_path
; search_path
&& *search_path
; search_path
++) {
1370 if (mono_path_filename_in_basedir (fname
, *search_path
)) {
1371 *out_asmctx
= MONO_ASMCTX_DEFAULT
;
1379 * LOCKING: Acquires the domain assemblies lock.
1382 set_domain_search_path (MonoDomain
*domain
)
1385 MonoAppDomainSetup
*setup
;
1387 gchar
*search_path
= NULL
;
1390 gchar
**pvt_split
= NULL
;
1391 GError
*gerror
= NULL
;
1392 gint appbaselen
= -1;
1395 * We use the low-level domain assemblies lock, since this is called from
1396 * assembly loads hooks, which means this thread might hold the loader lock.
1398 mono_domain_assemblies_lock (domain
);
1400 if (!domain
->setup
) {
1401 mono_domain_assemblies_unlock (domain
);
1405 if ((domain
->search_path
!= NULL
) && !domain
->setup
->path_changed
) {
1406 mono_domain_assemblies_unlock (domain
);
1409 setup
= domain
->setup
;
1410 if (!setup
->application_base
) {
1411 mono_domain_assemblies_unlock (domain
);
1412 return; /* Must set application base to get private path working */
1417 if (setup
->private_bin_path
) {
1418 search_path
= mono_string_to_utf8_checked (setup
->private_bin_path
, error
);
1419 if (!mono_error_ok (error
)) { /*FIXME maybe we should bubble up the error.*/
1420 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1421 mono_error_cleanup (error
);
1422 mono_domain_assemblies_unlock (domain
);
1427 if (domain
->private_bin_path
) {
1428 if (search_path
== NULL
)
1429 search_path
= domain
->private_bin_path
;
1431 gchar
*tmp2
= search_path
;
1432 search_path
= g_strjoin (";", search_path
, domain
->private_bin_path
, NULL
);
1439 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1440 * directories relative to ApplicationBase separated by semicolons (see
1441 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1442 * The loop below copes with the fact that some Unix applications may use ':' (or
1443 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1444 * ';' for the subsequent split.
1446 * The issue was reported in bug #81446
1449 #ifndef TARGET_WIN32
1452 slen
= strlen (search_path
);
1453 for (i
= 0; i
< slen
; i
++)
1454 if (search_path
[i
] == ':')
1455 search_path
[i
] = ';';
1458 pvt_split
= g_strsplit (search_path
, ";", 1000);
1459 g_free (search_path
);
1460 for (tmp
= pvt_split
; *tmp
; tmp
++, npaths
++);
1465 g_strfreev (pvt_split
);
1467 * Don't do this because the first time is called, the domain
1468 * setup is not finished.
1470 * domain->search_path = g_malloc (sizeof (char *));
1471 * domain->search_path [0] = NULL;
1473 mono_domain_assemblies_unlock (domain
);
1477 if (domain
->search_path
)
1478 g_strfreev (domain
->search_path
);
1480 tmp
= (gchar
**)g_malloc ((npaths
+ 1) * sizeof (gchar
*));
1481 tmp
[npaths
] = NULL
;
1483 *tmp
= mono_string_to_utf8_checked (setup
->application_base
, error
);
1484 if (!mono_error_ok (error
)) {
1485 mono_error_cleanup (error
);
1486 g_strfreev (pvt_split
);
1489 mono_domain_assemblies_unlock (domain
);
1493 domain
->search_path
= tmp
;
1495 /* FIXME: is this needed? */
1496 if (strncmp (*tmp
, "file://", 7) == 0) {
1502 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
1505 uri
= mono_escape_uri_string (tmpuri
);
1506 *tmp
= g_filename_from_uri (uri
, NULL
, &gerror
);
1512 if (gerror
!= NULL
) {
1513 g_warning ("%s\n", gerror
->message
);
1514 g_error_free (gerror
);
1521 for (i
= 1; pvt_split
&& i
< npaths
; i
++) {
1522 if (g_path_is_absolute (pvt_split
[i
- 1])) {
1523 tmp
[i
] = g_strdup (pvt_split
[i
- 1]);
1525 tmp
[i
] = g_build_filename (tmp
[0], pvt_split
[i
- 1], NULL
);
1528 if (strchr (tmp
[i
], '.')) {
1532 reduced
= mono_path_canonicalize (tmp
[i
]);
1533 if (appbaselen
== -1)
1534 appbaselen
= strlen (tmp
[0]);
1536 if (strncmp (tmp
[0], reduced
, appbaselen
)) {
1539 tmp
[i
] = g_strdup ("");
1549 if (setup
->private_bin_path_probe
!= NULL
) {
1551 tmp
[0] = g_strdup ("");
1554 domain
->setup
->path_changed
= FALSE
;
1556 g_strfreev (pvt_split
);
1558 mono_domain_assemblies_unlock (domain
);
1561 #ifdef DISABLE_SHADOW_COPY
1563 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1569 mono_make_shadow_copy (const char *filename
, MonoError
*error
)
1572 return (char *) filename
;
1577 SHADOW_COPY_SIBLING_EXT_APPEND
,
1578 SHADOW_COPY_SIBLING_EXT_REPLACE
,
1579 } ShadowCopySiblingExt
;
1583 make_sibling_path (const gchar
*path
, gint pathlen
, const char *extension
, ShadowCopySiblingExt extopt
)
1585 gchar
*result
= NULL
;
1587 case SHADOW_COPY_SIBLING_EXT_APPEND
: {
1588 result
= g_strconcat (path
, extension
, NULL
);
1591 case SHADOW_COPY_SIBLING_EXT_REPLACE
: {
1592 /* expect path to be a .dll or .exe (or some case insensitive variant) */
1593 g_assert (pathlen
>= 4 && path
[pathlen
- 4] == '.');
1594 GString
*s
= g_string_sized_new (pathlen
- 4 + strlen (extension
));
1595 g_string_append_len (s
, path
, pathlen
- 4);
1596 g_string_append (s
, extension
);
1597 result
= g_string_free (s
, FALSE
);
1601 g_assert_not_reached ();
1607 shadow_copy_sibling (const gchar
*src_pristine
, gint srclen
, const char *extension
, ShadowCopySiblingExt extopt
, const gchar
*target_pristine
, gint targetlen
)
1609 guint16
*orig
, *dest
;
1610 gboolean copy_result
;
1613 gchar
*target
= NULL
;
1615 src
= make_sibling_path (src_pristine
, srclen
, extension
, extopt
);
1617 if (IS_PORTABILITY_CASE
) {
1618 gchar
*file
= mono_portability_find_file (src
, TRUE
);
1626 } else if (!g_file_test (src
, G_FILE_TEST_IS_REGULAR
)) {
1631 orig
= g_utf8_to_utf16 (src
, strlen (src
), NULL
, NULL
, NULL
);
1633 target
= make_sibling_path (target_pristine
, targetlen
, extension
, extopt
);
1635 dest
= g_utf8_to_utf16 (target
, strlen (target
), NULL
, NULL
, NULL
);
1637 mono_w32file_delete (dest
);
1639 copy_result
= mono_w32file_copy (orig
, dest
, TRUE
, ©_error
);
1641 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1642 * overwritten when updated in their original locations. */
1644 copy_result
= mono_w32file_set_attributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1655 get_cstring_hash (const char *str
)
1661 if (!str
|| !str
[0])
1666 for (i
= 0; i
< len
; i
++) {
1667 h
= (h
<< 5) - h
+ *p
;
1675 * Returned memory is malloc'd. Called must free it
1678 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
)
1680 MonoAppDomainSetup
*setup
;
1681 char *cache_path
, *appname
;
1687 setup
= domain
->setup
;
1688 if (setup
->cache_path
!= NULL
&& setup
->application_name
!= NULL
) {
1689 cache_path
= mono_string_to_utf8_checked (setup
->cache_path
, error
);
1690 return_val_if_nok (error
, NULL
);
1692 #ifndef TARGET_WIN32
1695 for (i
= strlen (cache_path
) - 1; i
>= 0; i
--)
1696 if (cache_path
[i
] == '\\')
1697 cache_path
[i
] = '/';
1701 appname
= mono_string_to_utf8_checked (setup
->application_name
, error
);
1702 if (!mono_error_ok (error
)) {
1703 g_free (cache_path
);
1707 location
= g_build_filename (cache_path
, appname
, "assembly", "shadow", NULL
);
1709 g_free (cache_path
);
1711 userdir
= g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1712 location
= g_build_filename (g_get_tmp_dir (), userdir
, "assembly", "shadow", NULL
);
1719 get_shadow_assembly_location (const char *filename
, MonoError
*error
)
1721 gint32 hash
= 0, hash2
= 0;
1723 char path_hash
[30];
1724 char *bname
= g_path_get_basename (filename
);
1725 char *dirname
= g_path_get_dirname (filename
);
1726 char *location
, *tmploc
;
1727 MonoDomain
*domain
= mono_domain_get ();
1731 hash
= get_cstring_hash (bname
);
1732 hash2
= get_cstring_hash (dirname
);
1733 g_snprintf (name_hash
, sizeof (name_hash
), "%08x", hash
);
1734 g_snprintf (path_hash
, sizeof (path_hash
), "%08x_%08x_%08x", hash
^ hash2
, hash2
, domain
->shadow_serial
);
1735 tmploc
= get_shadow_assembly_location_base (domain
, error
);
1736 if (!mono_error_ok (error
)) {
1742 location
= g_build_filename (tmploc
, name_hash
, path_hash
, bname
, NULL
);
1750 private_file_needs_copying (const char *src
, struct stat
*sbuf_src
, char *dest
)
1752 struct stat sbuf_dest
;
1754 gchar
*real_src
= mono_portability_find_file (src
, TRUE
);
1757 stat_src
= (gchar
*)src
;
1759 stat_src
= real_src
;
1761 if (stat (stat_src
, sbuf_src
) == -1) {
1762 time_t tnow
= time (NULL
);
1767 memset (sbuf_src
, 0, sizeof (*sbuf_src
));
1768 sbuf_src
->st_mtime
= tnow
;
1769 sbuf_src
->st_atime
= tnow
;
1776 if (stat (dest
, &sbuf_dest
) == -1)
1779 if (sbuf_src
->st_size
== sbuf_dest
.st_size
&&
1780 sbuf_src
->st_mtime
== sbuf_dest
.st_mtime
)
1787 shadow_copy_create_ini (const char *shadow
, const char *filename
)
1797 dir_name
= g_path_get_dirname (shadow
);
1798 ini_file
= g_build_filename (dir_name
, "__AssemblyInfo__.ini", NULL
);
1800 if (g_file_test (ini_file
, G_FILE_TEST_IS_REGULAR
)) {
1805 u16_ini
= g_utf8_to_utf16 (ini_file
, strlen (ini_file
), NULL
, NULL
, NULL
);
1810 handle
= (void **)mono_w32file_create (u16_ini
, GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, CREATE_NEW
, FileAttributes_Normal
);
1812 if (handle
== INVALID_HANDLE_VALUE
) {
1816 full_path
= mono_path_resolve_symlinks (filename
);
1817 result
= mono_w32file_write (handle
, full_path
, strlen (full_path
), &n
);
1819 mono_w32file_close (handle
);
1824 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1827 MonoAppDomainSetup
*setup
;
1830 gchar
**directories
;
1831 gchar
*shadow_status_string
;
1833 gboolean shadow_enabled
;
1834 gboolean found
= FALSE
;
1839 setup
= domain
->setup
;
1840 if (setup
== NULL
|| setup
->shadow_copy_files
== NULL
)
1843 shadow_status_string
= mono_string_to_utf8_checked (setup
->shadow_copy_files
, error
);
1844 if (!mono_error_ok (error
)) {
1845 mono_error_cleanup (error
);
1848 shadow_enabled
= !g_ascii_strncasecmp (shadow_status_string
, "true", 4);
1849 g_free (shadow_status_string
);
1851 if (!shadow_enabled
)
1854 if (setup
->shadow_copy_directories
== NULL
)
1857 /* Is dir_name a shadow_copy destination already? */
1858 base_dir
= get_shadow_assembly_location_base (domain
, error
);
1859 if (!mono_error_ok (error
)) {
1860 mono_error_cleanup (error
);
1864 if (strstr (dir_name
, base_dir
)) {
1870 all_dirs
= mono_string_to_utf8_checked (setup
->shadow_copy_directories
, error
);
1871 if (!mono_error_ok (error
)) {
1872 mono_error_cleanup (error
);
1876 directories
= g_strsplit (all_dirs
, G_SEARCHPATH_SEPARATOR_S
, 1000);
1877 dir_ptr
= directories
;
1879 if (**dir_ptr
!= '\0' && !strcmp (*dir_ptr
, dir_name
)) {
1885 g_strfreev (directories
);
1891 This function raises exceptions so it can cause as sorts of nasty stuff if called
1892 while holding a lock.
1893 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1894 or NULL if source file not found.
1895 FIXME bubble up the error instead of raising it here
1898 mono_make_shadow_copy (const char *filename
, MonoError
*oerror
)
1901 gint filename_len
, shadow_len
;
1902 guint16
*orig
, *dest
;
1905 gboolean copy_result
;
1906 struct stat src_sbuf
;
1907 struct utimbuf utbuf
;
1908 char *dir_name
= g_path_get_dirname (filename
);
1909 MonoDomain
*domain
= mono_domain_get ();
1913 error_init (oerror
);
1915 set_domain_search_path (domain
);
1917 if (!mono_is_shadow_copy_enabled (domain
, dir_name
)) {
1919 return (char *) filename
;
1922 /* Is dir_name a shadow_copy destination already? */
1923 shadow_dir
= get_shadow_assembly_location_base (domain
, error
);
1924 if (!mono_error_ok (error
)) {
1925 mono_error_cleanup (error
);
1927 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (invalid characters in shadow directory name).");
1931 if (strstr (dir_name
, shadow_dir
)) {
1932 g_free (shadow_dir
);
1934 return (char *) filename
;
1936 g_free (shadow_dir
);
1939 shadow
= get_shadow_assembly_location (filename
, error
);
1940 if (!mono_error_ok (error
)) {
1941 mono_error_cleanup (error
);
1942 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (invalid characters in file name).");
1946 if (g_ensure_directory_exists (shadow
) == FALSE
) {
1948 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (ensure directory exists).");
1952 if (!private_file_needs_copying (filename
, &src_sbuf
, shadow
))
1953 return (char*) shadow
;
1955 orig
= g_utf8_to_utf16 (filename
, strlen (filename
), NULL
, NULL
, NULL
);
1956 dest
= g_utf8_to_utf16 (shadow
, strlen (shadow
), NULL
, NULL
, NULL
);
1957 mono_w32file_delete (dest
);
1959 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1960 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1961 * and not have it runtime error" */
1962 attrs
= mono_w32file_get_attributes (orig
);
1963 if (attrs
== INVALID_FILE_ATTRIBUTES
) {
1965 return (char *)filename
;
1968 copy_result
= mono_w32file_copy (orig
, dest
, TRUE
, ©_error
);
1970 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1971 * overwritten when updated in their original locations. */
1973 copy_result
= mono_w32file_set_attributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1978 if (copy_result
== FALSE
) {
1981 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1982 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND
|| mono_w32error_get_last() == ERROR_PATH_NOT_FOUND
)
1983 return NULL
; /* file not found, shadow copy failed */
1985 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (mono_w32file_copy).");
1989 /* attempt to copy .mdb, .pdb and .config if they exist */
1990 filename_len
= strlen (filename
);
1991 shadow_len
= strlen (shadow
);
1993 copy_result
= shadow_copy_sibling (filename
, filename_len
, ".mdb", SHADOW_COPY_SIBLING_EXT_APPEND
, shadow
, shadow_len
);
1995 copy_result
= shadow_copy_sibling (filename
, filename_len
, ".pdb", SHADOW_COPY_SIBLING_EXT_REPLACE
, shadow
, shadow_len
);
1997 copy_result
= shadow_copy_sibling (filename
, filename_len
, ".config", SHADOW_COPY_SIBLING_EXT_APPEND
, shadow
, shadow_len
);
2001 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
2005 /* Create a .ini file containing the original assembly location */
2006 if (!shadow_copy_create_ini (shadow
, filename
)) {
2008 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy .ini file.");
2012 utbuf
.actime
= src_sbuf
.st_atime
;
2013 utbuf
.modtime
= src_sbuf
.st_mtime
;
2014 utime (shadow
, &utbuf
);
2018 #endif /* DISABLE_SHADOW_COPY */
2021 * mono_domain_from_appdomain:
2024 mono_domain_from_appdomain (MonoAppDomain
*appdomain_raw
)
2026 HANDLE_FUNCTION_ENTER ();
2027 MONO_HANDLE_DCL (MonoAppDomain
, appdomain
);
2028 MonoDomain
*result
= mono_domain_from_appdomain_handle (appdomain
);
2029 HANDLE_FUNCTION_RETURN_VAL (result
);
2033 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain
)
2035 HANDLE_FUNCTION_ENTER ();
2036 MonoDomain
*dom
= NULL
;
2037 if (MONO_HANDLE_IS_NULL (appdomain
))
2040 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain
))) {
2041 MonoTransparentProxyHandle tp
= MONO_HANDLE_CAST (MonoTransparentProxy
, appdomain
);
2042 MonoRealProxyHandle rp
= MONO_HANDLE_NEW_GET (MonoRealProxy
, tp
, rp
);
2044 dom
= mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp
, target_domain_id
));
2046 dom
= MONO_HANDLE_GETVAL (appdomain
, data
);
2049 HANDLE_FUNCTION_RETURN_VAL (dom
);
2054 try_load_from (MonoAssembly
**assembly
,
2055 const gchar
*path1
, const gchar
*path2
,
2056 const gchar
*path3
, const gchar
*path4
,
2057 MonoAssemblyContextKind asmctx
, gboolean is_private
,
2058 MonoAssemblyCandidatePredicate predicate
, gpointer user_data
)
2061 gboolean found
= FALSE
;
2064 fullpath
= g_build_filename (path1
, path2
, path3
, path4
, NULL
);
2066 if (IS_PORTABILITY_SET
) {
2067 gchar
*new_fullpath
= mono_portability_find_file (fullpath
, TRUE
);
2070 fullpath
= new_fullpath
;
2074 found
= g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
);
2077 *assembly
= mono_assembly_open_predicate (fullpath
, asmctx
, predicate
, user_data
, NULL
, NULL
);
2080 return (*assembly
!= NULL
);
2083 static MonoAssembly
*
2084 real_load (gchar
**search_path
, const gchar
*culture
, const gchar
*name
, MonoAssemblyContextKind asmctx
, MonoAssemblyCandidatePredicate predicate
, gpointer user_data
)
2086 MonoAssembly
*result
= NULL
;
2089 const gchar
*local_culture
;
2091 gboolean is_private
= FALSE
;
2093 if (!culture
|| *culture
== '\0') {
2096 local_culture
= culture
;
2099 filename
= g_strconcat (name
, ".dll", NULL
);
2100 len
= strlen (filename
);
2102 for (path
= search_path
; *path
; path
++) {
2103 if (**path
== '\0') {
2105 continue; /* Ignore empty ApplicationBase */
2108 /* See test cases in bug #58992 and bug #57710 */
2109 /* 1st try: [culture]/[name].dll (culture may be empty) */
2110 strcpy (filename
+ len
- 4, ".dll");
2111 if (try_load_from (&result
, *path
, local_culture
, "", filename
, asmctx
, is_private
, predicate
, user_data
))
2114 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2115 strcpy (filename
+ len
- 4, ".exe");
2116 if (try_load_from (&result
, *path
, local_culture
, "", filename
, asmctx
, is_private
, predicate
, user_data
))
2119 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2120 strcpy (filename
+ len
- 4, ".dll");
2121 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, asmctx
, is_private
, predicate
, user_data
))
2124 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2125 strcpy (filename
+ len
- 4, ".exe");
2126 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, asmctx
, is_private
, predicate
, user_data
))
2135 * Try loading the assembly from ApplicationBase and PrivateBinPath
2136 * and then from assemblies_path if any.
2137 * LOCKING: This is called from the assembly loading code, which means the caller
2138 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2140 static MonoAssembly
*
2141 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
2142 gchar
**assemblies_path
,
2145 MonoDomain
*domain
= mono_domain_get ();
2146 MonoAssembly
*result
= NULL
;
2147 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
2149 set_domain_search_path (domain
);
2151 MonoAssemblyCandidatePredicate predicate
= NULL
;
2152 void* predicate_ud
= NULL
;
2153 #if !defined(DISABLE_DESKTOP_LOADER)
2154 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2155 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
2156 predicate_ud
= aname
;
2159 if (domain
->search_path
&& domain
->search_path
[0] != NULL
) {
2160 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
)) {
2161 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Domain %s search path is:", domain
->friendly_name
);
2162 for (int i
= 0; domain
->search_path
[i
]; i
++) {
2163 const char *p
= domain
->search_path
[i
];
2164 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "\tpath[%d] = '%s'", i
, p
);
2166 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "End of domain %s search path.", domain
->friendly_name
);
2168 result
= real_load (domain
->search_path
, aname
->culture
, aname
->name
, refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
, predicate
, predicate_ud
);
2171 if (result
== NULL
&& assemblies_path
&& assemblies_path
[0] != NULL
) {
2172 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
, predicate
, predicate_ud
);
2179 * mono_assembly_load_from_assemblies_path:
2181 * \param assemblies_path directories to search for given assembly name, terminated by NULL
2182 * \param aname assembly name to look for
2183 * \param asmctx assembly load context for this load operation
2185 * Given a NULL-terminated array of paths, look for \c name.ext, \c name, \c
2186 * culture/name.ext, \c culture/name/name.ext where \c ext is \c dll and \c
2187 * exe and try to load it in the given assembly load context.
2189 * \returns A \c MonoAssembly if probing was successful, or NULL otherwise.
2192 mono_assembly_load_from_assemblies_path (gchar
**assemblies_path
, MonoAssemblyName
*aname
, MonoAssemblyContextKind asmctx
)
2194 MonoAssemblyCandidatePredicate predicate
= NULL
;
2195 void* predicate_ud
= NULL
;
2196 #if !defined(DISABLE_DESKTOP_LOADER)
2197 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2198 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
2199 predicate_ud
= aname
;
2202 MonoAssembly
*result
= NULL
;
2203 if (assemblies_path
&& assemblies_path
[0] != NULL
) {
2204 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, asmctx
, predicate
, predicate_ud
);
2210 * Check whenever a given assembly was already loaded in the current appdomain.
2212 static MonoAssembly
*
2213 mono_domain_assembly_search (MonoAssemblyName
*aname
,
2216 MonoDomain
*domain
= mono_domain_get ();
2219 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
2220 const gboolean strong_name
= aname
->public_key_token
[0] != 0;
2221 /* If it's not a strong name, any version that has the right simple
2222 * name is good enough to satisfy the request. .NET Framework also
2223 * ignores case differences in this case. */
2224 const MonoAssemblyNameEqFlags eq_flags
= strong_name
? MONO_ANAME_EQ_IGNORE_CASE
:
2225 (MONO_ANAME_EQ_IGNORE_PUBKEY
| MONO_ANAME_EQ_IGNORE_VERSION
| MONO_ANAME_EQ_IGNORE_CASE
);
2227 mono_domain_assemblies_lock (domain
);
2228 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
2229 ass
= (MonoAssembly
*)tmp
->data
;
2230 /* Dynamic assemblies can't match here in MS.NET */
2231 gboolean ass_ref_only
= mono_asmctx_get_kind (&ass
->context
) == MONO_ASMCTX_REFONLY
;
2232 if (assembly_is_dynamic (ass
) || refonly
!= ass_ref_only
|| !mono_assembly_names_equal_flags (aname
, &ass
->aname
, eq_flags
))
2235 mono_domain_assemblies_unlock (domain
);
2238 mono_domain_assemblies_unlock (domain
);
2243 MonoReflectionAssemblyHandle
2244 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname
, MonoBoolean refOnly
, MonoError
*error
)
2247 MonoDomain
*domain
= mono_domain_get ();
2248 char *name
, *filename
;
2249 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2250 MonoReflectionAssemblyHandle result
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2255 if (fname
== NULL
) {
2256 mono_error_set_argument_null (error
, "assemblyFile", "");
2260 name
= filename
= mono_string_handle_to_utf8 (fname
, error
);
2261 goto_if_nok (error
, leave
);
2263 MonoAssembly
*requesting_assembly
= NULL
;
2265 MonoMethod
*executing_method
= mono_runtime_get_caller_no_system_or_reflection ();
2266 MonoAssembly
*executing_assembly
= executing_method
? m_class_get_image (executing_method
->klass
)->assembly
: NULL
;
2267 requesting_assembly
= executing_assembly
;
2270 MonoAssembly
*ass
= mono_assembly_open_predicate (filename
, refOnly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_LOADFROM
, NULL
, NULL
, requesting_assembly
, &status
);
2273 if (status
== MONO_IMAGE_IMAGE_INVALID
)
2274 mono_error_set_bad_image_by_name (error
, name
, "Invalid Image");
2276 mono_error_set_file_not_found (error
, name
, "Invalid Image");
2280 result
= mono_assembly_get_object_handle (domain
, ass
, error
);
2287 MonoReflectionAssemblyHandle
2288 ves_icall_System_Reflection_Assembly_LoadFile_internal (MonoStringHandle fname
, MonoError
*error
)
2290 MonoDomain
*domain
= mono_domain_get ();
2291 MonoReflectionAssemblyHandle result
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2292 char *filename
= NULL
;
2293 if (MONO_HANDLE_IS_NULL (fname
)) {
2294 mono_error_set_argument_null (error
, "assemblyFile", "");
2298 filename
= mono_string_handle_to_utf8 (fname
, error
);
2299 goto_if_nok (error
, leave
);
2301 MonoImageOpenStatus status
;
2303 MonoMethod
*executing_method
= mono_runtime_get_caller_no_system_or_reflection ();
2304 MonoAssembly
*executing_assembly
= executing_method
? m_class_get_image (executing_method
->klass
)->assembly
: NULL
;
2305 MonoAssembly
*ass
= mono_assembly_open_predicate (filename
, MONO_ASMCTX_INDIVIDUAL
, NULL
, NULL
, executing_assembly
, &status
);
2307 if (status
== MONO_IMAGE_IMAGE_INVALID
)
2308 mono_error_set_bad_image_by_name (error
, filename
, "Invalid Image");
2310 mono_error_set_file_not_found (error
, filename
, "Invalid Image");
2314 result
= mono_assembly_get_object_handle (domain
, ass
, error
);
2321 MonoReflectionAssemblyHandle
2322 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad
,
2323 MonoArrayHandle raw_assembly
,
2324 MonoArrayHandle raw_symbol_store
, MonoObjectHandle evidence
,
2325 MonoBoolean refonly
,
2330 MonoReflectionAssemblyHandle refass
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2331 MonoDomain
*domain
= MONO_HANDLE_GETVAL(ad
, data
);
2332 MonoImageOpenStatus status
;
2333 guint32 raw_assembly_len
= mono_array_handle_length (raw_assembly
);
2335 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2336 char *assembly_data
= (char*) g_try_malloc (raw_assembly_len
);
2337 if (!assembly_data
) {
2338 mono_error_set_out_of_memory (error
, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len
);
2342 mono_byte
*raw_data
= (mono_byte
*) MONO_ARRAY_HANDLE_PIN (raw_assembly
, gchar
, 0, &gchandle
);
2343 memcpy (assembly_data
, raw_data
, raw_assembly_len
);
2344 mono_gchandle_free (gchandle
); /* unpin */
2345 MONO_HANDLE_ASSIGN (raw_assembly
, NULL_HANDLE
); /* don't reference the data anymore */
2347 MonoImage
*image
= mono_image_open_from_data_full (assembly_data
, raw_assembly_len
, FALSE
, NULL
, refonly
);
2350 mono_error_set_bad_image_by_name (error
, "In memory assembly", "0x%p", raw_data
);
2354 if (!MONO_HANDLE_IS_NULL(raw_symbol_store
)) {
2355 guint32 symbol_len
= mono_array_handle_length (raw_symbol_store
);
2356 uint32_t symbol_gchandle
;
2357 mono_byte
*raw_symbol_data
= (mono_byte
*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store
, mono_byte
, 0, &symbol_gchandle
);
2358 mono_debug_open_image_from_memory (image
, raw_symbol_data
, symbol_len
);
2359 mono_gchandle_free (symbol_gchandle
);
2362 MonoAssembly
* redirected_asm
= NULL
;
2363 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2364 if ((redirected_asm
= mono_assembly_binding_applies_to_image (image
, &new_status
))) {
2365 mono_image_close (image
);
2366 image
= redirected_asm
->image
;
2367 mono_image_addref (image
); /* so that mono_image close, below, has something to do */
2368 } else if (new_status
!= MONO_IMAGE_OK
) {
2369 mono_image_close (image
);
2370 mono_error_set_bad_image_by_name (error
, "In Memory assembly", "0x%p was assembly binding redirected to another assembly that failed to load", assembly_data
);
2374 ass
= mono_assembly_load_from_predicate (image
, "", refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_INDIVIDUAL
, NULL
, NULL
, &status
);
2378 mono_image_close (image
);
2379 mono_error_set_bad_image_by_name (error
, "In Memory assembly", "0x%p", assembly_data
);
2383 /* Clear the reference added by mono_image_open_from_data_full above */
2384 mono_image_close (image
);
2386 refass
= mono_assembly_get_object_handle (domain
, ass
, error
);
2387 if (!MONO_HANDLE_IS_NULL(refass
))
2388 MONO_HANDLE_SET (refass
, evidence
, evidence
);
2392 MonoReflectionAssemblyHandle
2393 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad
, MonoStringHandle assRef
, MonoObjectHandle evidence
, MonoBoolean refOnly
, MonoError
*error
)
2396 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
2397 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2399 MonoAssemblyName aname
;
2405 name
= mono_string_handle_to_utf8 (assRef
, error
);
2406 goto_if_nok (error
, fail
);
2407 parsed
= mono_assembly_name_parse (name
, &aname
);
2411 MonoReflectionAssemblyHandle refass
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2412 /* This is a parse error... */
2414 MonoAssembly
*assm
= mono_try_assembly_resolve_handle (domain
, assRef
, NULL
, refOnly
, error
);
2415 goto_if_nok (error
, fail
);
2417 refass
= mono_assembly_get_object_handle (domain
, assm
, error
);
2418 goto_if_nok (error
, fail
);
2424 MonoAssemblyContextKind asmctx
= refOnly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
;
2425 const char *basedir
= NULL
;
2427 /* Determine if the current assembly is in LoadFrom context.
2428 * If it is, we must include the executing assembly's basedir
2429 * when probing for the given assembly name, and also load the
2430 * requested assembly in LoadFrom context.
2432 MonoMethod
*executing_method
= mono_runtime_get_caller_no_system_or_reflection ();
2433 MonoAssembly
*executing_assembly
= executing_method
? m_class_get_image (executing_method
->klass
)->assembly
: NULL
;
2434 if (executing_assembly
&& mono_asmctx_get_kind (&executing_assembly
->context
) == MONO_ASMCTX_LOADFROM
) {
2435 asmctx
= MONO_ASMCTX_LOADFROM
;
2436 basedir
= executing_assembly
->basedir
;
2441 ass
= mono_assembly_load_full_nosearch (&aname
, basedir
, asmctx
, &status
);
2442 mono_assembly_name_free (&aname
);
2445 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2447 ass
= mono_try_assembly_resolve_handle (domain
, assRef
, NULL
, refOnly
, error
);
2448 goto_if_nok (error
, fail
);
2455 MonoReflectionAssemblyHandle refass
= mono_assembly_get_object_handle (domain
, ass
, error
);
2456 goto_if_nok (error
, fail
);
2458 MONO_HANDLE_SET (refass
, evidence
, evidence
);
2462 return MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2466 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id
, MonoError
*error
)
2469 MonoDomain
* domain
= mono_domain_get_by_id (domain_id
);
2471 if (NULL
== domain
) {
2472 mono_error_set_execution_engine (error
, "Failed to unload domain, domain id not found");
2476 if (domain
== mono_get_root_domain ()) {
2477 mono_error_set_generic_error (error
, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2482 * Unloading seems to cause problems when running NUnit/NAnt, hence
2485 if (g_hasenv ("MONO_NO_UNLOAD"))
2488 MonoException
*exc
= NULL
;
2489 mono_domain_try_unload (domain
, (MonoObject
**)&exc
);
2491 mono_error_set_exception_instance (error
, exc
);
2495 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id
, MonoError
*error
)
2498 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2503 return mono_domain_is_unloading (domain
);
2507 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc
, MonoError
*error
)
2510 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject
, exc
), error
);
2511 mono_error_assert_ok (error
);
2515 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad
,
2516 MonoReflectionAssemblyHandle refass
, MonoArrayHandle args
,
2523 g_assert (!MONO_HANDLE_IS_NULL (refass
));
2524 MonoAssembly
*assembly
= MONO_HANDLE_GETVAL (refass
, assembly
);
2525 image
= assembly
->image
;
2528 method
= mono_get_method_checked (image
, mono_image_get_entry_point (image
), NULL
, NULL
, error
);
2531 g_error ("No entry point method found in %s due to %s", image
->name
, mono_error_get_message (error
));
2533 if (MONO_HANDLE_IS_NULL (args
)) {
2534 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
2535 MONO_HANDLE_ASSIGN (args
, mono_array_new_handle (domain
, mono_defaults
.string_class
, 0, error
));
2536 mono_error_assert_ok (error
);
2539 int res
= mono_runtime_exec_main_checked (method
, MONO_HANDLE_RAW (args
), error
);
2544 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain
* ad
)
2546 return ad
->data
->domain_id
;
2550 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad
, MonoError
* error
)
2553 MonoDomain
*old_domain
= mono_domain_get ();
2555 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad
, data
), FALSE
)) {
2556 mono_error_set_appdomain_unloaded (error
);
2557 return MONO_HANDLE_CAST (MonoAppDomain
, NULL_HANDLE
);
2560 return MONO_HANDLE_NEW (MonoAppDomain
, old_domain
->domain
);
2564 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid
, MonoError
*error
)
2566 MonoDomain
*current_domain
= mono_domain_get ();
2567 MonoDomain
*domain
= mono_domain_get_by_id (domainid
);
2569 if (!domain
|| !mono_domain_set (domain
, FALSE
)) {
2570 mono_error_set_appdomain_unloaded (error
);
2571 return MONO_HANDLE_CAST (MonoAppDomain
, NULL_HANDLE
);
2574 return MONO_HANDLE_NEW (MonoAppDomain
, current_domain
->domain
);
2578 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad
, MonoError
*error
)
2581 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad
, data
));
2585 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id
, MonoError
*error
)
2588 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2592 * Raise an exception to prevent the managed code from executing a pop
2595 mono_error_set_appdomain_unloaded (error
);
2599 mono_thread_push_appdomain_ref (domain
);
2603 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError
*error
)
2606 mono_thread_pop_appdomain_ref ();
2609 MonoAppContextHandle
2610 ves_icall_System_AppDomain_InternalGetContext (MonoError
*error
)
2613 return mono_context_get_handle ();
2616 MonoAppContextHandle
2617 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError
*error
)
2620 return MONO_HANDLE_NEW (MonoAppContext
, mono_domain_get ()->default_context
);
2623 MonoAppContextHandle
2624 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc
, MonoError
*error
)
2627 MonoAppContextHandle old_context
= mono_context_get_handle ();
2629 mono_context_set_handle (mc
);
2635 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid
, MonoError
*error
)
2638 MonoDomain
* mono_root_domain
= mono_get_root_domain ();
2639 mono_domain_lock (mono_root_domain
);
2640 if (process_guid_set
) {
2641 mono_domain_unlock (mono_root_domain
);
2642 return mono_string_new_utf16_handle (mono_domain_get (), process_guid
, sizeof(process_guid
)/2, error
);
2644 uint32_t gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, newguid
), TRUE
);
2645 memcpy (process_guid
, mono_string_chars(MONO_HANDLE_RAW (newguid
)), sizeof(process_guid
));
2646 mono_gchandle_free (gchandle
);
2647 process_guid_set
= TRUE
;
2648 mono_domain_unlock (mono_root_domain
);
2653 * mono_domain_is_unloading:
2656 mono_domain_is_unloading (MonoDomain
*domain
)
2658 if (domain
->state
== MONO_APPDOMAIN_UNLOADING
|| domain
->state
== MONO_APPDOMAIN_UNLOADED
)
2665 clear_cached_vtable (MonoVTable
*vtable
)
2667 MonoClass
*klass
= vtable
->klass
;
2668 MonoDomain
*domain
= vtable
->domain
;
2669 MonoClassRuntimeInfo
*runtime_info
;
2672 runtime_info
= m_class_get_runtime_info (klass
);
2673 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
)
2674 runtime_info
->domain_vtables
[domain
->domain_id
] = NULL
;
2675 if (m_class_has_static_refs (klass
) && (data
= mono_vtable_get_static_field_data (vtable
)))
2676 mono_gc_free_fixed (data
);
2679 static G_GNUC_UNUSED
void
2680 zero_static_data (MonoVTable
*vtable
)
2682 MonoClass
*klass
= vtable
->klass
;
2685 if (m_class_has_static_refs (klass
) && (data
= mono_vtable_get_static_field_data (vtable
)))
2686 mono_gc_bzero_aligned (data
, mono_class_data_size (klass
));
2689 typedef struct unload_data
{
2692 char *failure_reason
;
2697 unload_data_unref (unload_data
*data
)
2701 mono_atomic_load_acquire (count
, gint32
, &data
->refcount
);
2702 g_assert (count
>= 1 && count
<= 2);
2707 } while (mono_atomic_cas_i32 (&data
->refcount
, count
- 1, count
) != count
);
2711 deregister_reflection_info_roots_from_list (MonoImage
*image
)
2713 GSList
*list
= image
->reflection_info_unregister_classes
;
2716 MonoClass
*klass
= (MonoClass
*)list
->data
;
2718 mono_class_free_ref_info (klass
);
2723 image
->reflection_info_unregister_classes
= NULL
;
2727 deregister_reflection_info_roots (MonoDomain
*domain
)
2731 mono_domain_assemblies_lock (domain
);
2732 for (list
= domain
->domain_assemblies
; list
; list
= list
->next
) {
2733 MonoAssembly
*assembly
= (MonoAssembly
*)list
->data
;
2734 MonoImage
*image
= assembly
->image
;
2738 * No need to take the image lock here since dynamic images are appdomain bound and
2739 * at this point the mutator is gone. Taking the image lock here would mean
2740 * promoting it from a simple lock to a complex lock, which we better avoid if
2743 if (image_is_dynamic (image
))
2744 deregister_reflection_info_roots_from_list (image
);
2746 for (i
= 0; i
< image
->module_count
; ++i
) {
2747 MonoImage
*module
= image
->modules
[i
];
2748 if (module
&& image_is_dynamic (module
))
2749 deregister_reflection_info_roots_from_list (module
);
2752 mono_domain_assemblies_unlock (domain
);
2756 unload_thread_main (void *arg
)
2759 unload_data
*data
= (unload_data
*)arg
;
2760 MonoDomain
*domain
= data
->domain
;
2761 MonoInternalThread
*internal
;
2764 internal
= mono_thread_internal_current ();
2766 MonoString
*thread_name_str
= mono_string_new_checked (mono_domain_get (), "Domain unloader", error
);
2768 mono_thread_set_name_internal (internal
, thread_name_str
, TRUE
, FALSE
, error
);
2769 if (!is_ok (error
)) {
2770 data
->failure_reason
= g_strdup (mono_error_get_message (error
));
2771 mono_error_cleanup (error
);
2776 * FIXME: Abort our parent thread last, so we can return a failure
2777 * indication if aborting times out.
2779 if (!mono_threads_abort_appdomain_threads (domain
, -1)) {
2780 data
->failure_reason
= g_strdup_printf ("Aborting of threads in domain %s timed out.", domain
->friendly_name
);
2784 if (!mono_threadpool_remove_domain_jobs (domain
, -1)) {
2785 data
->failure_reason
= g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain
->friendly_name
);
2789 /* Finalize all finalizable objects in the doomed appdomain */
2790 if (!mono_domain_finalize (domain
, -1)) {
2791 data
->failure_reason
= g_strdup_printf ("Finalization of domain %s timed out.", domain
->friendly_name
);
2795 /* Clear references to our vtables in class->runtime_info.
2796 * We also hold the loader lock because we're going to change
2797 * class->runtime_info.
2800 mono_loader_lock (); //FIXME why do we need the loader lock here?
2801 mono_domain_lock (domain
);
2803 * We need to make sure that we don't have any remsets
2804 * pointing into static data of the to-be-freed domain because
2805 * at the next collections they would be invalid. So what we
2806 * do is we first zero all static data and then do a minor
2807 * collection. Because all references in the static data will
2808 * now be null we won't do any unnecessary copies and after
2809 * the collection there won't be any more remsets.
2811 for (i
= 0; i
< domain
->class_vtable_array
->len
; ++i
)
2812 zero_static_data ((MonoVTable
*)g_ptr_array_index (domain
->class_vtable_array
, i
));
2813 mono_gc_collect (0);
2814 for (i
= 0; i
< domain
->class_vtable_array
->len
; ++i
)
2815 clear_cached_vtable ((MonoVTable
*)g_ptr_array_index (domain
->class_vtable_array
, i
));
2816 deregister_reflection_info_roots (domain
);
2818 mono_assembly_cleanup_domain_bindings (domain
->domain_id
);
2820 mono_domain_unlock (domain
);
2821 mono_loader_unlock ();
2823 domain
->state
= MONO_APPDOMAIN_UNLOADED
;
2825 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2827 /* remove from the handle table the items related to this domain */
2828 mono_gchandle_free_domain (domain
);
2830 mono_domain_free (domain
, FALSE
);
2832 mono_gc_collect (mono_gc_max_generation ());
2834 mono_atomic_store_release (&data
->done
, TRUE
);
2835 unload_data_unref (data
);
2839 mono_atomic_store_release (&data
->done
, TRUE
);
2840 unload_data_unref (data
);
2845 * mono_domain_unload:
2846 * \param domain The domain to unload
2848 * Unloads an appdomain. Follows the process outlined in the comment
2849 * for \c mono_domain_try_unload.
2852 mono_domain_unload (MonoDomain
*domain
)
2854 MonoObject
*exc
= NULL
;
2855 mono_domain_try_unload (domain
, &exc
);
2858 static MonoThreadInfoWaitRet
2859 guarded_wait (MonoThreadHandle
*thread_handle
, guint32 timeout
, gboolean alertable
)
2861 MonoThreadInfoWaitRet result
;
2864 result
= mono_thread_info_wait_one_handle (thread_handle
, timeout
, alertable
);
2871 * mono_domain_unload:
2872 * \param domain The domain to unload
2873 * \param exc Exception information
2875 * Unloads an appdomain. Follows the process outlined in:
2876 * http://blogs.gotdotnet.com/cbrumme
2878 * If doing things the 'right' way is too hard or complex, we do it the
2879 * 'simple' way, which means do everything needed to avoid crashes and
2880 * memory leaks, but not much else.
2882 * It is required to pass a valid reference to the exc argument, upon return
2883 * from this function *exc will be set to the exception thrown, if any.
2885 * If this method is not called from an icall (embedded scenario for instance),
2886 * it must not be called with any managed frames on the stack, since the unload
2887 * process could end up trying to abort the current thread.
2890 mono_domain_try_unload (MonoDomain
*domain
, MonoObject
**exc
)
2893 MonoThreadHandle
*thread_handle
;
2894 MonoAppDomainState prev_state
;
2896 unload_data
*thread_data
;
2897 MonoInternalThread
*internal
;
2898 MonoDomain
*caller_domain
= mono_domain_get ();
2902 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2904 /* Atomically change our state to UNLOADING */
2905 prev_state
= (MonoAppDomainState
)mono_atomic_cas_i32 ((gint32
*)&domain
->state
,
2906 MONO_APPDOMAIN_UNLOADING_START
,
2907 MONO_APPDOMAIN_CREATED
);
2908 if (prev_state
!= MONO_APPDOMAIN_CREATED
) {
2909 switch (prev_state
) {
2910 case MONO_APPDOMAIN_UNLOADING_START
:
2911 case MONO_APPDOMAIN_UNLOADING
:
2912 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2914 case MONO_APPDOMAIN_UNLOADED
:
2915 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2918 g_warning ("Invalid appdomain state %d", prev_state
);
2919 g_assert_not_reached ();
2923 mono_domain_set (domain
, FALSE
);
2924 /* Notify OnDomainUnload listeners */
2925 method
= mono_class_get_method_from_name_checked (domain
->domain
->mbr
.obj
.vtable
->klass
, "DoDomainUnload", -1, 0, error
);
2928 mono_runtime_try_invoke (method
, domain
->domain
, NULL
, exc
, error
);
2930 if (!mono_error_ok (error
)) {
2932 mono_error_cleanup (error
);
2934 *exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
2938 /* Roll back the state change */
2939 domain
->state
= MONO_APPDOMAIN_CREATED
;
2940 mono_domain_set (caller_domain
, FALSE
);
2943 mono_domain_set (caller_domain
, FALSE
);
2945 thread_data
= g_new0 (unload_data
, 1);
2946 thread_data
->domain
= domain
;
2947 thread_data
->failure_reason
= NULL
;
2948 thread_data
->done
= FALSE
;
2949 thread_data
->refcount
= 2; /*Must be 2: unload thread + initiator */
2951 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2952 domain
->state
= MONO_APPDOMAIN_UNLOADING
;
2954 * First we create a separate thread for unloading, since
2955 * we might have to abort some threads, including the current one.
2957 * Have to attach to the runtime so shutdown can wait for this thread.
2959 * Force it to be attached to avoid racing during shutdown.
2961 internal
= mono_thread_create_internal (mono_get_root_domain (), unload_thread_main
, thread_data
, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
, error
);
2962 mono_error_assert_ok (error
);
2964 thread_handle
= mono_threads_open_thread_handle (internal
->handle
);
2966 /* Wait for the thread */
2967 while (!thread_data
->done
&& guarded_wait (thread_handle
, MONO_INFINITE_WAIT
, TRUE
) == MONO_THREAD_INFO_WAIT_RET_ALERTED
) {
2968 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain
) && (mono_thread_interruption_requested ())) {
2969 /* The unload thread tries to abort us */
2970 /* The icall wrapper will execute the abort */
2971 mono_threads_close_thread_handle (thread_handle
);
2972 unload_data_unref (thread_data
);
2977 mono_threads_close_thread_handle (thread_handle
);
2979 if (thread_data
->failure_reason
) {
2980 /* Roll back the state change */
2981 domain
->state
= MONO_APPDOMAIN_CREATED
;
2983 g_warning ("%s", thread_data
->failure_reason
);
2985 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain (thread_data
->failure_reason
);
2987 g_free (thread_data
->failure_reason
);
2988 thread_data
->failure_reason
= NULL
;
2991 unload_data_unref (thread_data
);