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>
79 #include "object-internals.h"
80 #include "icall-decl.h"
85 int assemblybinding_count
;
90 static gunichar2 process_guid
[36];
91 static gboolean process_guid_set
= FALSE
;
93 static gboolean no_exec
= FALSE
;
96 mono_check_corlib_version_internal (void);
99 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
100 gchar
**assemblies_path
,
103 static MonoAssembly
*
104 mono_domain_assembly_search (MonoAssemblyName
*aname
,
108 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
);
111 mono_domain_asmctx_from_path (const char *fname
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
);
114 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*hash
);
116 static MonoAppDomainHandle
117 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetupHandle setup
, MonoError
*error
);
120 mono_domain_create_appdomain_checked (char *friendly_name
, char *configuration_file
, MonoError
*error
);
124 mono_context_set_default_context (MonoDomain
*domain
);
127 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
);
129 static MonoLoadFunc load_function
= NULL
;
131 /* Lazy class loading functions */
132 static GENERATE_GET_CLASS_WITH_CACHE (assembly
, "System.Reflection", "Assembly");
134 GENERATE_GET_CLASS_WITH_CACHE (appdomain
, MONO_APPDOMAIN_CLASS_NAME_SPACE
, MONO_APPDOMAIN_CLASS_NAME
);
135 GENERATE_GET_CLASS_WITH_CACHE (appdomain_setup
, MONO_APPDOMAIN_SETUP_CLASS_NAME_SPACE
, MONO_APPDOMAIN_SETUP_CLASS_NAME
);
138 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain
);
141 mono_error_set_appdomain_unloaded (MonoError
*error
)
143 mono_error_set_generic_error (error
, "System", "AppDomainUnloadedException", "");
147 mono_install_runtime_load (MonoLoadFunc func
)
149 load_function
= func
;
153 mono_runtime_load (const char *filename
, const char *runtime_version
)
155 g_assert (load_function
);
156 return load_function (filename
, runtime_version
);
160 * mono_runtime_set_no_exec:
162 * Instructs the runtime to operate in static mode, i.e. avoid/do not
163 * allow managed code execution. This is useful for running the AOT
164 * compiler on platforms which allow full-aot execution only. This
165 * should be called before mono_runtime_init ().
168 mono_runtime_set_no_exec (gboolean val
)
174 * mono_runtime_get_no_exec:
176 * If true, then the runtime will not allow managed code execution.
179 mono_runtime_get_no_exec (void)
185 create_domain_objects (MonoDomain
*domain
)
187 HANDLE_FUNCTION_ENTER ();
190 MonoDomain
*old_domain
= mono_domain_get ();
191 MonoStringHandle arg
;
192 MonoVTable
*string_vt
;
193 MonoClassField
*string_empty_fld
;
195 if (domain
!= old_domain
) {
196 mono_thread_push_appdomain_ref (domain
);
197 mono_domain_set_internal_with_options (domain
, FALSE
);
201 * Initialize String.Empty. This enables the removal of
202 * the static cctor of the String class.
204 string_vt
= mono_class_vtable_checked (domain
, mono_defaults
.string_class
, error
);
205 mono_error_assert_ok (error
);
206 string_empty_fld
= mono_class_get_field_from_name_full (mono_defaults
.string_class
, "Empty", NULL
);
207 g_assert (string_empty_fld
);
208 MonoStringHandle empty_str
= mono_string_new_handle (domain
, "", error
);
209 mono_error_assert_ok (error
);
210 empty_str
= mono_string_intern_checked (empty_str
, error
);
211 mono_error_assert_ok (error
);
212 mono_field_static_set_value_internal (string_vt
, string_empty_fld
, MONO_HANDLE_RAW (empty_str
));
213 domain
->empty_string
= MONO_HANDLE_RAW (empty_str
);
216 * Create an instance early since we can't do it when there is no memory.
218 arg
= mono_string_new_handle (domain
, "Out of memory", error
);
219 mono_error_assert_ok (error
);
220 domain
->out_of_memory_ex
= MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "OutOfMemoryException", arg
, NULL_HANDLE_STRING
, error
));
221 mono_error_assert_ok (error
);
224 * These two are needed because the signal handlers might be executing on
225 * an alternate stack, and Boehm GC can't handle that.
227 arg
= mono_string_new_handle (domain
, "A null value was found where an object instance was required", error
);
228 mono_error_assert_ok (error
);
229 domain
->null_reference_ex
= MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "NullReferenceException", arg
, NULL_HANDLE_STRING
, error
));
230 mono_error_assert_ok (error
);
231 arg
= mono_string_new_handle (domain
, "The requested operation caused a stack overflow.", error
);
232 mono_error_assert_ok (error
);
233 domain
->stack_overflow_ex
= MONO_HANDLE_RAW (mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "StackOverflowException", arg
, NULL_HANDLE_STRING
, error
));
234 mono_error_assert_ok (error
);
236 /*The ephemeron tombstone i*/
237 domain
->ephemeron_tombstone
= MONO_HANDLE_RAW (mono_object_new_handle (domain
, mono_defaults
.object_class
, error
));
238 mono_error_assert_ok (error
);
240 if (domain
!= old_domain
) {
241 mono_thread_pop_appdomain_ref ();
242 mono_domain_set_internal_with_options (old_domain
, FALSE
);
246 * This class is used during exception handling, so initialize it here, to prevent
247 * stack overflows while handling stack overflows.
249 mono_class_init_internal (mono_class_create_array (mono_defaults
.int_class
, 1));
250 HANDLE_FUNCTION_RETURN ();
255 * \param domain domain returned by \c mono_init
257 * Initialize the core AppDomain: this function will run also some
258 * IL initialization code, so it needs the execution engine to be fully
261 * \c AppDomain.SetupInformation is set up in \c mono_runtime_exec_main, where
262 * we know the \c entry_assembly.
266 mono_runtime_init (MonoDomain
*domain
, MonoThreadStartCB start_cb
, MonoThreadAttachCB attach_cb
)
269 mono_runtime_init_checked (domain
, start_cb
, attach_cb
, error
);
270 mono_error_cleanup (error
);
274 mono_runtime_init_checked (MonoDomain
*domain
, MonoThreadStartCB start_cb
, MonoThreadAttachCB attach_cb
, MonoError
*error
)
276 HANDLE_FUNCTION_ENTER ();
278 MonoAppDomainSetupHandle setup
;
279 MonoAppDomainHandle ad
;
283 mono_portability_helpers_init ();
285 mono_gc_base_init ();
286 mono_monitor_init ();
287 mono_marshal_init ();
288 mono_gc_init_icalls ();
290 mono_install_assembly_preload_hook (mono_domain_assembly_preload
, GUINT_TO_POINTER (FALSE
));
291 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload
, GUINT_TO_POINTER (TRUE
));
292 mono_install_assembly_search_hook (mono_domain_assembly_search
, GUINT_TO_POINTER (FALSE
));
293 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search
, GUINT_TO_POINTER (TRUE
));
294 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc
)mono_domain_assembly_postload_search
, GUINT_TO_POINTER (FALSE
));
295 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc
)mono_domain_assembly_postload_search
, GUINT_TO_POINTER (TRUE
));
296 mono_install_assembly_load_hook (mono_domain_fire_assembly_load
, NULL
);
297 mono_install_assembly_asmctx_from_path_hook (mono_domain_asmctx_from_path
, NULL
);
299 mono_thread_init (start_cb
, attach_cb
);
301 if (!mono_runtime_get_no_exec ()) {
302 MonoClass
*klass
= mono_class_get_appdomain_setup_class ();
303 setup
= MONO_HANDLE_CAST (MonoAppDomainSetup
, mono_object_new_pinned_handle (domain
, klass
, error
));
304 goto_if_nok (error
, exit
);
306 klass
= mono_class_get_appdomain_class ();
308 ad
= MONO_HANDLE_CAST (MonoAppDomain
, mono_object_new_pinned_handle (domain
, klass
, error
));
309 goto_if_nok (error
, exit
);
311 MONO_HANDLE_SETVAL (ad
, data
, MonoDomain
*, domain
);
312 domain
->domain
= MONO_HANDLE_RAW (ad
);
313 domain
->setup
= MONO_HANDLE_RAW (setup
);
316 mono_thread_attach (domain
);
318 mono_type_initialization_init ();
320 if (!mono_runtime_get_no_exec ())
321 create_domain_objects (domain
);
323 /* GC init has to happen after thread init */
326 /* contexts use GC handles, so they must be initialized after the GC */
327 mono_context_init_checked (domain
, error
);
328 goto_if_nok (error
, exit
);
329 mono_context_set_default_context (domain
);
331 #ifndef DISABLE_SOCKETS
332 mono_network_init ();
335 mono_console_init ();
338 mono_locks_tracer_init ();
340 /* mscorlib is loaded before we install the load hook */
341 mono_domain_fire_assembly_load (mono_defaults
.corlib
->assembly
, NULL
);
344 HANDLE_FUNCTION_RETURN ();
348 mono_context_set_default_context (MonoDomain
*domain
)
350 if (mono_runtime_get_no_exec ())
353 HANDLE_FUNCTION_ENTER ();
354 mono_context_set_handle (MONO_HANDLE_NEW (MonoAppContext
, domain
->default_context
));
355 HANDLE_FUNCTION_RETURN ();
359 mono_get_corlib_version (void)
364 MonoClassField
*field
;
366 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "Environment");
367 mono_class_init_internal (klass
);
368 field
= mono_class_get_field_from_name_full (klass
, "mono_corlib_version", NULL
);
372 if (! (field
->type
->attrs
& (FIELD_ATTRIBUTE_STATIC
| FIELD_ATTRIBUTE_LITERAL
)))
376 MonoTypeEnum field_type
;
377 const char *data
= mono_class_get_field_default_value (field
, &field_type
);
378 if (field_type
!= MONO_TYPE_STRING
)
380 mono_metadata_read_constant_value (data
, field_type
, &value
, error
);
381 mono_error_assert_ok (error
);
383 char *res
= mono_string_from_blob (value
, error
);
384 mono_error_assert_ok (error
);
390 * mono_check_corlib_version:
391 * Checks that the corlib that is loaded matches the version of this runtime.
392 * \returns NULL if the runtime will work with the corlib, or a \c g_malloc
393 * allocated string with the error otherwise.
396 mono_check_corlib_version (void)
399 MONO_ENTER_GC_UNSAFE
;
400 res
= mono_check_corlib_version_internal ();
406 mono_check_corlib_version_internal (void)
408 #if defined(MONO_CROSS_COMPILE)
409 /* Can't read the corlib version because we only have the target class layouts */
414 char *version
= mono_get_corlib_version ();
416 result
= g_strdup_printf ("expected corlib string (%s) but not found or not string", MONO_CORLIB_VERSION
);
419 if (strcmp (version
, MONO_CORLIB_VERSION
) != 0) {
420 result
= g_strdup_printf ("The runtime did not find the mscorlib.dll it expected. "
421 "Expected interface version %s but found %s. Check that "
422 "your runtime and class libraries are matching.",
423 MONO_CORLIB_VERSION
, version
);
427 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
428 guint32 native_offset
;
429 guint32 managed_offset
;
430 native_offset
= (guint32
) MONO_STRUCT_OFFSET (MonoInternalThread
, last
);
431 managed_offset
= mono_field_get_offset (mono_class_get_field_from_name_full (mono_defaults
.internal_thread_class
, "last", NULL
));
432 if (native_offset
!= managed_offset
)
433 result
= g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset
, managed_offset
);
441 * \param domain The domain where the \c System.Runtime.Remoting.Context.Context is initialized
442 * Initializes the \p domain's default \c System.Runtime.Remoting 's Context.
445 mono_context_init (MonoDomain
*domain
)
448 mono_context_init_checked (domain
, error
);
449 mono_error_cleanup (error
);
453 mono_context_init_checked (MonoDomain
*domain
, MonoError
*error
)
455 HANDLE_FUNCTION_ENTER ();
458 MonoAppContextHandle context
;
461 if (mono_runtime_get_no_exec ())
464 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Contexts", "Context");
465 context
= MONO_HANDLE_CAST (MonoAppContext
, mono_object_new_pinned_handle (domain
, klass
, error
));
466 goto_if_nok (error
, exit
);
468 MONO_HANDLE_SETVAL (context
, domain_id
, gint32
, domain
->domain_id
);
469 MONO_HANDLE_SETVAL (context
, context_id
, gint32
, 0);
470 mono_threads_register_app_context (context
, error
);
471 mono_error_assert_ok (error
);
472 domain
->default_context
= MONO_HANDLE_RAW (context
);
474 HANDLE_FUNCTION_RETURN ();
478 * mono_runtime_cleanup:
479 * \param domain unused.
483 * This must not be called while there are still running threads executing
487 mono_runtime_cleanup (MonoDomain
*domain
)
489 mono_attach_cleanup ();
491 /* This ends up calling any pending pending (for at most 2 seconds) */
494 mono_thread_cleanup ();
496 #ifndef DISABLE_SOCKETS
497 mono_network_cleanup ();
499 mono_marshal_cleanup ();
501 mono_type_initialization_cleanup ();
503 mono_monitor_cleanup ();
506 static MonoDomainFunc quit_function
= NULL
;
509 * mono_install_runtime_cleanup:
512 mono_install_runtime_cleanup (MonoDomainFunc func
)
514 quit_function
= func
;
523 if (quit_function
!= NULL
)
524 quit_function (mono_get_root_domain (), NULL
);
528 * mono_domain_create_appdomain:
529 * \param friendly_name The friendly name of the appdomain to create
530 * \param configuration_file The configuration file to initialize the appdomain with
531 * \returns a \c MonoDomain initialized with the appdomain
534 mono_domain_create_appdomain (char *friendly_name
, char *configuration_file
)
536 HANDLE_FUNCTION_ENTER ();
538 MONO_ENTER_GC_UNSAFE
;
540 domain
= mono_domain_create_appdomain_checked (friendly_name
, configuration_file
, error
);
541 mono_error_cleanup (error
);
543 HANDLE_FUNCTION_RETURN_VAL (domain
);
547 * mono_domain_create_appdomain_checked:
548 * \param friendly_name The friendly name of the appdomain to create
549 * \param configuration_file The configuration file to initialize the appdomain with
550 * \param error Set on error.
552 * \returns a MonoDomain initialized with the appdomain. On failure sets \p error and returns NULL.
555 mono_domain_create_appdomain_checked (char *friendly_name
, char *configuration_file
, MonoError
*error
)
557 HANDLE_FUNCTION_ENTER ();
559 MonoDomain
*result
= NULL
;
561 MonoClass
*klass
= mono_class_get_appdomain_setup_class ();
562 MonoAppDomainSetupHandle setup
= MONO_HANDLE_CAST (MonoAppDomainSetup
, mono_object_new_handle (mono_domain_get (), klass
, error
));
563 goto_if_nok (error
, leave
);
564 MonoStringHandle config_file
;
565 if (configuration_file
!= NULL
) {
566 config_file
= mono_string_new_handle (mono_domain_get (), configuration_file
, error
);
567 goto_if_nok (error
, leave
);
569 config_file
= MONO_HANDLE_NEW (MonoString
, NULL
);
571 MONO_HANDLE_SET (setup
, configuration_file
, config_file
);
573 MonoAppDomainHandle ad
;
574 ad
= mono_domain_create_appdomain_internal (friendly_name
, setup
, error
);
575 goto_if_nok (error
, leave
);
577 result
= mono_domain_from_appdomain_handle (ad
);
579 HANDLE_FUNCTION_RETURN_VAL (result
);
583 * mono_domain_set_config:
584 * \param domain \c MonoDomain initialized with the appdomain we want to change
585 * \param base_dir new base directory for the appdomain
586 * \param config_file_name path to the new configuration for the app domain
588 * Used to set the system configuration for an appdomain
590 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
591 * Error Initializing the configuration system. ---> System.ArgumentException:
592 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
595 mono_domain_set_config (MonoDomain
*domain
, const char *base_dir
, const char *config_file_name
)
597 HANDLE_FUNCTION_ENTER ();
598 MONO_ENTER_GC_UNSAFE
;
600 mono_domain_set_config_checked (domain
, base_dir
, config_file_name
, error
);
601 mono_error_cleanup (error
);
603 HANDLE_FUNCTION_RETURN ();
607 mono_domain_set_config_checked (MonoDomain
*domain
, const char *base_dir
, const char *config_file_name
, MonoError
*error
)
610 MonoAppDomainSetupHandle setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
);
611 MonoStringHandle base_dir_str
= mono_string_new_handle (domain
, base_dir
, error
);
612 goto_if_nok (error
, leave
);
613 MONO_HANDLE_SET (setup
, application_base
, base_dir_str
);
614 MonoStringHandle config_file_name_str
;
615 config_file_name_str
= mono_string_new_handle (domain
, config_file_name
, error
);
616 goto_if_nok (error
, leave
);
617 MONO_HANDLE_SET (setup
, configuration_file
, config_file_name_str
);
619 return is_ok (error
);
622 static MonoAppDomainSetupHandle
623 copy_app_domain_setup (MonoDomain
*domain
, MonoAppDomainSetupHandle setup
, MonoError
*error
)
625 HANDLE_FUNCTION_ENTER ();
626 MonoDomain
*caller_domain
;
627 MonoClass
*ads_class
;
628 MonoAppDomainSetupHandle result
= MONO_HANDLE_NEW (MonoAppDomainSetup
, NULL
);
632 caller_domain
= mono_domain_get ();
633 ads_class
= mono_class_get_appdomain_setup_class ();
635 MonoAppDomainSetupHandle copy
= MONO_HANDLE_CAST (MonoAppDomainSetup
, mono_object_new_handle(domain
, ads_class
, error
));
636 goto_if_nok (error
, leave
);
638 mono_domain_set_internal (domain
);
640 #define XCOPY_FIELD(type, dst, field, src, error) \
642 TYPED_HANDLE_NAME (type) src_val = MONO_HANDLE_NEW_GET (type, (src), field); \
643 TYPED_HANDLE_NAME (type) copied_val = MONO_HANDLE_CAST (type, mono_marshal_xdomain_copy_value_handle (MONO_HANDLE_CAST (MonoObject, src_val), error)); \
644 goto_if_nok (error, leave); \
645 MONO_HANDLE_SET ((dst),field,copied_val); \
648 #define COPY_VAL(dst,field,type,src) \
650 MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
653 XCOPY_FIELD (MonoString
, copy
, application_base
, setup
, error
);
654 XCOPY_FIELD (MonoString
, copy
, application_name
, setup
, error
);
655 XCOPY_FIELD (MonoString
, copy
, cache_path
, setup
, error
);
656 XCOPY_FIELD (MonoString
, copy
, configuration_file
, setup
, error
);
657 XCOPY_FIELD (MonoString
, copy
, dynamic_base
, setup
, error
);
658 XCOPY_FIELD (MonoString
, copy
, license_file
, setup
, error
);
659 XCOPY_FIELD (MonoString
, copy
, private_bin_path
, setup
, error
);
660 XCOPY_FIELD (MonoString
, copy
, private_bin_path_probe
, setup
, error
);
661 XCOPY_FIELD (MonoString
, copy
, shadow_copy_directories
, setup
, error
);
662 XCOPY_FIELD (MonoString
, copy
, shadow_copy_files
, setup
, error
);
663 COPY_VAL (copy
, publisher_policy
, MonoBoolean
, setup
);
664 COPY_VAL (copy
, path_changed
, MonoBoolean
, setup
);
665 COPY_VAL (copy
, loader_optimization
, int, setup
);
666 COPY_VAL (copy
, disallow_binding_redirects
, MonoBoolean
, setup
);
667 COPY_VAL (copy
, disallow_code_downloads
, MonoBoolean
, setup
);
668 XCOPY_FIELD (MonoArray
, copy
, domain_initializer_args
, setup
, error
);
669 COPY_VAL (copy
, disallow_appbase_probe
, MonoBoolean
, setup
);
670 XCOPY_FIELD (MonoObject
, copy
, application_trust
, setup
, error
);
671 XCOPY_FIELD (MonoArray
, copy
, configuration_bytes
, setup
, error
);
672 XCOPY_FIELD (MonoArray
, copy
, serialized_non_primitives
, setup
, error
);
677 mono_domain_set_internal (caller_domain
);
679 MONO_HANDLE_ASSIGN (result
, copy
);
681 HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup
, result
);
684 static MonoAppDomainHandle
685 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetupHandle setup
, MonoError
*error
)
687 HANDLE_FUNCTION_ENTER ();
688 MonoAppDomainHandle result
= MONO_HANDLE_NEW (MonoAppDomain
, NULL
);
694 adclass
= mono_class_get_appdomain_class ();
696 /* FIXME: pin all those objects */
697 data
= mono_domain_create();
699 MonoAppDomainHandle ad
= MONO_HANDLE_CAST (MonoAppDomain
, mono_object_new_handle (data
, adclass
, error
));
700 goto_if_nok (error
, leave
);
701 MONO_HANDLE_SETVAL (ad
, data
, MonoDomain
*, data
);
702 data
->domain
= MONO_HANDLE_RAW (ad
);
703 data
->friendly_name
= g_strdup (friendly_name
);
705 MONO_PROFILER_RAISE (domain_name
, (data
, data
->friendly_name
));
707 MonoStringHandle app_base
;
708 app_base
= MONO_HANDLE_NEW_GET (MonoString
, setup
, application_base
);
709 if (MONO_HANDLE_IS_NULL (app_base
)) {
710 /* Inherit from the root domain since MS.NET does this */
711 MonoDomain
*root
= mono_get_root_domain ();
712 MonoAppDomainSetupHandle root_setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, root
->setup
);
713 MonoStringHandle root_app_base
= MONO_HANDLE_NEW_GET (MonoString
, root_setup
, application_base
);
714 if (!MONO_HANDLE_IS_NULL (root_app_base
)) {
715 /* N.B. new string is in the new domain */
716 uint32_t gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, root_app_base
), TRUE
);
717 MonoStringHandle s
= mono_string_new_utf16_handle (data
, mono_string_chars_internal (MONO_HANDLE_RAW (root_app_base
)), mono_string_handle_length (root_app_base
), error
);
718 mono_gchandle_free_internal (gchandle
);
719 if (!is_ok (error
)) {
720 g_free (data
->friendly_name
);
723 MONO_HANDLE_SET (setup
, application_base
, s
);
727 mono_context_init_checked (data
, error
);
728 goto_if_nok (error
, leave
);
730 data
->setup
= MONO_HANDLE_RAW (copy_app_domain_setup (data
, setup
, error
));
731 if (!mono_error_ok (error
)) {
732 g_free (data
->friendly_name
);
736 mono_domain_set_options_from_config (data
);
737 add_assemblies_to_domain (data
, mono_defaults
.corlib
->assembly
, NULL
);
739 #ifndef DISABLE_SHADOW_COPY
740 /*FIXME, guard this for when the debugger is not running */
741 char *shadow_location
;
742 shadow_location
= get_shadow_assembly_location_base (data
, error
);
743 if (!mono_error_ok (error
)) {
744 g_free (data
->friendly_name
);
748 g_free (shadow_location
);
751 create_domain_objects (data
);
753 MONO_HANDLE_ASSIGN (result
, ad
);
755 HANDLE_FUNCTION_RETURN_REF (MonoAppDomain
, result
);
759 * mono_domain_has_type_resolve:
760 * \param domain application domain being looked up
762 * \returns TRUE if the \c AppDomain.TypeResolve field has been set.
765 mono_domain_has_type_resolve (MonoDomain
*domain
)
767 static MonoClassField
*field
= NULL
;
771 field
= mono_class_get_field_from_name_full (mono_defaults
.appdomain_class
, "TypeResolve", NULL
);
775 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
779 mono_field_get_value_internal ((MonoObject
*)(domain
->domain
), field
, &o
);
784 * mono_domain_try_type_resolve:
785 * \param domain application domain in which to resolve the type
786 * \param name the name of the type to resolve or NULL.
787 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder, used if name is NULL.
789 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
790 * the assembly that matches name, or ((TypeBuilder)typebuilder).FullName.
792 * \returns A \c MonoReflectionAssembly or NULL if not found
794 MonoReflectionAssembly
*
795 mono_domain_try_type_resolve (MonoDomain
*domain
, char *name
, MonoObject
*typebuilder_raw
)
797 HANDLE_FUNCTION_ENTER ();
800 g_assert (name
|| typebuilder_raw
);
804 MonoReflectionAssemblyHandle ret
= NULL_HANDLE_INIT
;
807 MonoStringHandle name_handle
= mono_string_new_handle (mono_domain_get (), name
, error
);
808 goto_if_nok (error
, exit
);
809 ret
= mono_domain_try_type_resolve_name (domain
, name_handle
, error
);
811 MONO_HANDLE_DCL (MonoObject
, typebuilder
);
812 ret
= mono_domain_try_type_resolve_typebuilder (domain
, MONO_HANDLE_CAST (MonoReflectionTypeBuilder
, typebuilder
), error
);
816 mono_error_cleanup (error
);
817 HANDLE_FUNCTION_RETURN_OBJ (ret
);
821 * mono_class_get_appdomain_do_type_resolve_method:
823 * This routine returns System.AppDomain.DoTypeResolve.
826 mono_class_get_appdomain_do_type_resolve_method (MonoError
*error
)
828 static MonoMethod
*method
; // cache
833 // not cached yet, fill cache under caller's lock
835 method
= mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoTypeResolve", -1, 0, error
);
838 g_warning ("%s method AppDomain.DoTypeResolve not found. %s\n", __func__
, mono_error_get_message (error
));
844 * mono_domain_try_type_resolve_name:
845 * \param domain application domain in which to resolve the type
846 * \param name the name of the type to resolve.
848 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
849 * the assembly that matches name.
851 * \returns A \c MonoReflectionAssembly or NULL if not found
853 MonoReflectionAssemblyHandle
854 mono_domain_try_type_resolve_name (MonoDomain
*domain
, MonoStringHandle name
, MonoError
*error
)
856 HANDLE_FUNCTION_ENTER ();
858 void *params
[1] = { 0 };
861 g_assert (MONO_HANDLE_BOOL (name
));
867 method
= mono_class_get_appdomain_do_type_resolve_method (error
);
868 goto_if_nok (error
, return_null
);
870 MonoAppDomainHandle appdomain
;
871 appdomain
= MONO_HANDLE_NEW (MonoAppDomain
, domain
->domain
);
873 MonoObjectHandle ret
;
874 params
[0] = MONO_HANDLE_RAW (name
);
875 ret
= mono_runtime_invoke_handle (method
, MONO_HANDLE_CAST (MonoObject
, appdomain
), params
, error
);
876 goto_if_nok (error
, return_null
);
881 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly
, MONO_HANDLE_CAST (MonoReflectionAssembly
, ret
));
885 * mono_domain_try_type_resolve_typebuilder:
886 * \param domain application domain in which to resolve the type
887 * \param typebuilder A \c System.Reflection.Emit.TypeBuilder; typebuilder.FullName is the name of the type to resolve.
889 * This routine invokes the internal \c System.AppDomain.DoTypeResolve and returns
890 * the assembly that matches typebuilder.FullName.
892 * \returns A \c MonoReflectionAssembly or NULL_HANDLE if not found
894 MonoReflectionAssemblyHandle
895 mono_domain_try_type_resolve_typebuilder (MonoDomain
*domain
, MonoReflectionTypeBuilderHandle typebuilder
, MonoError
*error
)
897 HANDLE_FUNCTION_ENTER ();
900 g_assert (MONO_HANDLE_BOOL (typebuilder
));
905 MonoMethod
* const method
= mono_class_get_appdomain_do_type_resolve_method (error
);
906 goto_if_nok (error
, return_null
);
908 MonoAppDomainHandle appdomain
;
909 appdomain
= MONO_HANDLE_NEW (MonoAppDomain
, domain
->domain
);
911 args
[0] = MONO_HANDLE_RAW (typebuilder
);
913 MonoObjectHandle ret
;
914 ret
= mono_runtime_invoke_handle (method
, MONO_HANDLE_CAST (MonoObject
, appdomain
), args
, error
);
915 goto_if_nok (error
, return_null
);
920 HANDLE_FUNCTION_RETURN_REF (MonoReflectionAssembly
, MONO_HANDLE_CAST (MonoReflectionAssembly
, ret
));
924 * mono_domain_owns_vtable_slot:
925 * \returns Whether \p vtable_slot is inside a vtable which belongs to \p domain.
928 mono_domain_owns_vtable_slot (MonoDomain
*domain
, gpointer vtable_slot
)
932 mono_domain_lock (domain
);
933 res
= mono_mempool_contains_addr (domain
->mp
, vtable_slot
);
934 mono_domain_unlock (domain
);
940 * \param domain domain
941 * \param force force setting.
943 * Set the current appdomain to \p domain. If \p force is set, set it even
944 * if it is being unloaded.
946 * \returns TRUE on success; FALSE if the domain is unloaded
949 mono_domain_set (MonoDomain
*domain
, gboolean force
)
951 if (!force
&& domain
->state
== MONO_APPDOMAIN_UNLOADED
)
954 MONO_ENTER_GC_UNSAFE
;
955 mono_domain_set_internal (domain
);
961 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad
, MonoStringHandle name
, MonoError
*error
)
965 if (MONO_HANDLE_IS_NULL (name
)) {
966 mono_error_set_argument_null (error
, "name", "");
970 g_assert (!MONO_HANDLE_IS_NULL (ad
));
971 MonoDomain
*add
= MONO_HANDLE_GETVAL (ad
, data
);
974 char *str
= mono_string_handle_to_utf8 (name
, error
);
975 return_val_if_nok (error
, NULL_HANDLE
);
977 mono_domain_lock (add
);
979 MonoAppDomainSetupHandle ad_setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, add
->setup
);
981 if (!strcmp (str
, "APPBASE"))
982 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, application_base
);
983 else if (!strcmp (str
, "APP_CONFIG_FILE"))
984 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, configuration_file
);
985 else if (!strcmp (str
, "DYNAMIC_BASE"))
986 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, dynamic_base
);
987 else if (!strcmp (str
, "APP_NAME"))
988 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, application_name
);
989 else if (!strcmp (str
, "CACHE_BASE"))
990 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, cache_path
);
991 else if (!strcmp (str
, "PRIVATE_BINPATH"))
992 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, private_bin_path
);
993 else if (!strcmp (str
, "BINPATH_PROBE_ONLY"))
994 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, private_bin_path_probe
);
995 else if (!strcmp (str
, "SHADOW_COPY_DIRS"))
996 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, shadow_copy_directories
);
997 else if (!strcmp (str
, "FORCE_CACHE_INSTALL"))
998 o
= MONO_HANDLE_NEW_GET (MonoString
, ad_setup
, shadow_copy_files
);
1000 o
= MONO_HANDLE_NEW (MonoString
, (MonoString
*)mono_g_hash_table_lookup (add
->env
, MONO_HANDLE_RAW (name
)));
1002 mono_domain_unlock (add
);
1005 return MONO_HANDLE_CAST (MonoObject
, o
);
1009 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad
, MonoStringHandle name
, MonoObjectHandle data
, MonoError
*error
)
1013 if (MONO_HANDLE_IS_NULL (name
)) {
1014 mono_error_set_argument_null (error
, "name", "");
1018 g_assert (!MONO_HANDLE_IS_NULL (ad
));
1019 MonoDomain
*add
= MONO_HANDLE_GETVAL (ad
, data
);
1022 mono_domain_lock (add
);
1024 mono_g_hash_table_insert (add
->env
, MONO_HANDLE_RAW (name
), MONO_HANDLE_RAW (data
));
1026 mono_domain_unlock (add
);
1029 MonoAppDomainSetupHandle
1030 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad
, MonoError
*error
)
1033 g_assert (!MONO_HANDLE_IS_NULL (ad
));
1034 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
1037 return MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
);
1041 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad
, MonoError
*error
)
1044 g_assert (!MONO_HANDLE_IS_NULL (ad
));
1045 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
1048 return mono_string_new_handle (domain
, domain
->friendly_name
, error
);
1052 ves_icall_System_AppDomain_getCurDomain (MonoError
*error
)
1055 MonoDomain
*add
= mono_domain_get ();
1057 return MONO_HANDLE_NEW (MonoAppDomain
, add
->domain
);
1061 ves_icall_System_AppDomain_getRootDomain (MonoError
*error
)
1064 MonoDomain
*root
= mono_get_root_domain ();
1066 return MONO_HANDLE_NEW (MonoAppDomain
, root
->domain
);
1070 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions (MonoError
*error
)
1072 MonoDomain
*domain
= mono_domain_get ();
1074 return domain
->throw_unobserved_task_exceptions
;
1078 get_attribute_value (const gchar
**attribute_names
,
1079 const gchar
**attribute_values
,
1080 const char *att_name
)
1083 for (n
= 0; attribute_names
[n
] != NULL
; n
++) {
1084 if (strcmp (attribute_names
[n
], att_name
) == 0)
1085 return g_strdup (attribute_values
[n
]);
1091 start_element (GMarkupParseContext
*context
,
1092 const gchar
*element_name
,
1093 const gchar
**attribute_names
,
1094 const gchar
**attribute_values
,
1098 RuntimeConfig
*runtime_config
= (RuntimeConfig
*)user_data
;
1100 if (strcmp (element_name
, "runtime") == 0) {
1101 runtime_config
->runtime_count
++;
1105 if (strcmp (element_name
, "assemblyBinding") == 0) {
1106 runtime_config
->assemblybinding_count
++;
1110 if (runtime_config
->runtime_count
!= 1)
1113 if (strcmp (element_name
, "ThrowUnobservedTaskExceptions") == 0) {
1114 const char *value
= get_attribute_value (attribute_names
, attribute_values
, "enabled");
1116 if (value
&& g_ascii_strcasecmp (value
, "true") == 0)
1117 runtime_config
->domain
->throw_unobserved_task_exceptions
= TRUE
;
1120 if (runtime_config
->assemblybinding_count
!= 1)
1123 if (strcmp (element_name
, "probing") != 0)
1126 g_free (runtime_config
->domain
->private_bin_path
);
1127 runtime_config
->domain
->private_bin_path
= get_attribute_value (attribute_names
, attribute_values
, "privatePath");
1128 if (runtime_config
->domain
->private_bin_path
&& !runtime_config
->domain
->private_bin_path
[0]) {
1129 g_free (runtime_config
->domain
->private_bin_path
);
1130 runtime_config
->domain
->private_bin_path
= NULL
;
1136 end_element (GMarkupParseContext
*context
,
1137 const gchar
*element_name
,
1141 RuntimeConfig
*runtime_config
= (RuntimeConfig
*)user_data
;
1142 if (strcmp (element_name
, "runtime") == 0)
1143 runtime_config
->runtime_count
--;
1144 else if (strcmp (element_name
, "assemblyBinding") == 0)
1145 runtime_config
->assemblybinding_count
--;
1149 parse_error (GMarkupParseContext
*context
, GError
*gerror
, gpointer user_data
)
1151 RuntimeConfig
*state
= (RuntimeConfig
*)user_data
;
1153 const gchar
*filename
;
1155 filename
= state
&& state
->filename
? (gchar
*) state
->filename
: "<unknown>";
1156 msg
= gerror
&& gerror
->message
? gerror
->message
: "";
1157 g_warning ("Error parsing %s: %s", filename
, msg
);
1160 static const GMarkupParser
1170 mono_domain_set_options_from_config (MonoDomain
*domain
)
1173 gchar
*config_file_name
= NULL
, *text
= NULL
, *config_file_path
= NULL
;
1175 GMarkupParseContext
*context
;
1176 RuntimeConfig runtime_config
;
1179 if (!domain
|| !domain
->setup
|| !domain
->setup
->configuration_file
)
1182 config_file_name
= mono_string_to_utf8_checked_internal (domain
->setup
->configuration_file
, error
);
1183 if (!mono_error_ok (error
)) {
1184 mono_error_cleanup (error
);
1188 config_file_path
= mono_portability_find_file (config_file_name
, TRUE
);
1189 if (!config_file_path
)
1190 config_file_path
= config_file_name
;
1192 if (!g_file_get_contents (config_file_path
, &text
, &len
, NULL
))
1195 runtime_config
.runtime_count
= 0;
1196 runtime_config
.assemblybinding_count
= 0;
1197 runtime_config
.domain
= domain
;
1198 runtime_config
.filename
= config_file_path
;
1201 if (len
> 3 && text
[0] == '\xef' && text
[1] == (gchar
) '\xbb' && text
[2] == '\xbf')
1202 offset
= 3; /* Skip UTF-8 BOM */
1204 context
= g_markup_parse_context_new (&mono_parser
, (GMarkupParseFlags
)0, &runtime_config
, NULL
);
1205 if (g_markup_parse_context_parse (context
, text
+ offset
, len
- offset
, NULL
))
1206 g_markup_parse_context_end_parse (context
, NULL
);
1207 g_markup_parse_context_free (context
);
1211 if (config_file_name
!= config_file_path
)
1212 g_free (config_file_name
);
1213 g_free (config_file_path
);
1217 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name
, MonoAppDomainSetupHandle setup
, MonoError
*error
)
1220 MonoAppDomainHandle ad
= MONO_HANDLE_NEW (MonoAppDomain
, NULL
);
1222 #ifdef DISABLE_APPDOMAINS
1223 mono_error_set_not_supported (error
, "AppDomain creation is not supported on this runtime.");
1227 fname
= mono_string_handle_to_utf8 (friendly_name
, error
);
1228 return_val_if_nok (error
, ad
);
1229 ad
= mono_domain_create_appdomain_internal (fname
, setup
, error
);
1236 add_assembly_to_array (MonoDomain
*domain
, MonoArrayHandle dest
, int dest_idx
, MonoAssembly
* assm
, MonoError
*error
)
1238 HANDLE_FUNCTION_ENTER ();
1240 MonoReflectionAssemblyHandle assm_obj
= mono_assembly_get_object_handle (domain
, assm
, error
);
1241 goto_if_nok (error
, leave
);
1242 MONO_HANDLE_ARRAY_SETREF (dest
, dest_idx
, assm_obj
);
1244 HANDLE_FUNCTION_RETURN_VAL (is_ok (error
));
1248 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad
, MonoBoolean refonly
, MonoError
*error
)
1251 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
1255 GPtrArray
*assemblies
;
1258 * Make a copy of the list of assemblies because we can't hold the assemblies
1259 * lock while creating objects etc.
1261 assemblies
= g_ptr_array_new ();
1262 /* Need to skip internal assembly builders created by remoting */
1263 mono_domain_assemblies_lock (domain
);
1264 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1265 ass
= (MonoAssembly
*)tmp
->data
;
1266 MonoBoolean ass_refonly
= mono_asmctx_get_kind (&ass
->context
) == MONO_ASMCTX_REFONLY
;
1267 /* .NET Framework GetAssemblies() includes LoadFrom and Load(byte[]) assemblies, too */
1268 if (refonly
!= ass_refonly
)
1270 if (ass
->corlib_internal
)
1272 g_ptr_array_add (assemblies
, ass
);
1274 mono_domain_assemblies_unlock (domain
);
1276 MonoArrayHandle res
= mono_array_new_handle (domain
, mono_class_get_assembly_class (), assemblies
->len
, error
);
1277 goto_if_nok (error
, leave
);
1278 for (i
= 0; i
< assemblies
->len
; ++i
) {
1279 if (!add_assembly_to_array (domain
, res
, i
, (MonoAssembly
*)g_ptr_array_index (assemblies
, i
), error
))
1284 g_ptr_array_free (assemblies
, TRUE
);
1289 mono_try_assembly_resolve (MonoDomain
*domain
, const char *fname_raw
, MonoAssembly
*requesting
, gboolean refonly
, MonoError
*error
)
1291 HANDLE_FUNCTION_ENTER ();
1293 MonoAssembly
*result
= NULL
;
1294 MonoStringHandle fname
= mono_string_new_handle (domain
, fname_raw
, error
);
1295 goto_if_nok (error
, leave
);
1296 result
= mono_try_assembly_resolve_handle (domain
, fname
, requesting
, refonly
, error
);
1298 HANDLE_FUNCTION_RETURN_VAL (result
);
1302 mono_try_assembly_resolve_handle (MonoDomain
*domain
, MonoStringHandle fname
, MonoAssembly
*requesting
, gboolean refonly
, MonoError
*error
)
1304 HANDLE_FUNCTION_ENTER ();
1305 MonoAssembly
*ret
= NULL
;
1307 MonoBoolean isrefonly
;
1308 gpointer params
[3];
1312 if (mono_runtime_get_no_exec ())
1315 g_assert (domain
!= NULL
&& !MONO_HANDLE_IS_NULL (fname
));
1317 method
= mono_class_get_method_from_name_checked (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1, 0, error
);
1318 g_assert (method
!= NULL
);
1320 isrefonly
= refonly
? 1 : 0;
1321 MonoReflectionAssemblyHandle requesting_handle
;
1323 requesting_handle
= mono_assembly_get_object_handle (domain
, requesting
, error
);
1324 goto_if_nok (error
, leave
);
1326 params
[0] = MONO_HANDLE_RAW (fname
);
1327 params
[1] = requesting
? MONO_HANDLE_RAW (requesting_handle
) : NULL
;
1328 params
[2] = &isrefonly
;
1331 MonoReflectionAssemblyHandle result
;
1332 result
= MONO_HANDLE_CAST (MonoReflectionAssembly
, MONO_HANDLE_NEW (MonoObject
, mono_runtime_try_invoke (method
, domain
->domain
, params
, &exc
, error
)));
1333 if (!is_ok (error
) || exc
!= NULL
) {
1335 mono_error_set_exception_instance (error
, (MonoException
*)exc
);
1338 ret
= !MONO_HANDLE_IS_NULL (result
) ? MONO_HANDLE_GETVAL (result
, assembly
) : NULL
;
1340 if (ret
&& !refonly
&& mono_asmctx_get_kind (&ret
->context
) == MONO_ASMCTX_REFONLY
) {
1341 /* .NET Framework throws System.IO.FileNotFoundException in this case */
1342 mono_error_set_file_not_found (error
, NULL
, "AssemblyResolveEvent handlers cannot return Assemblies loaded for reflection only");
1347 HANDLE_FUNCTION_RETURN_VAL (ret
);
1351 mono_domain_assembly_postload_search (MonoAssemblyName
*aname
, MonoAssembly
*requesting
,
1355 MonoAssembly
*assembly
;
1356 MonoDomain
*domain
= mono_domain_get ();
1359 aname_str
= mono_stringify_assembly_name (aname
);
1361 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1363 assembly
= mono_try_assembly_resolve (domain
, aname_str
, requesting
, refonly
, error
);
1365 mono_error_cleanup (error
);
1371 * LOCKING: assumes assemblies_lock in the domain is already locked.
1374 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*ht
)
1378 gboolean destroy_ht
= FALSE
;
1380 g_assert (ass
!= NULL
);
1382 if (!ass
->aname
.name
)
1386 ht
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1388 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1389 g_hash_table_insert (ht
, tmp
->data
, tmp
->data
);
1393 /* FIXME: handle lazy loaded assemblies */
1395 if (!g_hash_table_lookup (ht
, ass
)) {
1396 mono_assembly_addref (ass
);
1397 g_hash_table_insert (ht
, ass
, ass
);
1398 domain
->domain_assemblies
= g_slist_append (domain
->domain_assemblies
, ass
);
1399 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
);
1402 if (ass
->image
->references
) {
1403 for (i
= 0; i
< ass
->image
->nreferences
; i
++) {
1404 if (ass
->image
->references
[i
] && ass
->image
->references
[i
] != REFERENCE_MISSING
) {
1405 if (!g_hash_table_lookup (ht
, ass
->image
->references
[i
])) {
1406 add_assemblies_to_domain (domain
, ass
->image
->references
[i
], ht
);
1412 g_hash_table_destroy (ht
);
1416 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
)
1418 HANDLE_FUNCTION_ENTER ();
1419 static MonoClassField
*assembly_load_field
;
1420 static MonoMethod
*assembly_load_method
;
1422 MonoDomain
*domain
= mono_domain_get ();
1424 MonoObjectHandle appdomain
;
1426 if (!MONO_BOOL (domain
->domain
))
1427 goto leave
; // This can happen during startup
1429 if (mono_runtime_get_no_exec ())
1432 #ifdef ASSEMBLY_LOAD_DEBUG
1433 fprintf (stderr
, "Loading %s into domain %s\n", assembly
->aname
.name
, domain
->friendly_name
);
1435 appdomain
= MONO_HANDLE_NEW (MonoObject
, &domain
->domain
->mbr
.obj
);
1436 klass
= mono_handle_class (appdomain
);
1438 mono_domain_assemblies_lock (domain
);
1439 add_assemblies_to_domain (domain
, assembly
, NULL
);
1440 mono_domain_assemblies_unlock (domain
);
1442 if (assembly_load_field
== NULL
) {
1443 assembly_load_field
= mono_class_get_field_from_name_full (klass
, "AssemblyLoad", NULL
);
1444 g_assert (assembly_load_field
);
1447 if (!MONO_HANDLE_GET_FIELD_BOOL (appdomain
, MonoObject
*, assembly_load_field
))
1448 goto leave
; // No events waiting to be triggered
1450 MonoReflectionAssemblyHandle reflection_assembly
;
1451 reflection_assembly
= mono_assembly_get_object_handle (domain
, assembly
, error
);
1452 mono_error_assert_ok (error
);
1454 if (assembly_load_method
== NULL
) {
1455 assembly_load_method
= mono_class_get_method_from_name_checked (klass
, "DoAssemblyLoad", -1, 0, error
);
1456 g_assert (assembly_load_method
);
1460 params
[0] = MONO_HANDLE_RAW (reflection_assembly
);
1461 mono_runtime_invoke_handle (assembly_load_method
, appdomain
, params
, error
);
1463 mono_error_cleanup (error
);
1464 HANDLE_FUNCTION_RETURN ();
1468 mono_domain_asmctx_from_path (const char *fname
, MonoAssembly
*requesting_assembly
, gpointer user_data
, MonoAssemblyContextKind
*out_asmctx
)
1470 MonoDomain
*domain
= mono_domain_get ();
1471 char **search_path
= NULL
;
1473 for (search_path
= domain
->search_path
; search_path
&& *search_path
; search_path
++) {
1474 if (mono_path_filename_in_basedir (fname
, *search_path
)) {
1475 *out_asmctx
= MONO_ASMCTX_DEFAULT
;
1483 * LOCKING: Acquires the domain assemblies lock.
1486 set_domain_search_path (MonoDomain
*domain
)
1488 HANDLE_FUNCTION_ENTER ();
1490 MonoAppDomainSetupHandle setup
;
1492 gchar
*search_path
= NULL
;
1494 gchar
**pvt_split
= NULL
;
1495 GError
*gerror
= NULL
;
1496 gint appbaselen
= -1;
1499 * We use the low-level domain assemblies lock, since this is called from
1500 * assembly loads hooks, which means this thread might hold the loader lock.
1502 mono_domain_assemblies_lock (domain
);
1504 if (!MONO_BOOL (domain
->setup
))
1507 setup
= MONO_HANDLE_NEW (MonoAppDomainSetup
, domain
->setup
);
1509 if (domain
->search_path
&& !MONO_HANDLE_GET_BOOL (setup
, path_changed
))
1512 if (!MONO_HANDLE_GET_BOOL (setup
, application_base
))
1513 goto exit
; // Must set application base to get private path working
1515 if (MONO_HANDLE_GET_BOOL (setup
, private_bin_path
)) {
1516 search_path
= mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString
, setup
, private_bin_path
), error
);
1517 if (!mono_error_ok (error
)) { /*FIXME maybe we should bubble up the error.*/
1518 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1523 if (domain
->private_bin_path
) {
1524 if (search_path
== NULL
)
1525 search_path
= domain
->private_bin_path
;
1527 gchar
*tmp2
= search_path
;
1528 search_path
= g_strjoin (";", search_path
, domain
->private_bin_path
, NULL
);
1535 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1536 * directories relative to ApplicationBase separated by semicolons (see
1537 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1538 * The loop below copes with the fact that some Unix applications may use ':' (or
1539 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1540 * ';' for the subsequent split.
1542 * The issue was reported in bug #81446
1544 #ifndef TARGET_WIN32
1545 g_strdelimit (search_path
, ':', ';');
1547 pvt_split
= g_strsplit (search_path
, ";", 1000);
1548 g_free (search_path
);
1549 for (tmp
= pvt_split
; *tmp
; tmp
++, npaths
++);
1552 g_strfreev (domain
->search_path
);
1553 domain
->search_path
= NULL
;
1555 tmp
= g_new (gchar
*, npaths
+ 1);
1556 tmp
[npaths
] = NULL
;
1558 *tmp
= mono_string_handle_to_utf8 (MONO_HANDLE_NEW_GET (MonoString
, setup
, application_base
), error
);
1559 if (!mono_error_ok (error
)) {
1564 domain
->search_path
= tmp
;
1566 /* FIXME: is this needed? */
1567 if (strncmp (*tmp
, "file://", 7) == 0) {
1573 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
1576 uri
= mono_escape_uri_string (tmpuri
);
1577 *tmp
= g_filename_from_uri (uri
, NULL
, &gerror
);
1583 if (gerror
!= NULL
) {
1584 g_warning ("%s\n", gerror
->message
);
1585 g_error_free (gerror
);
1592 for (gsize i
= 1; pvt_split
&& i
< npaths
; i
++) {
1593 if (g_path_is_absolute (pvt_split
[i
- 1])) {
1594 tmp
[i
] = g_strdup (pvt_split
[i
- 1]);
1596 tmp
[i
] = g_build_filename (tmp
[0], pvt_split
[i
- 1], NULL
);
1599 if (strchr (tmp
[i
], '.')) {
1603 reduced
= mono_path_canonicalize (tmp
[i
]);
1604 if (appbaselen
== -1)
1605 appbaselen
= strlen (tmp
[0]);
1607 if (strncmp (tmp
[0], reduced
, appbaselen
)) {
1610 tmp
[i
] = g_strdup ("");
1620 if (MONO_HANDLE_GET_BOOL (setup
, private_bin_path_probe
)) {
1622 tmp
[0] = g_strdup ("");
1625 MONO_HANDLE_SETVAL (setup
, path_changed
, MonoBoolean
, FALSE
);
1627 mono_error_cleanup (error
);
1628 g_strfreev (pvt_split
);
1629 mono_domain_assemblies_unlock (domain
);
1630 HANDLE_FUNCTION_RETURN ();
1633 #ifdef DISABLE_SHADOW_COPY
1635 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1641 mono_make_shadow_copy (const char *filename
, MonoError
*error
)
1644 return (char *) filename
;
1649 SHADOW_COPY_SIBLING_EXT_APPEND
,
1650 SHADOW_COPY_SIBLING_EXT_REPLACE
,
1651 } ShadowCopySiblingExt
;
1655 make_sibling_path (const gchar
*path
, gint pathlen
, const char *extension
, ShadowCopySiblingExt extopt
)
1657 gchar
*result
= NULL
;
1659 case SHADOW_COPY_SIBLING_EXT_APPEND
: {
1660 result
= g_strconcat (path
, extension
, NULL
);
1663 case SHADOW_COPY_SIBLING_EXT_REPLACE
: {
1664 /* expect path to be a .dll or .exe (or some case insensitive variant) */
1665 g_assert (pathlen
>= 4 && path
[pathlen
- 4] == '.');
1666 GString
*s
= g_string_sized_new (pathlen
- 4 + strlen (extension
));
1667 g_string_append_len (s
, path
, pathlen
- 4);
1668 g_string_append (s
, extension
);
1669 result
= g_string_free (s
, FALSE
);
1673 g_assert_not_reached ();
1679 shadow_copy_sibling (const gchar
*src_pristine
, gint srclen
, const char *extension
, ShadowCopySiblingExt extopt
, const gchar
*target_pristine
, gint targetlen
)
1682 gunichar2
*orig
= NULL
;
1683 gunichar2
*dest
= NULL
;
1684 gboolean copy_result
= TRUE
;
1685 gchar
*target
= NULL
;
1687 char *src
= make_sibling_path (src_pristine
, srclen
, extension
, extopt
);
1689 if (IS_PORTABILITY_CASE
) {
1690 file
= mono_portability_find_file (src
, TRUE
);
1693 } else if (!g_file_test (src
, G_FILE_TEST_IS_REGULAR
))
1696 orig
= g_utf8_to_utf16 (src
, strlen (src
), NULL
, NULL
, NULL
);
1698 target
= make_sibling_path (target_pristine
, targetlen
, extension
, extopt
);
1700 dest
= g_utf8_to_utf16 (target
, strlen (target
), NULL
, NULL
, NULL
);
1702 mono_w32file_delete (dest
);
1705 copy_result
= mono_w32file_copy (orig
, dest
, TRUE
, ©_error
);
1707 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1708 * overwritten when updated in their original locations. */
1710 copy_result
= mono_w32file_set_attributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1722 get_cstring_hash (const char *str
)
1727 if (!str
|| !str
[0])
1730 gsize
const len
= strlen (str
);
1732 for (gsize i
= 0; i
< len
; i
++) {
1733 h
= (h
<< 5) - h
+ *p
;
1741 * Returned memory is malloc'd. Called must free it
1744 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
)
1746 MonoAppDomainSetup
*setup
;
1747 char *cache_path
= NULL
;
1748 char *appname
= NULL
;
1749 char *userdir
= NULL
;
1754 setup
= domain
->setup
;
1755 if (setup
->cache_path
!= NULL
&& setup
->application_name
!= NULL
) {
1756 cache_path
= mono_string_to_utf8_checked_internal (setup
->cache_path
, error
);
1757 return_val_if_nok (error
, NULL
);
1759 #ifndef TARGET_WIN32
1762 for (i
= strlen (cache_path
) - 1; i
>= 0; i
--)
1763 if (cache_path
[i
] == '\\')
1764 cache_path
[i
] = '/';
1768 appname
= mono_string_to_utf8_checked_internal (setup
->application_name
, error
);
1769 if (!mono_error_ok (error
)) {
1770 g_free (cache_path
);
1774 location
= g_build_filename (cache_path
, appname
, "assembly", "shadow", NULL
);
1776 userdir
= g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1777 location
= g_build_filename (g_get_tmp_dir (), userdir
, "assembly", "shadow", NULL
);
1780 g_free (cache_path
);
1786 get_shadow_assembly_location (const char *filename
, MonoError
*error
)
1788 gint32 hash
= 0, hash2
= 0;
1790 char path_hash
[30];
1791 char *bname
= g_path_get_basename (filename
);
1792 char *dirname
= g_path_get_dirname (filename
);
1793 char *location
, *tmploc
;
1794 MonoDomain
*domain
= mono_domain_get ();
1798 hash
= get_cstring_hash (bname
);
1799 hash2
= get_cstring_hash (dirname
);
1800 g_snprintf (name_hash
, sizeof (name_hash
), "%08x", hash
);
1801 g_snprintf (path_hash
, sizeof (path_hash
), "%08x_%08x_%08x", hash
^ hash2
, hash2
, domain
->shadow_serial
);
1802 tmploc
= get_shadow_assembly_location_base (domain
, error
);
1803 if (!mono_error_ok (error
)) {
1809 location
= g_build_filename (tmploc
, name_hash
, path_hash
, bname
, NULL
);
1817 private_file_needs_copying (const char *src
, struct stat
*sbuf_src
, char *dest
)
1819 struct stat sbuf_dest
;
1821 gchar
*real_src
= mono_portability_find_file (src
, TRUE
);
1824 stat_src
= (gchar
*)src
;
1826 stat_src
= real_src
;
1828 if (stat (stat_src
, sbuf_src
) == -1) {
1829 time_t tnow
= time (NULL
);
1834 memset (sbuf_src
, 0, sizeof (*sbuf_src
));
1835 sbuf_src
->st_mtime
= tnow
;
1836 sbuf_src
->st_atime
= tnow
;
1843 if (stat (dest
, &sbuf_dest
) == -1)
1846 if (sbuf_src
->st_size
== sbuf_dest
.st_size
&&
1847 sbuf_src
->st_mtime
== sbuf_dest
.st_mtime
)
1854 shadow_copy_create_ini (const char *shadow
, const char *filename
)
1856 gunichar2
*u16_ini
= NULL
;
1857 gboolean result
= FALSE
;
1859 HANDLE handle
= INVALID_HANDLE_VALUE
;
1860 gchar
*full_path
= NULL
;
1862 char *dir_name
= g_path_get_dirname (shadow
);
1863 char *ini_file
= g_build_filename (dir_name
, "__AssemblyInfo__.ini", NULL
);
1865 result
= g_file_test (ini_file
, G_FILE_TEST_IS_REGULAR
);
1869 u16_ini
= g_utf8_to_utf16 (ini_file
, strlen (ini_file
), NULL
, NULL
, NULL
);
1873 handle
= mono_w32file_create (u16_ini
, GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, CREATE_NEW
, FileAttributes_Normal
);
1874 if (handle
== INVALID_HANDLE_VALUE
)
1877 full_path
= mono_path_resolve_symlinks (filename
);
1880 result
= mono_w32file_write (handle
, full_path
, strlen (full_path
), &n
, &win32error
);
1882 if (handle
!= INVALID_HANDLE_VALUE
)
1883 mono_w32file_close (handle
);
1891 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1894 MonoAppDomainSetup
*setup
;
1895 gchar
*all_dirs
= NULL
;
1897 gchar
**directories
= NULL
;
1898 gchar
*shadow_status_string
;
1899 gchar
*base_dir
= NULL
;
1900 gboolean shadow_enabled
;
1901 gboolean found
= FALSE
;
1906 setup
= domain
->setup
;
1907 if (setup
== NULL
|| setup
->shadow_copy_files
== NULL
)
1910 shadow_status_string
= mono_string_to_utf8_checked_internal (setup
->shadow_copy_files
, error
);
1911 if (!mono_error_ok (error
))
1914 shadow_enabled
= !g_ascii_strncasecmp (shadow_status_string
, "true", 4);
1915 g_free (shadow_status_string
);
1917 if (!shadow_enabled
)
1920 found
= (setup
->shadow_copy_directories
== NULL
);
1924 /* Is dir_name a shadow_copy destination already? */
1925 base_dir
= get_shadow_assembly_location_base (domain
, error
);
1926 if (!mono_error_ok (error
))
1929 found
= !!strstr (dir_name
, base_dir
);
1933 all_dirs
= mono_string_to_utf8_checked_internal (setup
->shadow_copy_directories
, error
);
1934 if (!mono_error_ok (error
))
1937 directories
= g_strsplit (all_dirs
, G_SEARCHPATH_SEPARATOR_S
, 1000);
1938 dir_ptr
= directories
;
1939 while (!found
&& *dir_ptr
) {
1940 found
= (**dir_ptr
!= '\0' && !strcmp (*dir_ptr
, dir_name
));
1944 mono_error_cleanup (error
);
1946 g_strfreev (directories
);
1952 This function raises exceptions so it can cause as sorts of nasty stuff if called
1953 while holding a lock.
1954 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1955 or NULL if source file not found.
1956 FIXME bubble up the error instead of raising it here
1959 mono_make_shadow_copy (const char *filename
, MonoError
*oerror
)
1962 gint filename_len
, shadow_len
;
1963 gunichar2
*orig
, *dest
;
1966 gboolean copy_result
;
1967 struct stat src_sbuf
;
1968 struct utimbuf utbuf
;
1969 char *dir_name
= g_path_get_dirname (filename
);
1970 MonoDomain
*domain
= mono_domain_get ();
1974 error_init (oerror
);
1976 set_domain_search_path (domain
);
1978 if (!mono_is_shadow_copy_enabled (domain
, dir_name
)) {
1980 return (char *) filename
;
1983 /* Is dir_name a shadow_copy destination already? */
1984 shadow_dir
= get_shadow_assembly_location_base (domain
, error
);
1985 if (!mono_error_ok (error
)) {
1986 mono_error_cleanup (error
);
1988 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (invalid characters in shadow directory name).");
1992 if (strstr (dir_name
, shadow_dir
)) {
1993 g_free (shadow_dir
);
1995 return (char *) filename
;
1997 g_free (shadow_dir
);
2000 shadow
= get_shadow_assembly_location (filename
, error
);
2001 if (!mono_error_ok (error
)) {
2002 mono_error_cleanup (error
);
2003 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (invalid characters in file name).");
2007 if (g_ensure_directory_exists (shadow
) == FALSE
) {
2009 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (ensure directory exists).");
2013 if (!private_file_needs_copying (filename
, &src_sbuf
, shadow
))
2014 return (char*) shadow
;
2016 orig
= g_utf8_to_utf16 (filename
, strlen (filename
), NULL
, NULL
, NULL
);
2017 dest
= g_utf8_to_utf16 (shadow
, strlen (shadow
), NULL
, NULL
, NULL
);
2018 mono_w32file_delete (dest
);
2020 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
2021 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
2022 * and not have it runtime error" */
2023 attrs
= mono_w32file_get_attributes (orig
);
2024 if (attrs
== INVALID_FILE_ATTRIBUTES
) {
2026 return (char *)filename
;
2029 copy_result
= mono_w32file_copy (orig
, dest
, TRUE
, ©_error
);
2031 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
2032 * overwritten when updated in their original locations. */
2034 copy_result
= mono_w32file_set_attributes (dest
, FILE_ATTRIBUTE_NORMAL
);
2039 if (copy_result
== FALSE
) {
2042 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
2043 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND
|| mono_w32error_get_last() == ERROR_PATH_NOT_FOUND
)
2044 return NULL
; /* file not found, shadow copy failed */
2046 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (mono_w32file_copy).");
2050 /* attempt to copy .mdb, .pdb and .config if they exist */
2051 filename_len
= strlen (filename
);
2052 shadow_len
= strlen (shadow
);
2054 copy_result
= shadow_copy_sibling (filename
, filename_len
, ".mdb", SHADOW_COPY_SIBLING_EXT_APPEND
, shadow
, shadow_len
);
2056 copy_result
= shadow_copy_sibling (filename
, filename_len
, ".pdb", SHADOW_COPY_SIBLING_EXT_REPLACE
, shadow
, shadow_len
);
2058 copy_result
= shadow_copy_sibling (filename
, filename_len
, ".config", SHADOW_COPY_SIBLING_EXT_APPEND
, shadow
, shadow_len
);
2062 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
2066 /* Create a .ini file containing the original assembly location */
2067 if (!shadow_copy_create_ini (shadow
, filename
)) {
2069 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy .ini file.");
2073 utbuf
.actime
= src_sbuf
.st_atime
;
2074 utbuf
.modtime
= src_sbuf
.st_mtime
;
2075 utime (shadow
, &utbuf
);
2079 #endif /* DISABLE_SHADOW_COPY */
2082 * mono_domain_from_appdomain:
2085 mono_domain_from_appdomain (MonoAppDomain
*appdomain_raw
)
2087 HANDLE_FUNCTION_ENTER ();
2089 MONO_ENTER_GC_UNSAFE
;
2090 MONO_HANDLE_DCL (MonoAppDomain
, appdomain
);
2091 result
= mono_domain_from_appdomain_handle (appdomain
);
2092 MONO_EXIT_GC_UNSAFE
;
2093 HANDLE_FUNCTION_RETURN_VAL (result
);
2097 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain
)
2099 HANDLE_FUNCTION_ENTER ();
2100 MonoDomain
*dom
= NULL
;
2101 if (MONO_HANDLE_IS_NULL (appdomain
))
2104 if (mono_class_is_transparent_proxy (mono_handle_class (appdomain
))) {
2105 MonoTransparentProxyHandle tp
= MONO_HANDLE_CAST (MonoTransparentProxy
, appdomain
);
2106 MonoRealProxyHandle rp
= MONO_HANDLE_NEW_GET (MonoRealProxy
, tp
, rp
);
2108 dom
= mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp
, target_domain_id
));
2110 dom
= MONO_HANDLE_GETVAL (appdomain
, data
);
2113 HANDLE_FUNCTION_RETURN_VAL (dom
);
2118 try_load_from (MonoAssembly
**assembly
,
2119 const gchar
*path1
, const gchar
*path2
,
2120 const gchar
*path3
, const gchar
*path4
,
2121 const MonoAssemblyOpenRequest
*req
)
2124 gboolean found
= FALSE
;
2127 fullpath
= g_build_filename (path1
, path2
, path3
, path4
, NULL
);
2129 if (IS_PORTABILITY_SET
) {
2130 gchar
*new_fullpath
= mono_portability_find_file (fullpath
, TRUE
);
2133 fullpath
= new_fullpath
;
2137 found
= g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
);
2140 *assembly
= mono_assembly_request_open (fullpath
, req
, NULL
);
2144 return (*assembly
!= NULL
);
2147 static MonoAssembly
*
2148 real_load (gchar
**search_path
, const gchar
*culture
, const gchar
*name
, const MonoAssemblyOpenRequest
*req
)
2150 MonoAssembly
*result
= NULL
;
2153 const gchar
*local_culture
;
2156 if (!culture
|| *culture
== '\0') {
2159 local_culture
= culture
;
2162 filename
= g_strconcat (name
, ".dll", NULL
);
2163 len
= strlen (filename
);
2165 for (path
= search_path
; *path
; path
++) {
2166 if (**path
== '\0') {
2167 continue; /* Ignore empty ApplicationBase */
2170 /* See test cases in bug #58992 and bug #57710 */
2171 /* 1st try: [culture]/[name].dll (culture may be empty) */
2172 strcpy (filename
+ len
- 4, ".dll");
2173 if (try_load_from (&result
, *path
, local_culture
, "", filename
, req
))
2176 /* 2nd try: [culture]/[name].exe (culture may be empty) */
2177 strcpy (filename
+ len
- 4, ".exe");
2178 if (try_load_from (&result
, *path
, local_culture
, "", filename
, req
))
2181 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
2182 strcpy (filename
+ len
- 4, ".dll");
2183 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, req
))
2186 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
2187 strcpy (filename
+ len
- 4, ".exe");
2188 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, req
))
2197 * Try loading the assembly from ApplicationBase and PrivateBinPath
2198 * and then from assemblies_path if any.
2199 * LOCKING: This is called from the assembly loading code, which means the caller
2200 * might hold the loader lock. Thus, this function must not acquire the domain lock.
2202 static MonoAssembly
*
2203 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
2204 gchar
**assemblies_path
,
2207 MonoDomain
*domain
= mono_domain_get ();
2208 MonoAssembly
*result
= NULL
;
2209 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
2211 set_domain_search_path (domain
);
2213 MonoAssemblyCandidatePredicate predicate
= NULL
;
2214 void* predicate_ud
= NULL
;
2215 #if !defined(DISABLE_DESKTOP_LOADER)
2216 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2217 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
2218 predicate_ud
= aname
;
2221 MonoAssemblyOpenRequest req
;
2222 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
);
2223 req
.request
.predicate
= predicate
;
2224 req
.request
.predicate_ud
= predicate_ud
;
2226 if (domain
->search_path
&& domain
->search_path
[0] != NULL
) {
2227 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
)) {
2228 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Domain %s search path is:", domain
->friendly_name
);
2229 for (int i
= 0; domain
->search_path
[i
]; i
++) {
2230 const char *p
= domain
->search_path
[i
];
2231 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "\tpath[%d] = '%s'", i
, p
);
2233 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "End of domain %s search path.", domain
->friendly_name
);
2235 result
= real_load (domain
->search_path
, aname
->culture
, aname
->name
, &req
);
2238 if (result
== NULL
&& assemblies_path
&& assemblies_path
[0] != NULL
) {
2239 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, &req
);
2246 * mono_assembly_load_from_assemblies_path:
2248 * \param assemblies_path directories to search for given assembly name, terminated by NULL
2249 * \param aname assembly name to look for
2250 * \param asmctx assembly load context for this load operation
2252 * Given a NULL-terminated array of paths, look for \c name.ext, \c name, \c
2253 * culture/name.ext, \c culture/name/name.ext where \c ext is \c dll and \c
2254 * exe and try to load it in the given assembly load context.
2256 * \returns A \c MonoAssembly if probing was successful, or NULL otherwise.
2259 mono_assembly_load_from_assemblies_path (gchar
**assemblies_path
, MonoAssemblyName
*aname
, MonoAssemblyContextKind asmctx
)
2261 MonoAssemblyCandidatePredicate predicate
= NULL
;
2262 void* predicate_ud
= NULL
;
2263 #if !defined(DISABLE_DESKTOP_LOADER)
2264 if (G_LIKELY (mono_loader_get_strict_strong_names ())) {
2265 predicate
= &mono_assembly_candidate_predicate_sn_same_name
;
2266 predicate_ud
= aname
;
2269 MonoAssemblyOpenRequest req
;
2270 mono_assembly_request_prepare (&req
.request
, sizeof (req
), asmctx
);
2271 req
.request
.predicate
= predicate
;
2272 req
.request
.predicate_ud
= predicate_ud
;
2273 MonoAssembly
*result
= NULL
;
2274 if (assemblies_path
&& assemblies_path
[0] != NULL
) {
2275 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, &req
);
2281 * Check whenever a given assembly was already loaded in the current appdomain.
2283 static MonoAssembly
*
2284 mono_domain_assembly_search (MonoAssemblyName
*aname
,
2287 g_assert (aname
!= NULL
);
2288 MonoDomain
*domain
= mono_domain_get ();
2291 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
2292 const gboolean strong_name
= aname
->public_key_token
[0] != 0;
2293 /* If it's not a strong name, any version that has the right simple
2294 * name is good enough to satisfy the request. .NET Framework also
2295 * ignores case differences in this case. */
2296 const MonoAssemblyNameEqFlags eq_flags
= (MonoAssemblyNameEqFlags
)(strong_name
? MONO_ANAME_EQ_IGNORE_CASE
:
2297 (MONO_ANAME_EQ_IGNORE_PUBKEY
| MONO_ANAME_EQ_IGNORE_VERSION
| MONO_ANAME_EQ_IGNORE_CASE
));
2299 mono_domain_assemblies_lock (domain
);
2300 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
2301 ass
= (MonoAssembly
*)tmp
->data
;
2302 g_assert (ass
!= NULL
);
2303 /* Dynamic assemblies can't match here in MS.NET */
2304 gboolean ass_ref_only
= mono_asmctx_get_kind (&ass
->context
) == MONO_ASMCTX_REFONLY
;
2305 if (assembly_is_dynamic (ass
) || refonly
!= ass_ref_only
|| !mono_assembly_names_equal_flags (aname
, &ass
->aname
, eq_flags
))
2308 mono_domain_assemblies_unlock (domain
);
2311 mono_domain_assemblies_unlock (domain
);
2316 MonoReflectionAssemblyHandle
2317 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname
, MonoBoolean refOnly
, MonoStackCrawlMark
*stack_mark
, MonoError
*error
)
2320 MonoDomain
*domain
= mono_domain_get ();
2321 char *name
, *filename
;
2322 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2323 MonoReflectionAssemblyHandle result
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2327 if (MONO_HANDLE_IS_NULL (fname
)) {
2328 mono_error_set_argument_null (error
, "assemblyFile", "");
2332 name
= filename
= mono_string_handle_to_utf8 (fname
, error
);
2333 goto_if_nok (error
, leave
);
2335 MonoAssembly
*requesting_assembly
;
2336 requesting_assembly
= NULL
;
2338 requesting_assembly
= mono_runtime_get_caller_from_stack_mark (stack_mark
);
2341 MonoAssemblyOpenRequest req
;
2342 mono_assembly_request_prepare (&req
.request
, sizeof (req
), refOnly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_LOADFROM
);
2343 req
.requesting_assembly
= requesting_assembly
;
2344 ass
= mono_assembly_request_open (filename
, &req
, &status
);
2347 if (status
== MONO_IMAGE_IMAGE_INVALID
)
2348 mono_error_set_bad_image_by_name (error
, name
, "Invalid Image");
2350 mono_error_set_file_not_found (error
, name
, "Invalid Image");
2354 result
= mono_assembly_get_object_handle (domain
, ass
, error
);
2361 MonoReflectionAssemblyHandle
2362 ves_icall_System_Reflection_Assembly_LoadFile_internal (MonoStringHandle fname
, MonoStackCrawlMark
*stack_mark
, MonoError
*error
)
2364 MonoDomain
*domain
= mono_domain_get ();
2365 MonoReflectionAssemblyHandle result
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2366 char *filename
= NULL
;
2367 if (MONO_HANDLE_IS_NULL (fname
)) {
2368 mono_error_set_argument_null (error
, "assemblyFile", "");
2372 filename
= mono_string_handle_to_utf8 (fname
, error
);
2373 goto_if_nok (error
, leave
);
2375 if (!g_path_is_absolute (filename
)) {
2376 mono_error_set_argument (error
, "assemblyFile", "Absolute path information is required.");
2380 MonoImageOpenStatus status
;
2381 MonoAssembly
*executing_assembly
;
2382 executing_assembly
= mono_runtime_get_caller_from_stack_mark (stack_mark
);
2384 MonoAssemblyOpenRequest req
;
2385 mono_assembly_request_prepare (&req
.request
, sizeof (req
), MONO_ASMCTX_INDIVIDUAL
);
2386 req
.requesting_assembly
= executing_assembly
;
2387 ass
= mono_assembly_request_open (filename
, &req
, &status
);
2389 if (status
== MONO_IMAGE_IMAGE_INVALID
)
2390 mono_error_set_bad_image_by_name (error
, filename
, "Invalid Image");
2392 mono_error_set_file_not_found (error
, filename
, "Invalid Image");
2396 result
= mono_assembly_get_object_handle (domain
, ass
, error
);
2402 MonoReflectionAssemblyHandle
2403 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad
,
2404 MonoArrayHandle raw_assembly
,
2405 MonoArrayHandle raw_symbol_store
, MonoObjectHandle evidence
,
2406 MonoBoolean refonly
,
2410 MonoReflectionAssemblyHandle refass
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2411 MonoDomain
*domain
= MONO_HANDLE_GETVAL(ad
, data
);
2412 MonoImageOpenStatus status
;
2413 guint32 raw_assembly_len
= mono_array_handle_length (raw_assembly
);
2415 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2416 char *assembly_data
= (char*) g_try_malloc (raw_assembly_len
);
2417 if (!assembly_data
) {
2418 mono_error_set_out_of_memory (error
, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len
);
2422 mono_byte
*raw_data
= (mono_byte
*) MONO_ARRAY_HANDLE_PIN (raw_assembly
, gchar
, 0, &gchandle
);
2423 memcpy (assembly_data
, raw_data
, raw_assembly_len
);
2424 mono_gchandle_free_internal (gchandle
); /* unpin */
2425 MONO_HANDLE_ASSIGN (raw_assembly
, NULL_HANDLE
); /* don't reference the data anymore */
2427 MonoImage
*image
= mono_image_open_from_data_internal (assembly_data
, raw_assembly_len
, FALSE
, NULL
, refonly
, FALSE
, NULL
);
2430 mono_error_set_bad_image_by_name (error
, "In memory assembly", "0x%p", raw_data
);
2434 if (!MONO_HANDLE_IS_NULL(raw_symbol_store
)) {
2435 guint32 symbol_len
= mono_array_handle_length (raw_symbol_store
);
2436 uint32_t symbol_gchandle
;
2437 mono_byte
*raw_symbol_data
= (mono_byte
*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store
, mono_byte
, 0, &symbol_gchandle
);
2438 mono_debug_open_image_from_memory (image
, raw_symbol_data
, symbol_len
);
2439 mono_gchandle_free_internal (symbol_gchandle
);
2442 MonoAssembly
* redirected_asm
= NULL
;
2443 MonoImageOpenStatus new_status
= MONO_IMAGE_OK
;
2444 if ((redirected_asm
= mono_assembly_binding_applies_to_image (image
, &new_status
))) {
2445 mono_image_close (image
);
2446 image
= redirected_asm
->image
;
2447 mono_image_addref (image
); /* so that mono_image close, below, has something to do */
2448 } else if (new_status
!= MONO_IMAGE_OK
) {
2449 mono_image_close (image
);
2450 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
);
2454 MonoAssemblyLoadRequest req
;
2455 mono_assembly_request_prepare (&req
, sizeof (req
), refonly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_INDIVIDUAL
);
2456 ass
= mono_assembly_request_load_from (image
, "", &req
, &status
);
2459 mono_image_close (image
);
2460 mono_error_set_bad_image_by_name (error
, "In Memory assembly", "0x%p", assembly_data
);
2464 /* Clear the reference added by mono_image_open_from_data_internal above */
2465 mono_image_close (image
);
2467 refass
= mono_assembly_get_object_handle (domain
, ass
, error
);
2468 if (!MONO_HANDLE_IS_NULL(refass
))
2469 MONO_HANDLE_SET (refass
, evidence
, evidence
);
2473 MonoReflectionAssemblyHandle
2474 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad
, MonoStringHandle assRef
, MonoObjectHandle evidence
, MonoBoolean refOnly
, MonoStackCrawlMark
*stack_mark
, MonoError
*error
)
2476 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
2477 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2479 MonoAssemblyName aname
;
2483 g_assert (!MONO_HANDLE_IS_NULL (assRef
));
2485 name
= mono_string_handle_to_utf8 (assRef
, error
);
2486 goto_if_nok (error
, fail
);
2487 parsed
= mono_assembly_name_parse (name
, &aname
);
2491 MonoReflectionAssemblyHandle refass
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2492 /* This is a parse error... */
2494 MonoAssembly
*assm
= mono_try_assembly_resolve_handle (domain
, assRef
, NULL
, refOnly
, error
);
2495 goto_if_nok (error
, fail
);
2497 refass
= mono_assembly_get_object_handle (domain
, assm
, error
);
2498 goto_if_nok (error
, fail
);
2504 MonoAssemblyContextKind asmctx
;
2505 asmctx
= refOnly
? MONO_ASMCTX_REFONLY
: MONO_ASMCTX_DEFAULT
;
2506 const char *basedir
;
2509 /* Determine if the current assembly is in LoadFrom context.
2510 * If it is, we must include the executing assembly's basedir
2511 * when probing for the given assembly name, and also load the
2512 * requested assembly in LoadFrom context.
2514 MonoAssembly
*executing_assembly
= mono_runtime_get_caller_from_stack_mark (stack_mark
);
2515 if (executing_assembly
&& mono_asmctx_get_kind (&executing_assembly
->context
) == MONO_ASMCTX_LOADFROM
) {
2516 asmctx
= MONO_ASMCTX_LOADFROM
;
2517 basedir
= executing_assembly
->basedir
;
2522 MonoAssemblyByNameRequest req
;
2523 mono_assembly_request_prepare (&req
.request
, sizeof (req
), asmctx
);
2524 req
.basedir
= basedir
;
2525 req
.no_postload_search
= TRUE
;
2526 ass
= mono_assembly_request_byname (&aname
, &req
, &status
);
2527 mono_assembly_name_free (&aname
);
2530 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2532 ass
= mono_try_assembly_resolve_handle (domain
, assRef
, NULL
, refOnly
, error
);
2533 goto_if_nok (error
, fail
);
2540 MonoReflectionAssemblyHandle refass
;
2541 refass
= mono_assembly_get_object_handle (domain
, ass
, error
);
2542 goto_if_nok (error
, fail
);
2544 MONO_HANDLE_SET (refass
, evidence
, evidence
);
2548 return MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2552 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id
, MonoError
*error
)
2554 MonoDomain
* domain
= mono_domain_get_by_id (domain_id
);
2556 if (NULL
== domain
) {
2557 mono_error_set_execution_engine (error
, "Failed to unload domain, domain id not found");
2561 if (domain
== mono_get_root_domain ()) {
2562 mono_error_set_generic_error (error
, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2567 * Unloading seems to cause problems when running NUnit/NAnt, hence
2570 if (g_hasenv ("MONO_NO_UNLOAD"))
2573 MonoException
*exc
= NULL
;
2574 mono_domain_try_unload (domain
, (MonoObject
**)&exc
);
2576 mono_error_set_exception_instance (error
, exc
);
2580 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id
, MonoError
*error
)
2582 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2587 return mono_domain_is_unloading (domain
);
2591 ves_icall_System_AppDomain_DoUnhandledException (MonoExceptionHandle exc
, MonoError
*error
)
2593 mono_unhandled_exception_checked (MONO_HANDLE_CAST (MonoObject
, exc
), error
);
2594 mono_error_assert_ok (error
);
2598 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad
,
2599 MonoReflectionAssemblyHandle refass
, MonoArrayHandle args
,
2605 g_assert (!MONO_HANDLE_IS_NULL (refass
));
2606 MonoAssembly
*assembly
= MONO_HANDLE_GETVAL (refass
, assembly
);
2607 image
= assembly
->image
;
2610 method
= mono_get_method_checked (image
, mono_image_get_entry_point (image
), NULL
, NULL
, error
);
2613 g_error ("No entry point method found in %s due to %s", image
->name
, mono_error_get_message (error
));
2615 if (MONO_HANDLE_IS_NULL (args
)) {
2616 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
2617 MONO_HANDLE_ASSIGN (args
, mono_array_new_handle (domain
, mono_defaults
.string_class
, 0, error
));
2618 mono_error_assert_ok (error
);
2621 int res
= mono_runtime_exec_main_checked (method
, MONO_HANDLE_RAW (args
), error
);
2626 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad
, MonoError
* error
)
2629 MonoDomain
*old_domain
= mono_domain_get ();
2631 if (!mono_domain_set (MONO_HANDLE_GETVAL (ad
, data
), FALSE
)) {
2632 mono_error_set_appdomain_unloaded (error
);
2633 return MONO_HANDLE_CAST (MonoAppDomain
, NULL_HANDLE
);
2636 return MONO_HANDLE_NEW (MonoAppDomain
, old_domain
->domain
);
2640 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid
, MonoError
*error
)
2642 MonoDomain
*current_domain
= mono_domain_get ();
2643 MonoDomain
*domain
= mono_domain_get_by_id (domainid
);
2645 if (!domain
|| !mono_domain_set (domain
, FALSE
)) {
2646 mono_error_set_appdomain_unloaded (error
);
2647 return MONO_HANDLE_CAST (MonoAppDomain
, NULL_HANDLE
);
2650 return MONO_HANDLE_NEW (MonoAppDomain
, current_domain
->domain
);
2654 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad
, MonoError
*error
)
2657 mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad
, data
));
2661 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id
, MonoError
*error
)
2664 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2668 * Raise an exception to prevent the managed code from executing a pop
2671 mono_error_set_appdomain_unloaded (error
);
2675 mono_thread_push_appdomain_ref (domain
);
2679 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError
*error
)
2682 mono_thread_pop_appdomain_ref ();
2685 MonoAppContextHandle
2686 ves_icall_System_AppDomain_InternalGetContext (MonoError
*error
)
2689 return mono_context_get_handle ();
2692 MonoAppContextHandle
2693 ves_icall_System_AppDomain_InternalGetDefaultContext (MonoError
*error
)
2696 return MONO_HANDLE_NEW (MonoAppContext
, mono_domain_get ()->default_context
);
2699 MonoAppContextHandle
2700 ves_icall_System_AppDomain_InternalSetContext (MonoAppContextHandle mc
, MonoError
*error
)
2703 MonoAppContextHandle old_context
= mono_context_get_handle ();
2705 mono_context_set_handle (mc
);
2711 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid
, MonoError
*error
)
2714 MonoDomain
* mono_root_domain
= mono_get_root_domain ();
2715 mono_domain_lock (mono_root_domain
);
2716 if (process_guid_set
) {
2717 mono_domain_unlock (mono_root_domain
);
2718 return mono_string_new_utf16_handle (mono_domain_get (), process_guid
, sizeof(process_guid
)/2, error
);
2720 uint32_t gchandle
= mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject
, newguid
), TRUE
);
2721 memcpy (process_guid
, mono_string_chars_internal (MONO_HANDLE_RAW (newguid
)), sizeof(process_guid
));
2722 mono_gchandle_free_internal (gchandle
);
2723 process_guid_set
= TRUE
;
2724 mono_domain_unlock (mono_root_domain
);
2729 * mono_domain_is_unloading:
2732 mono_domain_is_unloading (MonoDomain
*domain
)
2734 if (domain
->state
== MONO_APPDOMAIN_UNLOADING
|| domain
->state
== MONO_APPDOMAIN_UNLOADED
)
2741 clear_cached_vtable (MonoVTable
*vtable
)
2743 MonoClass
*klass
= vtable
->klass
;
2744 MonoDomain
*domain
= vtable
->domain
;
2745 MonoClassRuntimeInfo
*runtime_info
;
2748 runtime_info
= m_class_get_runtime_info (klass
);
2749 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
)
2750 runtime_info
->domain_vtables
[domain
->domain_id
] = NULL
;
2751 if (m_class_has_static_refs (klass
) && (data
= mono_vtable_get_static_field_data (vtable
)))
2752 mono_gc_free_fixed (data
);
2755 static G_GNUC_UNUSED
void
2756 zero_static_data (MonoVTable
*vtable
)
2758 MonoClass
*klass
= vtable
->klass
;
2761 if (m_class_has_static_refs (klass
) && (data
= mono_vtable_get_static_field_data (vtable
)))
2762 mono_gc_bzero_aligned (data
, mono_class_data_size (klass
));
2765 typedef struct unload_data
{
2768 char *failure_reason
;
2773 unload_data_unref (unload_data
*data
)
2779 mono_atomic_load_acquire (count
, gint32
, &data
->refcount
);
2780 g_assert (count
>= 1 && count
<= 2);
2785 } while (mono_atomic_cas_i32 (&data
->refcount
, count
- 1, count
) != count
);
2789 deregister_reflection_info_roots_from_list (MonoImage
*image
)
2791 GSList
*list
= image
->reflection_info_unregister_classes
;
2794 MonoClass
*klass
= (MonoClass
*)list
->data
;
2796 mono_class_free_ref_info (klass
);
2801 image
->reflection_info_unregister_classes
= NULL
;
2805 deregister_reflection_info_roots (MonoDomain
*domain
)
2809 mono_domain_assemblies_lock (domain
);
2810 for (list
= domain
->domain_assemblies
; list
; list
= list
->next
) {
2811 MonoAssembly
*assembly
= (MonoAssembly
*)list
->data
;
2812 MonoImage
*image
= assembly
->image
;
2816 * No need to take the image lock here since dynamic images are appdomain bound and
2817 * at this point the mutator is gone. Taking the image lock here would mean
2818 * promoting it from a simple lock to a complex lock, which we better avoid if
2821 if (image_is_dynamic (image
))
2822 deregister_reflection_info_roots_from_list (image
);
2824 for (i
= 0; i
< image
->module_count
; ++i
) {
2825 MonoImage
*module
= image
->modules
[i
];
2826 if (module
&& image_is_dynamic (module
))
2827 deregister_reflection_info_roots_from_list (module
);
2830 mono_domain_assemblies_unlock (domain
);
2834 unload_thread_main (void *arg
)
2837 unload_data
*data
= (unload_data
*)arg
;
2838 MonoDomain
*domain
= data
->domain
;
2839 MonoInternalThread
*internal
;
2841 gsize result
= 1; // failure
2843 internal
= mono_thread_internal_current ();
2845 MonoString
*thread_name_str
= mono_string_new_checked (mono_domain_get (), "Domain unloader", error
);
2847 mono_thread_set_name_internal (internal
, thread_name_str
, TRUE
, FALSE
, error
);
2848 if (!is_ok (error
)) {
2849 data
->failure_reason
= g_strdup (mono_error_get_message (error
));
2854 * FIXME: Abort our parent thread last, so we can return a failure
2855 * indication if aborting times out.
2857 if (!mono_threads_abort_appdomain_threads (domain
, -1)) {
2858 data
->failure_reason
= g_strdup_printf ("Aborting of threads in domain %s timed out.", domain
->friendly_name
);
2862 if (!mono_threadpool_remove_domain_jobs (domain
, -1)) {
2863 data
->failure_reason
= g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain
->friendly_name
);
2867 /* Finalize all finalizable objects in the doomed appdomain */
2868 if (!mono_domain_finalize (domain
, -1)) {
2869 data
->failure_reason
= g_strdup_printf ("Finalization of domain %s timed out.", domain
->friendly_name
);
2873 /* Clear references to our vtables in class->runtime_info.
2874 * We also hold the loader lock because we're going to change
2875 * class->runtime_info.
2878 mono_loader_lock (); //FIXME why do we need the loader lock here?
2879 mono_domain_lock (domain
);
2881 * We need to make sure that we don't have any remsets
2882 * pointing into static data of the to-be-freed domain because
2883 * at the next collections they would be invalid. So what we
2884 * do is we first zero all static data and then do a minor
2885 * collection. Because all references in the static data will
2886 * now be null we won't do any unnecessary copies and after
2887 * the collection there won't be any more remsets.
2889 for (i
= 0; i
< domain
->class_vtable_array
->len
; ++i
)
2890 zero_static_data ((MonoVTable
*)g_ptr_array_index (domain
->class_vtable_array
, i
));
2891 mono_gc_collect (0);
2892 for (i
= 0; i
< domain
->class_vtable_array
->len
; ++i
)
2893 clear_cached_vtable ((MonoVTable
*)g_ptr_array_index (domain
->class_vtable_array
, i
));
2894 deregister_reflection_info_roots (domain
);
2896 mono_assembly_cleanup_domain_bindings (domain
->domain_id
);
2898 mono_domain_unlock (domain
);
2899 mono_loader_unlock ();
2901 domain
->state
= MONO_APPDOMAIN_UNLOADED
;
2903 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2905 /* remove from the handle table the items related to this domain */
2906 mono_gchandle_free_domain (domain
);
2908 mono_domain_free (domain
, FALSE
);
2910 mono_gc_collect (mono_gc_max_generation ());
2912 result
= 0; // success
2914 mono_error_cleanup (error
);
2915 mono_atomic_store_release (&data
->done
, TRUE
);
2916 unload_data_unref (data
);
2925 * mono_domain_unload:
2926 * \param domain The domain to unload
2928 * Unloads an appdomain. Follows the process outlined in the comment
2929 * for \c mono_domain_try_unload.
2932 mono_domain_unload (MonoDomain
*domain
)
2934 MONO_ENTER_GC_UNSAFE
;
2935 MonoObject
*exc
= NULL
;
2936 mono_domain_try_unload (domain
, &exc
);
2937 MONO_EXIT_GC_UNSAFE
;
2940 static MonoThreadInfoWaitRet
2941 guarded_wait (MonoThreadHandle
*thread_handle
, guint32 timeout
, gboolean alertable
)
2943 MonoThreadInfoWaitRet result
;
2946 result
= mono_thread_info_wait_one_handle (thread_handle
, timeout
, alertable
);
2953 * mono_domain_unload:
2954 * \param domain The domain to unload
2955 * \param exc Exception information
2957 * Unloads an appdomain. Follows the process outlined in:
2958 * http://blogs.gotdotnet.com/cbrumme
2960 * If doing things the 'right' way is too hard or complex, we do it the
2961 * 'simple' way, which means do everything needed to avoid crashes and
2962 * memory leaks, but not much else.
2964 * It is required to pass a valid reference to the exc argument, upon return
2965 * from this function *exc will be set to the exception thrown, if any.
2967 * If this method is not called from an icall (embedded scenario for instance),
2968 * it must not be called with any managed frames on the stack, since the unload
2969 * process could end up trying to abort the current thread.
2972 mono_domain_try_unload (MonoDomain
*domain
, MonoObject
**exc
)
2974 HANDLE_FUNCTION_ENTER ();
2976 MonoThreadHandle
*thread_handle
= NULL
;
2977 MonoAppDomainState prev_state
;
2979 unload_data
*thread_data
= NULL
;
2980 MonoInternalThreadHandle internal
;
2981 MonoDomain
*caller_domain
= mono_domain_get ();
2983 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2985 /* Atomically change our state to UNLOADING */
2986 prev_state
= (MonoAppDomainState
)mono_atomic_cas_i32 ((gint32
*)&domain
->state
,
2987 MONO_APPDOMAIN_UNLOADING_START
,
2988 MONO_APPDOMAIN_CREATED
);
2989 if (prev_state
!= MONO_APPDOMAIN_CREATED
) {
2990 switch (prev_state
) {
2991 case MONO_APPDOMAIN_UNLOADING_START
:
2992 case MONO_APPDOMAIN_UNLOADING
:
2993 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2995 case MONO_APPDOMAIN_UNLOADED
:
2996 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2999 g_warning ("Invalid appdomain state %d", prev_state
);
3000 g_assert_not_reached ();
3004 mono_domain_set (domain
, FALSE
);
3005 /* Notify OnDomainUnload listeners */
3006 method
= mono_class_get_method_from_name_checked (domain
->domain
->mbr
.obj
.vtable
->klass
, "DoDomainUnload", -1, 0, error
);
3009 mono_runtime_try_invoke (method
, domain
->domain
, NULL
, exc
, error
);
3011 if (!mono_error_ok (error
)) {
3013 mono_error_cleanup (error
);
3015 *exc
= (MonoObject
*)mono_error_convert_to_exception (error
);
3019 /* Roll back the state change */
3020 domain
->state
= MONO_APPDOMAIN_CREATED
;
3021 mono_domain_set (caller_domain
, FALSE
);
3024 mono_domain_set (caller_domain
, FALSE
);
3026 thread_data
= g_new0 (unload_data
, 1);
3027 thread_data
->domain
= domain
;
3028 thread_data
->failure_reason
= NULL
;
3029 thread_data
->done
= FALSE
;
3030 thread_data
->refcount
= 2; /*Must be 2: unload thread + initiator */
3032 /*The managed callback finished successfully, now we start tearing down the appdomain*/
3033 domain
->state
= MONO_APPDOMAIN_UNLOADING
;
3035 * First we create a separate thread for unloading, since
3036 * we might have to abort some threads, including the current one.
3038 * Have to attach to the runtime so shutdown can wait for this thread.
3040 * Force it to be attached to avoid racing during shutdown.
3042 internal
= mono_thread_create_internal_handle (mono_get_root_domain (), unload_thread_main
, thread_data
, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE
, error
);
3043 mono_error_assert_ok (error
);
3045 thread_handle
= mono_threads_open_thread_handle (MONO_HANDLE_GETVAL (internal
, handle
));
3047 /* Wait for the thread */
3048 while (!thread_data
->done
&& guarded_wait (thread_handle
, MONO_INFINITE_WAIT
, TRUE
) == MONO_THREAD_INFO_WAIT_RET_ALERTED
) {
3049 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain
) && (mono_thread_interruption_requested ())) {
3050 /* The unload thread tries to abort us */
3051 /* The icall wrapper will execute the abort */
3056 if (thread_data
->failure_reason
) {
3057 /* Roll back the state change */
3058 domain
->state
= MONO_APPDOMAIN_CREATED
;
3060 g_warning ("%s", thread_data
->failure_reason
);
3062 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain (thread_data
->failure_reason
);
3064 g_free (thread_data
->failure_reason
);
3065 thread_data
->failure_reason
= NULL
;
3069 mono_threads_close_thread_handle (thread_handle
);
3070 unload_data_unref (thread_data
);
3071 HANDLE_FUNCTION_RETURN ();