2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 #undef ASSEMBLY_LOAD_DEBUG
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
28 #ifdef HAVE_SYS_UTIME_H
29 #include <sys/utime.h>
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/object.h>
35 #include <mono/metadata/domain-internals.h>
36 #include "mono/metadata/metadata-internals.h"
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/socket-io.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/gc-internal.h>
43 #include <mono/metadata/mono-gc.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/monitor.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/mono-debug-debugger.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/file-io.h>
51 #include <mono/metadata/lock-tracer.h>
52 #include <mono/metadata/console-io.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/tokentype.h>
55 #include <mono/utils/mono-uri.h>
56 #include <mono/utils/mono-logger.h>
57 #include <mono/utils/mono-path.h>
58 #include <mono/utils/mono-stdlib.h>
59 #include <mono/utils/mono-io-portability.h>
60 #include <mono/utils/mono-error-internals.h>
66 * This is the version number of the corlib-runtime interface. When
67 * making changes to this interface (by changing the layout
68 * of classes the runtime knows about, changing icall signature or
69 * semantics etc), increment this variable. Also increment the
70 * pair of this variable in mscorlib in:
71 * mcs/class/mscorlib/System/Environment.cs
73 * Changes which are already detected at runtime, like the addition
74 * of icalls, do not require an increment.
76 #define MONO_CORLIB_VERSION 89
81 int assemblybinding_count
;
85 CRITICAL_SECTION mono_delegate_section
;
88 /* Need to lock here because EGLIB has locking defined as no-ops, we can not depend on mono_strtod do the right locking */
89 /* Ideally this will be fixed in eglib */
90 CRITICAL_SECTION mono_strtod_mutex
;
94 static gunichar2 process_guid
[36];
95 static gboolean process_guid_set
= FALSE
;
97 static gboolean shutting_down
= FALSE
;
99 static gboolean no_exec
= FALSE
;
101 static MonoAssembly
*
102 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
103 gchar
**assemblies_path
,
106 static MonoAssembly
*
107 mono_domain_assembly_search (MonoAssemblyName
*aname
,
110 static MonoAssembly
*
111 mono_domain_assembly_postload_search (MonoAssemblyName
*aname
,
115 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
);
118 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*hash
);
120 static MonoAppDomain
*
121 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetup
*setup
);
124 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
);
126 static MonoLoadFunc load_function
= NULL
;
129 mono_install_runtime_load (MonoLoadFunc func
)
131 load_function
= func
;
135 mono_runtime_load (const char *filename
, const char *runtime_version
)
137 g_assert (load_function
);
138 return load_function (filename
, runtime_version
);
142 * mono_runtime_set_no_exec:
144 * Instructs the runtime to operate in static mode, i.e. avoid/do not
145 * allow managed code execution. This is useful for running the AOT
146 * compiler on platforms which allow full-aot execution only. This
147 * should be called before mono_runtime_init ().
150 mono_runtime_set_no_exec (gboolean val
)
156 * mono_runtime_get_no_exec:
158 * If true, then the runtime will not allow managed code execution.
161 mono_runtime_get_no_exec (void)
167 create_exceptions (MonoDomain
*domain
)
169 MonoDomain
*old_domain
= mono_domain_get ();
172 if (domain
!= old_domain
) {
173 mono_thread_push_appdomain_ref (domain
);
174 mono_domain_set_internal_with_options (domain
, FALSE
);
178 * Create an instance early since we can't do it when there is no memory.
180 arg
= mono_string_new (domain
, "Out of memory");
181 domain
->out_of_memory_ex
= mono_exception_from_name_two_strings (mono_defaults
.corlib
, "System", "OutOfMemoryException", arg
, NULL
);
184 * These two are needed because the signal handlers might be executing on
185 * an alternate stack, and Boehm GC can't handle that.
187 arg
= mono_string_new (domain
, "A null value was found where an object instance was required");
188 domain
->null_reference_ex
= mono_exception_from_name_two_strings (mono_defaults
.corlib
, "System", "NullReferenceException", arg
, NULL
);
189 arg
= mono_string_new (domain
, "The requested operation caused a stack overflow.");
190 domain
->stack_overflow_ex
= mono_exception_from_name_two_strings (mono_defaults
.corlib
, "System", "StackOverflowException", arg
, NULL
);
192 if (domain
!= old_domain
) {
193 mono_thread_pop_appdomain_ref ();
194 mono_domain_set_internal_with_options (old_domain
, FALSE
);
198 * This class is used during exception handling, so initialize it here, to prevent
199 * stack overflows while handling stack overflows.
201 mono_class_init (mono_array_class_get (mono_defaults
.int_class
, 1));
206 * @domain: domain returned by mono_init ()
208 * Initialize the core AppDomain: this function will run also some
209 * IL initialization code, so it needs the execution engine to be fully
212 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
213 * we know the entry_assembly.
217 mono_runtime_init (MonoDomain
*domain
, MonoThreadStartCB start_cb
,
218 MonoThreadAttachCB attach_cb
)
220 MonoAppDomainSetup
*setup
;
224 mono_portability_helpers_init ();
226 mono_gc_base_init ();
227 mono_monitor_init ();
228 mono_thread_pool_init ();
229 mono_marshal_init ();
231 mono_install_assembly_preload_hook (mono_domain_assembly_preload
, GUINT_TO_POINTER (FALSE
));
232 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload
, GUINT_TO_POINTER (TRUE
));
233 mono_install_assembly_search_hook (mono_domain_assembly_search
, GUINT_TO_POINTER (FALSE
));
234 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search
, GUINT_TO_POINTER (TRUE
));
235 mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search
, GUINT_TO_POINTER (FALSE
));
236 mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search
, GUINT_TO_POINTER (TRUE
));
237 mono_install_assembly_load_hook (mono_domain_fire_assembly_load
, NULL
);
238 mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token
);
240 mono_thread_init (start_cb
, attach_cb
);
242 class = mono_class_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
243 setup
= (MonoAppDomainSetup
*) mono_object_new (domain
, class);
245 class = mono_class_from_name (mono_defaults
.corlib
, "System", "AppDomain");
246 ad
= (MonoAppDomain
*) mono_object_new (domain
, class);
249 domain
->setup
= setup
;
251 InitializeCriticalSection (&mono_delegate_section
);
254 /* Needed until EGLIB is fixed #464316 */
255 InitializeCriticalSection (&mono_strtod_mutex
);
258 mono_thread_attach (domain
);
259 mono_context_init (domain
);
260 mono_context_set (domain
->default_context
);
262 mono_type_initialization_init ();
264 if (!mono_runtime_get_no_exec ())
265 create_exceptions (domain
);
267 /* GC init has to happen after thread init */
270 #ifndef DISABLE_SOCKETS
271 mono_network_init ();
274 mono_console_init ();
277 mono_locks_tracer_init ();
279 /* mscorlib is loaded before we install the load hook */
280 mono_domain_fire_assembly_load (mono_defaults
.corlib
->assembly
, NULL
);
286 mono_get_corlib_version (void)
289 MonoClassField
*field
;
292 klass
= mono_class_from_name (mono_defaults
.corlib
, "System", "Environment");
293 mono_class_init (klass
);
294 field
= mono_class_get_field_from_name (klass
, "mono_corlib_version");
297 if (! (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
299 value
= mono_field_get_value_object (mono_domain_get (), field
, NULL
);
300 return *(gint32
*)((gchar
*)value
+ sizeof (MonoObject
));
304 * mono_check_corlib_version
306 * Checks that the corlib that is loaded matches the version of this runtime.
308 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
309 * allocated string with the error otherwise.
312 mono_check_corlib_version (void)
314 int version
= mono_get_corlib_version ();
315 if (version
!= MONO_CORLIB_VERSION
)
316 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION
, version
);
323 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
325 * Initializes the @domain's default System.Runtime.Remoting's Context.
328 mono_context_init (MonoDomain
*domain
)
331 MonoAppContext
*context
;
333 class = mono_class_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Contexts", "Context");
334 context
= (MonoAppContext
*) mono_object_new (domain
, class);
335 context
->domain_id
= domain
->domain_id
;
336 context
->context_id
= 0;
337 domain
->default_context
= context
;
341 * mono_runtime_cleanup:
346 * This must not be called while there are still running threads executing
350 mono_runtime_cleanup (MonoDomain
*domain
)
352 shutting_down
= TRUE
;
354 mono_attach_cleanup ();
356 /* This ends up calling any pending pending (for at most 2 seconds) */
359 mono_thread_cleanup ();
361 #ifndef DISABLE_SOCKETS
362 mono_network_cleanup ();
364 mono_marshal_cleanup ();
366 mono_type_initialization_cleanup ();
368 mono_monitor_cleanup ();
375 static MonoDomainFunc quit_function
= NULL
;
378 mono_install_runtime_cleanup (MonoDomainFunc func
)
380 quit_function
= func
;
386 if (quit_function
!= NULL
)
387 quit_function (mono_get_root_domain (), NULL
);
391 * mono_runtime_set_shutting_down:
393 * Invoked by System.Environment.Exit to flag that the runtime
397 mono_runtime_set_shutting_down (void)
399 shutting_down
= TRUE
;
403 * mono_runtime_is_shutting_down:
405 * Returns whether the runtime has been flagged for shutdown.
407 * This is consumed by the P:System.Environment.HasShutdownStarted
412 mono_runtime_is_shutting_down (void)
414 return shutting_down
;
418 * mono_domain_create_appdomain:
419 * @friendly_name: The friendly name of the appdomain to create
420 * @configuration_file: The configuration file to initialize the appdomain with
422 * Returns a MonoDomain initialized with the appdomain
425 mono_domain_create_appdomain (char *friendly_name
, char *configuration_file
)
428 MonoAppDomainSetup
*setup
;
431 class = mono_class_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
432 setup
= (MonoAppDomainSetup
*) mono_object_new (mono_domain_get (), class);
433 setup
->configuration_file
= configuration_file
!= NULL
? mono_string_new (mono_domain_get (), configuration_file
) : NULL
;
435 ad
= mono_domain_create_appdomain_internal (friendly_name
, setup
);
437 return mono_domain_from_appdomain (ad
);
440 static MonoAppDomainSetup
*
441 copy_app_domain_setup (MonoDomain
*domain
, MonoAppDomainSetup
*setup
)
443 MonoDomain
*caller_domain
= mono_domain_get ();
444 MonoClass
*ads_class
= mono_class_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
445 MonoAppDomainSetup
*copy
= (MonoAppDomainSetup
*)mono_object_new (domain
, ads_class
);
447 mono_domain_set_internal (domain
);
449 MONO_OBJECT_SETREF (copy
, application_base
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->application_base
));
450 MONO_OBJECT_SETREF (copy
, application_name
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->application_name
));
451 MONO_OBJECT_SETREF (copy
, cache_path
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->cache_path
));
452 MONO_OBJECT_SETREF (copy
, configuration_file
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->configuration_file
));
453 MONO_OBJECT_SETREF (copy
, dynamic_base
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->dynamic_base
));
454 MONO_OBJECT_SETREF (copy
, license_file
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->license_file
));
455 MONO_OBJECT_SETREF (copy
, private_bin_path
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->private_bin_path
));
456 MONO_OBJECT_SETREF (copy
, private_bin_path_probe
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->private_bin_path_probe
));
457 MONO_OBJECT_SETREF (copy
, shadow_copy_directories
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->shadow_copy_directories
));
458 MONO_OBJECT_SETREF (copy
, shadow_copy_files
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->shadow_copy_files
));
459 copy
->publisher_policy
= setup
->publisher_policy
;
460 copy
->path_changed
= setup
->path_changed
;
461 copy
->loader_optimization
= setup
->loader_optimization
;
462 copy
->disallow_binding_redirects
= setup
->disallow_binding_redirects
;
463 copy
->disallow_code_downloads
= setup
->disallow_code_downloads
;
464 MONO_OBJECT_SETREF (copy
, domain_initializer_args
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->domain_initializer_args
));
465 copy
->disallow_appbase_probe
= setup
->disallow_appbase_probe
;
466 MONO_OBJECT_SETREF (copy
, application_trust
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->application_trust
));
467 MONO_OBJECT_SETREF (copy
, configuration_bytes
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->configuration_bytes
));
468 MONO_OBJECT_SETREF (copy
, serialized_non_primitives
, mono_marshal_xdomain_copy_value ((MonoObject
*)setup
->serialized_non_primitives
));
470 mono_domain_set_internal (caller_domain
);
475 static MonoAppDomain
*
476 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetup
*setup
)
482 char *shadow_location
;
486 adclass
= mono_class_from_name (mono_defaults
.corlib
, "System", "AppDomain");
488 /* FIXME: pin all those objects */
489 data
= mono_domain_create();
491 ad
= (MonoAppDomain
*) mono_object_new (data
, adclass
);
494 data
->friendly_name
= g_strdup (friendly_name
);
496 if (!setup
->application_base
) {
497 /* Inherit from the root domain since MS.NET does this */
498 MonoDomain
*root
= mono_get_root_domain ();
499 if (root
->setup
->application_base
)
500 MONO_OBJECT_SETREF (setup
, application_base
, mono_string_new_utf16 (data
, mono_string_chars (root
->setup
->application_base
), mono_string_length (root
->setup
->application_base
)));
503 mono_context_init (data
);
505 mono_set_private_bin_path_from_config (data
);
507 add_assemblies_to_domain (data
, mono_defaults
.corlib
->assembly
, NULL
);
509 data
->setup
= copy_app_domain_setup (data
, setup
);
511 #ifndef DISABLE_SHADOW_COPY
512 /*FIXME, guard this for when the debugger is not running */
513 shadow_location
= get_shadow_assembly_location_base (data
, &error
);
514 if (!mono_error_ok (&error
))
515 mono_error_raise_exception (&error
);
516 mono_debugger_event_create_appdomain (data
, shadow_location
);
517 g_free (shadow_location
);
520 create_exceptions (data
);
526 * mono_domain_has_type_resolve:
527 * @domain: application domains being looked up
529 * Returns true if the AppDomain.TypeResolve field has been
533 mono_domain_has_type_resolve (MonoDomain
*domain
)
535 static MonoClassField
*field
= NULL
;
539 field
= mono_class_get_field_from_name (mono_defaults
.appdomain_class
, "TypeResolve");
543 mono_field_get_value ((MonoObject
*)(domain
->domain
), field
, &o
);
548 * mono_domain_try_type_resolve:
549 * @domain: application domainwhere the name where the type is going to be resolved
550 * @name: the name of the type to resolve or NULL.
551 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
553 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
554 * the assembly that matches name.
556 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
558 * Returns: A MonoReflectionAssembly or NULL if not found
560 MonoReflectionAssembly
*
561 mono_domain_try_type_resolve (MonoDomain
*domain
, char *name
, MonoObject
*tb
)
565 static MonoMethod
*method
= NULL
;
567 g_assert (domain
!= NULL
&& ((name
!= NULL
) || (tb
!= NULL
)));
569 if (method
== NULL
) {
570 klass
= domain
->domain
->mbr
.obj
.vtable
->klass
;
573 method
= mono_class_get_method_from_name (klass
, "DoTypeResolve", -1);
574 if (method
== NULL
) {
575 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
581 *params
= (MonoObject
*)mono_string_new (mono_domain_get (), name
);
584 return (MonoReflectionAssembly
*) mono_runtime_invoke (method
, domain
->domain
, params
, NULL
);
588 * mono_domain_owns_vtable_slot:
590 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
593 mono_domain_owns_vtable_slot (MonoDomain
*domain
, gpointer vtable_slot
)
597 mono_domain_lock (domain
);
598 res
= mono_mempool_contains_addr (domain
->mp
, vtable_slot
);
599 mono_domain_unlock (domain
);
606 * @force: force setting.
608 * Set the current appdomain to @domain. If @force is set, set it even
609 * if it is being unloaded.
613 * FALSE if the domain is unloaded
616 mono_domain_set (MonoDomain
*domain
, gboolean force
)
618 if (!force
&& domain
->state
== MONO_APPDOMAIN_UNLOADED
)
621 mono_domain_set_internal (domain
);
627 ves_icall_System_AppDomain_GetData (MonoAppDomain
*ad
, MonoString
*name
)
635 g_assert (ad
!= NULL
);
637 g_assert (add
!= NULL
);
640 mono_raise_exception (mono_get_exception_argument_null ("name"));
642 str
= mono_string_to_utf8 (name
);
644 mono_domain_lock (add
);
646 if (!strcmp (str
, "APPBASE"))
647 o
= (MonoObject
*)add
->setup
->application_base
;
648 else if (!strcmp (str
, "APP_CONFIG_FILE"))
649 o
= (MonoObject
*)add
->setup
->configuration_file
;
650 else if (!strcmp (str
, "DYNAMIC_BASE"))
651 o
= (MonoObject
*)add
->setup
->dynamic_base
;
652 else if (!strcmp (str
, "APP_NAME"))
653 o
= (MonoObject
*)add
->setup
->application_name
;
654 else if (!strcmp (str
, "CACHE_BASE"))
655 o
= (MonoObject
*)add
->setup
->cache_path
;
656 else if (!strcmp (str
, "PRIVATE_BINPATH"))
657 o
= (MonoObject
*)add
->setup
->private_bin_path
;
658 else if (!strcmp (str
, "BINPATH_PROBE_ONLY"))
659 o
= (MonoObject
*)add
->setup
->private_bin_path_probe
;
660 else if (!strcmp (str
, "SHADOW_COPY_DIRS"))
661 o
= (MonoObject
*)add
->setup
->shadow_copy_directories
;
662 else if (!strcmp (str
, "FORCE_CACHE_INSTALL"))
663 o
= (MonoObject
*)add
->setup
->shadow_copy_files
;
665 o
= mono_g_hash_table_lookup (add
->env
, name
);
667 mono_domain_unlock (add
);
677 ves_icall_System_AppDomain_SetData (MonoAppDomain
*ad
, MonoString
*name
, MonoObject
*data
)
683 g_assert (ad
!= NULL
);
685 g_assert (add
!= NULL
);
688 mono_raise_exception (mono_get_exception_argument_null ("name"));
690 mono_domain_lock (add
);
692 mono_g_hash_table_insert (add
->env
, name
, data
);
694 mono_domain_unlock (add
);
698 ves_icall_System_AppDomain_getSetup (MonoAppDomain
*ad
)
702 g_assert (ad
!= NULL
);
703 g_assert (ad
->data
!= NULL
);
705 return ad
->data
->setup
;
709 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain
*ad
)
713 g_assert (ad
!= NULL
);
714 g_assert (ad
->data
!= NULL
);
716 return mono_string_new (ad
->data
, ad
->data
->friendly_name
);
720 ves_icall_System_AppDomain_getCurDomain ()
722 MonoDomain
*add
= mono_domain_get ();
730 ves_icall_System_AppDomain_getRootDomain ()
732 MonoDomain
*root
= mono_get_root_domain ();
740 get_attribute_value (const gchar
**attribute_names
,
741 const gchar
**attribute_values
,
742 const char *att_name
)
745 for (n
= 0; attribute_names
[n
] != NULL
; n
++) {
746 if (strcmp (attribute_names
[n
], att_name
) == 0)
747 return g_strdup (attribute_values
[n
]);
753 start_element (GMarkupParseContext
*context
,
754 const gchar
*element_name
,
755 const gchar
**attribute_names
,
756 const gchar
**attribute_values
,
760 RuntimeConfig
*runtime_config
= user_data
;
762 if (strcmp (element_name
, "runtime") == 0) {
763 runtime_config
->runtime_count
++;
767 if (strcmp (element_name
, "assemblyBinding") == 0) {
768 runtime_config
->assemblybinding_count
++;
772 if (runtime_config
->runtime_count
!= 1 || runtime_config
->assemblybinding_count
!= 1)
775 if (strcmp (element_name
, "probing") != 0)
778 g_free (runtime_config
->domain
->private_bin_path
);
779 runtime_config
->domain
->private_bin_path
= get_attribute_value (attribute_names
, attribute_values
, "privatePath");
780 if (runtime_config
->domain
->private_bin_path
&& !runtime_config
->domain
->private_bin_path
[0]) {
781 g_free (runtime_config
->domain
->private_bin_path
);
782 runtime_config
->domain
->private_bin_path
= NULL
;
788 end_element (GMarkupParseContext
*context
,
789 const gchar
*element_name
,
793 RuntimeConfig
*runtime_config
= user_data
;
794 if (strcmp (element_name
, "runtime") == 0)
795 runtime_config
->runtime_count
--;
796 else if (strcmp (element_name
, "assemblyBinding") == 0)
797 runtime_config
->assemblybinding_count
--;
800 static const GMarkupParser
810 mono_set_private_bin_path_from_config (MonoDomain
*domain
)
813 gchar
*config_file
, *text
;
815 GMarkupParseContext
*context
;
816 RuntimeConfig runtime_config
;
818 if (!domain
|| !domain
->setup
|| !domain
->setup
->configuration_file
)
821 config_file
= mono_string_to_utf8_checked (domain
->setup
->configuration_file
, &error
);
822 if (!mono_error_ok (&error
)) {
823 mono_error_cleanup (&error
);
827 if (!g_file_get_contents (config_file
, &text
, &len
, NULL
)) {
828 g_free (config_file
);
831 g_free (config_file
);
833 runtime_config
.runtime_count
= 0;
834 runtime_config
.assemblybinding_count
= 0;
835 runtime_config
.domain
= domain
;
837 context
= g_markup_parse_context_new (&mono_parser
, 0, &runtime_config
, NULL
);
838 if (g_markup_parse_context_parse (context
, text
, len
, NULL
))
839 g_markup_parse_context_end_parse (context
, NULL
);
840 g_markup_parse_context_free (context
);
845 ves_icall_System_AppDomain_createDomain (MonoString
*friendly_name
, MonoAppDomainSetup
*setup
)
847 char *fname
= mono_string_to_utf8 (friendly_name
);
848 MonoAppDomain
*ad
= mono_domain_create_appdomain_internal (fname
, setup
);
856 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain
*ad
, MonoBoolean refonly
)
858 MonoDomain
*domain
= ad
->data
;
860 static MonoClass
*System_Reflection_Assembly
;
864 GPtrArray
*assemblies
;
868 if (!System_Reflection_Assembly
)
869 System_Reflection_Assembly
= mono_class_from_name (
870 mono_defaults
.corlib
, "System.Reflection", "Assembly");
873 * Make a copy of the list of assemblies because we can't hold the assemblies
874 * lock while creating objects etc.
876 assemblies
= g_ptr_array_new ();
877 /* Need to skip internal assembly builders created by remoting */
878 mono_domain_assemblies_lock (domain
);
879 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
881 if (refonly
!= ass
->ref_only
)
883 if (ass
->corlib_internal
)
885 g_ptr_array_add (assemblies
, ass
);
887 mono_domain_assemblies_unlock (domain
);
889 res
= mono_array_new (domain
, System_Reflection_Assembly
, assemblies
->len
);
890 for (i
= 0; i
< assemblies
->len
; ++i
) {
891 ass
= g_ptr_array_index (assemblies
, i
);
892 mono_array_setref (res
, i
, mono_assembly_get_object (domain
, ass
));
895 g_ptr_array_free (assemblies
, TRUE
);
900 MonoReflectionAssembly
*
901 mono_try_assembly_resolve (MonoDomain
*domain
, MonoString
*fname
, gboolean refonly
)
905 MonoBoolean isrefonly
;
908 if (mono_runtime_get_no_exec ())
911 g_assert (domain
!= NULL
&& fname
!= NULL
);
913 klass
= domain
->domain
->mbr
.obj
.vtable
->klass
;
916 method
= mono_class_get_method_from_name (klass
, "DoAssemblyResolve", -1);
917 if (method
== NULL
) {
918 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
922 isrefonly
= refonly
? 1 : 0;
924 params
[1] = &isrefonly
;
925 return (MonoReflectionAssembly
*) mono_runtime_invoke (method
, domain
->domain
, params
, NULL
);
928 static MonoAssembly
*
929 mono_domain_assembly_postload_search (MonoAssemblyName
*aname
,
932 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
933 MonoReflectionAssembly
*assembly
;
934 MonoDomain
*domain
= mono_domain_get ();
937 aname_str
= mono_stringify_assembly_name (aname
);
939 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
940 assembly
= mono_try_assembly_resolve (domain
, mono_string_new (domain
, aname_str
), refonly
);
945 return assembly
->assembly
;
951 * LOCKING: assumes assemblies_lock in the domain is already locked.
954 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*ht
)
958 gboolean destroy_ht
= FALSE
;
960 if (!ass
->aname
.name
)
964 ht
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
968 /* FIXME: handle lazy loaded assemblies */
969 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
970 g_hash_table_insert (ht
, tmp
->data
, tmp
->data
);
972 if (!g_hash_table_lookup (ht
, ass
)) {
973 mono_assembly_addref (ass
);
974 g_hash_table_insert (ht
, ass
, ass
);
975 domain
->domain_assemblies
= g_slist_prepend (domain
->domain_assemblies
, ass
);
976 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly %s %p added to domain %s, ref_count=%d\n", ass
->aname
.name
, ass
, domain
->friendly_name
, ass
->ref_count
);
979 if (ass
->image
->references
) {
980 for (i
= 0; ass
->image
->references
[i
] != NULL
; i
++) {
981 if (ass
->image
->references
[i
] != REFERENCE_MISSING
)
982 if (!g_hash_table_lookup (ht
, ass
->image
->references
[i
])) {
983 add_assemblies_to_domain (domain
, ass
->image
->references
[i
], ht
);
988 g_hash_table_destroy (ht
);
992 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
)
994 static MonoClassField
*assembly_load_field
;
995 static MonoMethod
*assembly_load_method
;
996 MonoDomain
*domain
= mono_domain_get ();
997 MonoReflectionAssembly
*ref_assembly
;
1002 if (!domain
->domain
)
1003 /* This can happen during startup */
1005 #ifdef ASSEMBLY_LOAD_DEBUG
1006 fprintf (stderr
, "Loading %s into domain %s\n", assembly
->aname
.name
, domain
->friendly_name
);
1008 klass
= domain
->domain
->mbr
.obj
.vtable
->klass
;
1010 mono_domain_assemblies_lock (domain
);
1011 add_assemblies_to_domain (domain
, assembly
, NULL
);
1012 mono_domain_assemblies_unlock (domain
);
1014 if (assembly_load_field
== NULL
) {
1015 assembly_load_field
= mono_class_get_field_from_name (klass
, "AssemblyLoad");
1016 g_assert (assembly_load_field
);
1019 mono_field_get_value ((MonoObject
*) domain
->domain
, assembly_load_field
, &load_value
);
1020 if (load_value
== NULL
) {
1021 /* No events waiting to be triggered */
1025 ref_assembly
= mono_assembly_get_object (domain
, assembly
);
1026 g_assert (ref_assembly
);
1028 if (assembly_load_method
== NULL
) {
1029 assembly_load_method
= mono_class_get_method_from_name (klass
, "DoAssemblyLoad", -1);
1030 g_assert (assembly_load_method
);
1033 *params
= ref_assembly
;
1034 mono_runtime_invoke (assembly_load_method
, domain
->domain
, params
, NULL
);
1038 * LOCKING: Acquires the domain assemblies lock.
1041 set_domain_search_path (MonoDomain
*domain
)
1044 MonoAppDomainSetup
*setup
;
1046 gchar
*search_path
= NULL
;
1049 gchar
**pvt_split
= NULL
;
1050 GError
*gerror
= NULL
;
1051 gint appbaselen
= -1;
1054 * We use the low-level domain assemblies lock, since this is called from
1055 * assembly loads hooks, which means this thread might hold the loader lock.
1057 mono_domain_assemblies_lock (domain
);
1059 if (!domain
->setup
) {
1060 mono_domain_assemblies_unlock (domain
);
1064 if ((domain
->search_path
!= NULL
) && !domain
->setup
->path_changed
) {
1065 mono_domain_assemblies_unlock (domain
);
1068 setup
= domain
->setup
;
1069 if (!setup
->application_base
) {
1070 mono_domain_assemblies_unlock (domain
);
1071 return; /* Must set application base to get private path working */
1076 if (setup
->private_bin_path
) {
1077 search_path
= mono_string_to_utf8_checked (setup
->private_bin_path
, &error
);
1078 if (!mono_error_ok (&error
)) { /*FIXME maybe we should bubble up the error.*/
1079 g_warning ("Could not decode AppDomain search path since it contains invalid caracters");
1080 mono_error_cleanup (&error
);
1081 mono_domain_assemblies_unlock (domain
);
1086 if (domain
->private_bin_path
) {
1087 if (search_path
== NULL
)
1088 search_path
= domain
->private_bin_path
;
1090 gchar
*tmp2
= search_path
;
1091 search_path
= g_strjoin (";", search_path
, domain
->private_bin_path
, NULL
);
1098 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1099 * directories relative to ApplicationBase separated by semicolons (see
1100 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1101 * The loop below copes with the fact that some Unix applications may use ':' (or
1102 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1103 * ';' for the subsequent split.
1105 * The issue was reported in bug #81446
1108 #ifndef TARGET_WIN32
1111 slen
= strlen (search_path
);
1112 for (i
= 0; i
< slen
; i
++)
1113 if (search_path
[i
] == ':')
1114 search_path
[i
] = ';';
1117 pvt_split
= g_strsplit (search_path
, ";", 1000);
1118 g_free (search_path
);
1119 for (tmp
= pvt_split
; *tmp
; tmp
++, npaths
++);
1124 g_strfreev (pvt_split
);
1126 * Don't do this because the first time is called, the domain
1127 * setup is not finished.
1129 * domain->search_path = g_malloc (sizeof (char *));
1130 * domain->search_path [0] = NULL;
1132 mono_domain_assemblies_unlock (domain
);
1136 if (domain
->search_path
)
1137 g_strfreev (domain
->search_path
);
1139 tmp
= g_malloc ((npaths
+ 1) * sizeof (gchar
*));
1140 tmp
[npaths
] = NULL
;
1142 *tmp
= mono_string_to_utf8_checked (setup
->application_base
, &error
);
1143 if (!mono_error_ok (&error
)) {
1144 mono_error_cleanup (&error
);
1145 g_strfreev (pvt_split
);
1148 mono_domain_assemblies_unlock (domain
);
1152 domain
->search_path
= tmp
;
1154 /* FIXME: is this needed? */
1155 if (strncmp (*tmp
, "file://", 7) == 0) {
1161 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
1164 uri
= mono_escape_uri_string (tmpuri
);
1165 *tmp
= g_filename_from_uri (uri
, NULL
, &gerror
);
1171 if (gerror
!= NULL
) {
1172 g_warning ("%s\n", gerror
->message
);
1173 g_error_free (gerror
);
1180 for (i
= 1; pvt_split
&& i
< npaths
; i
++) {
1181 if (g_path_is_absolute (pvt_split
[i
- 1])) {
1182 tmp
[i
] = g_strdup (pvt_split
[i
- 1]);
1184 tmp
[i
] = g_build_filename (tmp
[0], pvt_split
[i
- 1], NULL
);
1187 if (strchr (tmp
[i
], '.')) {
1191 reduced
= mono_path_canonicalize (tmp
[i
]);
1192 if (appbaselen
== -1)
1193 appbaselen
= strlen (tmp
[0]);
1195 if (strncmp (tmp
[0], reduced
, appbaselen
)) {
1198 tmp
[i
] = g_strdup ("");
1208 if (setup
->private_bin_path_probe
!= NULL
) {
1210 tmp
[0] = g_strdup ("");
1213 domain
->setup
->path_changed
= FALSE
;
1215 g_strfreev (pvt_split
);
1217 mono_domain_assemblies_unlock (domain
);
1220 #ifdef DISABLE_SHADOW_COPY
1222 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1228 mono_make_shadow_copy (const char *filename
)
1230 return (char *) filename
;
1234 shadow_copy_sibling (gchar
*src
, gint srclen
, const char *extension
, gchar
*target
, gint targetlen
, gint tail_len
)
1236 guint16
*orig
, *dest
;
1237 gboolean copy_result
;
1239 strcpy (src
+ srclen
- tail_len
, extension
);
1240 if (!g_file_test (src
, G_FILE_TEST_IS_REGULAR
))
1242 orig
= g_utf8_to_utf16 (src
, strlen (src
), NULL
, NULL
, NULL
);
1244 strcpy (target
+ targetlen
- tail_len
, extension
);
1245 dest
= g_utf8_to_utf16 (target
, strlen (target
), NULL
, NULL
, NULL
);
1248 copy_result
= CopyFile (orig
, dest
, FALSE
);
1250 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1251 * overwritten when updated in their original locations. */
1253 copy_result
= SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1262 get_cstring_hash (const char *str
)
1268 if (!str
|| !str
[0])
1273 for (i
= 0; i
< len
; i
++) {
1274 h
= (h
<< 5) - h
+ *p
;
1282 * Returned memory is malloc'd. Called must free it
1285 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
)
1287 MonoAppDomainSetup
*setup
;
1288 char *cache_path
, *appname
;
1292 mono_error_init (error
);
1294 setup
= domain
->setup
;
1295 if (setup
->cache_path
!= NULL
&& setup
->application_name
!= NULL
) {
1296 cache_path
= mono_string_to_utf8_checked (setup
->cache_path
, error
);
1297 if (!mono_error_ok (error
))
1299 #ifndef TARGET_WIN32
1302 for (i
= strlen (cache_path
) - 1; i
>= 0; i
--)
1303 if (cache_path
[i
] == '\\')
1304 cache_path
[i
] = '/';
1308 appname
= mono_string_to_utf8_checked (setup
->application_name
, error
);
1309 if (!mono_error_ok (error
)) {
1310 g_free (cache_path
);
1314 location
= g_build_filename (cache_path
, appname
, "assembly", "shadow", NULL
);
1316 g_free (cache_path
);
1318 userdir
= g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1319 location
= g_build_filename (g_get_tmp_dir (), userdir
, "assembly", "shadow", NULL
);
1326 get_shadow_assembly_location (const char *filename
, MonoError
*error
)
1328 gint32 hash
= 0, hash2
= 0;
1330 char path_hash
[30];
1331 char *bname
= g_path_get_basename (filename
);
1332 char *dirname
= g_path_get_dirname (filename
);
1333 char *location
, *tmploc
;
1334 MonoDomain
*domain
= mono_domain_get ();
1336 mono_error_init (error
);
1338 hash
= get_cstring_hash (bname
);
1339 hash2
= get_cstring_hash (dirname
);
1340 g_snprintf (name_hash
, sizeof (name_hash
), "%08x", hash
);
1341 g_snprintf (path_hash
, sizeof (path_hash
), "%08x_%08x_%08x", hash
^ hash2
, hash2
, domain
->shadow_serial
);
1342 tmploc
= get_shadow_assembly_location_base (domain
, error
);
1343 if (!mono_error_ok (error
)) {
1349 location
= g_build_filename (tmploc
, name_hash
, path_hash
, bname
, NULL
);
1357 ensure_directory_exists (const char *filename
)
1360 gchar
*dir_utf8
= g_path_get_dirname (filename
);
1362 gunichar2
*dir_utf16
= NULL
;
1365 if (!dir_utf8
|| !dir_utf8
[0])
1368 dir_utf16
= g_utf8_to_utf16 (dir_utf8
, strlen (dir_utf8
), NULL
, NULL
, NULL
);
1376 /* make life easy and only use one directory seperator */
1387 while (*p
++ != '\\')
1393 p
= wcschr (p
, '\\');
1396 retval
= _wmkdir (dir_utf16
);
1397 if (retval
!= 0 && errno
!= EEXIST
) {
1410 gchar
*dir
= g_path_get_dirname (filename
);
1414 if (!dir
|| !dir
[0]) {
1419 if (stat (dir
, &sbuf
) == 0 && S_ISDIR (sbuf
.st_mode
)) {
1429 p
= strchr (p
, '/');
1432 retval
= mkdir (dir
, 0777);
1433 if (retval
!= 0 && errno
!= EEXIST
) {
1448 private_file_needs_copying (const char *src
, struct stat
*sbuf_src
, char *dest
)
1450 struct stat sbuf_dest
;
1452 if (stat (src
, sbuf_src
) == -1 || stat (dest
, &sbuf_dest
) == -1)
1455 if (sbuf_src
->st_size
== sbuf_dest
.st_size
&&
1456 sbuf_src
->st_mtime
== sbuf_dest
.st_mtime
)
1463 shadow_copy_create_ini (const char *shadow
, const char *filename
)
1473 dir_name
= g_path_get_dirname (shadow
);
1474 ini_file
= g_build_filename (dir_name
, "__AssemblyInfo__.ini", NULL
);
1476 if (g_file_test (ini_file
, G_FILE_TEST_IS_REGULAR
)) {
1481 u16_ini
= g_utf8_to_utf16 (ini_file
, strlen (ini_file
), NULL
, NULL
, NULL
);
1486 handle
= CreateFile (u16_ini
, GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1487 NULL
, CREATE_NEW
, FileAttributes_Normal
, NULL
);
1489 if (handle
== INVALID_HANDLE_VALUE
) {
1493 full_path
= mono_path_resolve_symlinks (filename
);
1494 result
= WriteFile (handle
, full_path
, strlen (full_path
), &n
, NULL
);
1496 CloseHandle (handle
);
1501 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1504 const char *version
;
1505 MonoAppDomainSetup
*setup
;
1508 gchar
**directories
;
1509 gchar
*shadow_status_string
;
1511 gboolean shadow_enabled
;
1512 gboolean found
= FALSE
;
1517 setup
= domain
->setup
;
1518 if (setup
== NULL
|| setup
->shadow_copy_files
== NULL
)
1521 version
= mono_get_runtime_info ()->framework_version
;
1523 /* For 1.x, not NULL is enough. In 2.0 it has to be "true" */
1524 if (*version
<= '1') {
1525 shadow_enabled
= TRUE
;
1527 shadow_status_string
= mono_string_to_utf8_checked (setup
->shadow_copy_files
, &error
);
1528 if (!mono_error_ok (&error
)) {
1529 mono_error_cleanup (&error
);
1532 shadow_enabled
= !g_ascii_strncasecmp (shadow_status_string
, "true", 4);
1533 g_free (shadow_status_string
);
1536 if (!shadow_enabled
)
1539 if (setup
->shadow_copy_directories
== NULL
)
1542 /* Is dir_name a shadow_copy destination already? */
1543 base_dir
= get_shadow_assembly_location_base (domain
, &error
);
1544 if (!mono_error_ok (&error
)) {
1545 mono_error_cleanup (&error
);
1549 if (strstr (dir_name
, base_dir
)) {
1555 all_dirs
= mono_string_to_utf8_checked (setup
->shadow_copy_directories
, &error
);
1556 if (!mono_error_ok (&error
)) {
1557 mono_error_cleanup (&error
);
1561 directories
= g_strsplit (all_dirs
, G_SEARCHPATH_SEPARATOR_S
, 1000);
1562 dir_ptr
= directories
;
1564 if (**dir_ptr
!= '\0' && !strcmp (*dir_ptr
, dir_name
)) {
1570 g_strfreev (directories
);
1576 This function raises exceptions so it can cause as sorts of nasty stuff if called
1577 while holding a lock.
1578 FIXME bubble up the error instead of raising it here
1581 mono_make_shadow_copy (const char *filename
)
1584 gchar
*sibling_source
, *sibling_target
;
1585 gint sibling_source_len
, sibling_target_len
;
1586 guint16
*orig
, *dest
;
1588 gboolean copy_result
;
1590 struct stat src_sbuf
;
1591 struct utimbuf utbuf
;
1592 char *dir_name
= g_path_get_dirname (filename
);
1593 MonoDomain
*domain
= mono_domain_get ();
1596 set_domain_search_path (domain
);
1598 if (!mono_is_shadow_copy_enabled (domain
, dir_name
)) {
1600 return (char *) filename
;
1603 /* Is dir_name a shadow_copy destination already? */
1604 shadow_dir
= get_shadow_assembly_location_base (domain
, &error
);
1605 if (!mono_error_ok (&error
)) {
1606 mono_error_cleanup (&error
);
1608 exc
= mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in shadow directory name).");
1609 mono_raise_exception (exc
);
1612 if (strstr (dir_name
, shadow_dir
)) {
1613 g_free (shadow_dir
);
1615 return (char *) filename
;
1617 g_free (shadow_dir
);
1620 shadow
= get_shadow_assembly_location (filename
, &error
);
1621 if (!mono_error_ok (&error
)) {
1622 mono_error_cleanup (&error
);
1623 exc
= mono_get_exception_execution_engine ("Failed to create shadow copy (invalid characters in file name).");
1624 mono_raise_exception (exc
);
1627 if (ensure_directory_exists (shadow
) == FALSE
) {
1629 exc
= mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1630 mono_raise_exception (exc
);
1633 if (!private_file_needs_copying (filename
, &src_sbuf
, shadow
))
1634 return (char*) shadow
;
1636 orig
= g_utf8_to_utf16 (filename
, strlen (filename
), NULL
, NULL
, NULL
);
1637 dest
= g_utf8_to_utf16 (shadow
, strlen (shadow
), NULL
, NULL
, NULL
);
1639 copy_result
= CopyFile (orig
, dest
, FALSE
);
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
= SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1649 if (copy_result
== FALSE
) {
1651 exc
= mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1652 mono_raise_exception (exc
);
1655 /* attempt to copy .mdb, .config if they exist */
1656 sibling_source
= g_strconcat (filename
, ".config", NULL
);
1657 sibling_source_len
= strlen (sibling_source
);
1658 sibling_target
= g_strconcat (shadow
, ".config", NULL
);
1659 sibling_target_len
= strlen (sibling_target
);
1661 copy_result
= shadow_copy_sibling (sibling_source
, sibling_source_len
, ".mdb", sibling_target
, sibling_target_len
, 7);
1662 if (copy_result
== TRUE
)
1663 copy_result
= shadow_copy_sibling (sibling_source
, sibling_source_len
, ".config", sibling_target
, sibling_target_len
, 7);
1665 g_free (sibling_source
);
1666 g_free (sibling_target
);
1668 if (copy_result
== FALSE
) {
1670 exc
= mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1671 mono_raise_exception (exc
);
1674 /* Create a .ini file containing the original assembly location */
1675 if (!shadow_copy_create_ini (shadow
, filename
)) {
1677 exc
= mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1678 mono_raise_exception (exc
);
1681 utbuf
.actime
= src_sbuf
.st_atime
;
1682 utbuf
.modtime
= src_sbuf
.st_mtime
;
1683 utime (shadow
, &utbuf
);
1687 #endif /* DISABLE_SHADOW_COPY */
1690 mono_domain_from_appdomain (MonoAppDomain
*appdomain
)
1692 if (appdomain
== NULL
)
1695 return appdomain
->data
;
1699 try_load_from (MonoAssembly
**assembly
, const gchar
*path1
, const gchar
*path2
,
1700 const gchar
*path3
, const gchar
*path4
,
1701 gboolean refonly
, gboolean is_private
)
1704 gboolean found
= FALSE
;
1707 fullpath
= g_build_filename (path1
, path2
, path3
, path4
, NULL
);
1709 if (IS_PORTABILITY_SET
) {
1710 gchar
*new_fullpath
= mono_portability_find_file (fullpath
, TRUE
);
1713 fullpath
= new_fullpath
;
1717 found
= g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
);
1720 *assembly
= mono_assembly_open_full (fullpath
, NULL
, refonly
);
1723 return (*assembly
!= NULL
);
1726 static MonoAssembly
*
1727 real_load (gchar
**search_path
, const gchar
*culture
, const gchar
*name
, gboolean refonly
)
1729 MonoAssembly
*result
= NULL
;
1732 const gchar
*local_culture
;
1734 gboolean is_private
= FALSE
;
1736 if (!culture
|| *culture
== '\0') {
1739 local_culture
= culture
;
1742 filename
= g_strconcat (name
, ".dll", NULL
);
1743 len
= strlen (filename
);
1745 for (path
= search_path
; *path
; path
++) {
1746 if (**path
== '\0') {
1748 continue; /* Ignore empty ApplicationBase */
1751 /* See test cases in bug #58992 and bug #57710 */
1752 /* 1st try: [culture]/[name].dll (culture may be empty) */
1753 strcpy (filename
+ len
- 4, ".dll");
1754 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
, is_private
))
1757 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1758 strcpy (filename
+ len
- 4, ".exe");
1759 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
, is_private
))
1762 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1763 strcpy (filename
+ len
- 4, ".dll");
1764 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
, is_private
))
1767 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1768 strcpy (filename
+ len
- 4, ".exe");
1769 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
, is_private
))
1778 * Try loading the assembly from ApplicationBase and PrivateBinPath
1779 * and then from assemblies_path if any.
1780 * LOCKING: This is called from the assembly loading code, which means the caller
1781 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1783 static MonoAssembly
*
1784 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
1785 gchar
**assemblies_path
,
1788 MonoDomain
*domain
= mono_domain_get ();
1789 MonoAssembly
*result
= NULL
;
1790 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
1792 set_domain_search_path (domain
);
1794 if (domain
->search_path
&& domain
->search_path
[0] != NULL
) {
1795 result
= real_load (domain
->search_path
, aname
->culture
, aname
->name
, refonly
);
1798 if (result
== NULL
&& assemblies_path
&& assemblies_path
[0] != NULL
) {
1799 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, refonly
);
1806 * Check whenever a given assembly was already loaded in the current appdomain.
1808 static MonoAssembly
*
1809 mono_domain_assembly_search (MonoAssemblyName
*aname
,
1812 MonoDomain
*domain
= mono_domain_get ();
1815 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
1817 mono_domain_assemblies_lock (domain
);
1818 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1820 /* Dynamic assemblies can't match here in MS.NET */
1821 if (ass
->dynamic
|| refonly
!= ass
->ref_only
|| !mono_assembly_names_equal (aname
, &ass
->aname
))
1824 mono_domain_assemblies_unlock (domain
);
1827 mono_domain_assemblies_unlock (domain
);
1832 MonoReflectionAssembly
*
1833 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString
*fname
, MonoBoolean refOnly
)
1835 MonoDomain
*domain
= mono_domain_get ();
1836 char *name
, *filename
;
1837 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
1840 MONO_ARCH_SAVE_REGS
;
1842 if (fname
== NULL
) {
1843 MonoException
*exc
= mono_get_exception_argument_null ("assemblyFile");
1844 mono_raise_exception (exc
);
1847 name
= filename
= mono_string_to_utf8 (fname
);
1849 ass
= mono_assembly_open_full (filename
, &status
, refOnly
);
1854 if (status
== MONO_IMAGE_IMAGE_INVALID
)
1855 exc
= mono_get_exception_bad_image_format2 (NULL
, fname
);
1857 exc
= mono_get_exception_file_not_found2 (NULL
, fname
);
1859 mono_raise_exception (exc
);
1864 return mono_assembly_get_object (domain
, ass
);
1867 MonoReflectionAssembly
*
1868 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain
*ad
,
1869 MonoArray
*raw_assembly
,
1870 MonoArray
*raw_symbol_store
, MonoObject
*evidence
,
1871 MonoBoolean refonly
)
1874 MonoReflectionAssembly
*refass
= NULL
;
1875 MonoDomain
*domain
= ad
->data
;
1876 MonoImageOpenStatus status
;
1877 guint32 raw_assembly_len
= mono_array_length (raw_assembly
);
1878 MonoImage
*image
= mono_image_open_from_data_full (mono_array_addr (raw_assembly
, gchar
, 0), raw_assembly_len
, TRUE
, NULL
, refonly
);
1881 mono_raise_exception (mono_get_exception_bad_image_format (""));
1885 if (raw_symbol_store
!= NULL
)
1886 mono_debug_open_image_from_memory (image
, mono_array_addr (raw_symbol_store
, guint8
, 0), mono_array_length (raw_symbol_store
));
1888 ass
= mono_assembly_load_from_full (image
, "", &status
, refonly
);
1892 mono_image_close (image
);
1893 mono_raise_exception (mono_get_exception_bad_image_format (""));
1897 refass
= mono_assembly_get_object (domain
, ass
);
1898 MONO_OBJECT_SETREF (refass
, evidence
, evidence
);
1902 MonoReflectionAssembly
*
1903 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain
*ad
, MonoString
*assRef
, MonoObject
*evidence
, MonoBoolean refOnly
)
1905 MonoDomain
*domain
= ad
->data
;
1906 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
1908 MonoAssemblyName aname
;
1909 MonoReflectionAssembly
*refass
= NULL
;
1913 MONO_ARCH_SAVE_REGS
;
1915 g_assert (assRef
!= NULL
);
1917 name
= mono_string_to_utf8 (assRef
);
1918 parsed
= mono_assembly_name_parse (name
, &aname
);
1922 /* This is a parse error... */
1926 ass
= mono_assembly_load_full_nosearch (&aname
, NULL
, &status
, refOnly
);
1927 mono_assembly_name_free (&aname
);
1930 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1932 refass
= mono_try_assembly_resolve (domain
, assRef
, refOnly
);
1941 refass
= mono_assembly_get_object (domain
, ass
);
1943 MONO_OBJECT_SETREF (refass
, evidence
, evidence
);
1948 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id
)
1950 MonoDomain
* domain
= mono_domain_get_by_id (domain_id
);
1952 MONO_ARCH_SAVE_REGS
;
1954 if (NULL
== domain
) {
1955 MonoException
*exc
= mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
1956 mono_raise_exception (exc
);
1959 if (domain
== mono_get_root_domain ()) {
1960 mono_raise_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
1965 * Unloading seems to cause problems when running NUnit/NAnt, hence
1968 if (g_getenv ("MONO_NO_UNLOAD"))
1971 mono_domain_unload (domain
);
1975 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id
)
1977 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
1982 return mono_domain_is_unloading (domain
);
1986 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain
*ad
,
1987 MonoReflectionAssembly
*refass
, MonoArray
*args
)
1992 MONO_ARCH_SAVE_REGS
;
1995 image
= refass
->assembly
->image
;
1998 method
= mono_get_method (image
, mono_image_get_entry_point (image
), NULL
);
2001 g_error ("No entry point method found in %s", image
->name
);
2004 args
= (MonoArray
*) mono_array_new (ad
->data
, mono_defaults
.string_class
, 0);
2006 return mono_runtime_exec_main (method
, (MonoArray
*)args
, NULL
);
2010 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain
* ad
)
2012 MONO_ARCH_SAVE_REGS
;
2014 return ad
->data
->domain_id
;
2018 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain
*ad
)
2020 MonoDomain
*old_domain
= mono_domain_get();
2022 MONO_ARCH_SAVE_REGS
;
2024 if (!mono_domain_set (ad
->data
, FALSE
))
2025 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2027 return old_domain
->domain
;
2031 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid
)
2033 MonoDomain
*current_domain
= mono_domain_get ();
2034 MonoDomain
*domain
= mono_domain_get_by_id (domainid
);
2036 MONO_ARCH_SAVE_REGS
;
2038 if (!domain
|| !mono_domain_set (domain
, FALSE
))
2039 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2041 return current_domain
->domain
;
2045 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain
*ad
)
2047 MONO_ARCH_SAVE_REGS
;
2049 mono_thread_push_appdomain_ref (ad
->data
);
2053 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id
)
2055 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2057 MONO_ARCH_SAVE_REGS
;
2061 * Raise an exception to prevent the managed code from executing a pop
2064 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
2066 mono_thread_push_appdomain_ref (domain
);
2070 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2072 MONO_ARCH_SAVE_REGS
;
2074 mono_thread_pop_appdomain_ref ();
2078 ves_icall_System_AppDomain_InternalGetContext ()
2080 MONO_ARCH_SAVE_REGS
;
2082 return mono_context_get ();
2086 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2088 MONO_ARCH_SAVE_REGS
;
2090 return mono_domain_get ()->default_context
;
2094 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext
*mc
)
2096 MonoAppContext
*old_context
= mono_context_get ();
2098 MONO_ARCH_SAVE_REGS
;
2100 mono_context_set (mc
);
2106 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString
* newguid
)
2108 MonoDomain
* mono_root_domain
= mono_get_root_domain ();
2109 mono_domain_lock (mono_root_domain
);
2110 if (process_guid_set
) {
2111 mono_domain_unlock (mono_root_domain
);
2112 return mono_string_new_utf16 (mono_domain_get (), process_guid
, sizeof(process_guid
)/2);
2114 memcpy (process_guid
, mono_string_chars(newguid
), sizeof(process_guid
));
2115 process_guid_set
= TRUE
;
2116 mono_domain_unlock (mono_root_domain
);
2121 mono_domain_is_unloading (MonoDomain
*domain
)
2123 if (domain
->state
== MONO_APPDOMAIN_UNLOADING
|| domain
->state
== MONO_APPDOMAIN_UNLOADED
)
2130 clear_cached_vtable (gpointer key
, gpointer value
, gpointer user_data
)
2132 MonoClass
*klass
= (MonoClass
*)key
;
2133 MonoVTable
*vtable
= value
;
2134 MonoDomain
*domain
= (MonoDomain
*)user_data
;
2135 MonoClassRuntimeInfo
*runtime_info
;
2137 runtime_info
= klass
->runtime_info
;
2138 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
)
2139 runtime_info
->domain_vtables
[domain
->domain_id
] = NULL
;
2140 if (vtable
->data
&& klass
->has_static_refs
)
2141 mono_gc_free_fixed (vtable
->data
);
2144 static G_GNUC_UNUSED
void
2145 zero_static_data (gpointer key
, gpointer value
, gpointer user_data
)
2147 MonoClass
*klass
= (MonoClass
*)key
;
2148 MonoVTable
*vtable
= value
;
2150 if (vtable
->data
&& klass
->has_static_refs
)
2151 memset (vtable
->data
, 0, mono_class_data_size (klass
));
2154 typedef struct unload_data
{
2156 char *failure_reason
;
2161 deregister_reflection_info_roots_nspace_table (gpointer key
, gpointer value
, gpointer image
)
2163 guint32 index
= GPOINTER_TO_UINT (value
);
2164 MonoClass
*class = mono_class_get (image
, MONO_TOKEN_TYPE_DEF
| index
);
2168 if (class->reflection_info
)
2169 mono_gc_deregister_root ((char*) &class->reflection_info
);
2173 deregister_reflection_info_roots_name_space (gpointer key
, gpointer value
, gpointer user_data
)
2175 g_hash_table_foreach (value
, deregister_reflection_info_roots_nspace_table
, user_data
);
2179 deregister_reflection_info_roots_from_list (MonoImage
*image
)
2181 GSList
*list
= image
->reflection_info_unregister_classes
;
2184 MonoClass
*class = list
->data
;
2186 g_assert (class->reflection_info
);
2187 mono_gc_deregister_root ((char*) &class->reflection_info
);
2192 g_slist_free (image
->reflection_info_unregister_classes
);
2193 image
->reflection_info_unregister_classes
= NULL
;
2197 deregister_reflection_info_roots (MonoDomain
*domain
)
2201 mono_loader_lock ();
2202 mono_domain_assemblies_lock (domain
);
2203 for (list
= domain
->domain_assemblies
; list
; list
= list
->next
) {
2204 MonoAssembly
*assembly
= list
->data
;
2205 MonoImage
*image
= assembly
->image
;
2207 /*No need to take the image lock here since dynamic images are appdomain bound and at this point the mutator is gone.*/
2208 if (image
->dynamic
&& image
->name_cache
)
2209 g_hash_table_foreach (image
->name_cache
, deregister_reflection_info_roots_name_space
, image
);
2210 deregister_reflection_info_roots_from_list (image
);
2211 for (i
= 0; i
< image
->module_count
; ++i
) {
2212 MonoImage
*module
= image
->modules
[i
];
2214 if (module
->dynamic
&& module
->name_cache
) {
2215 g_hash_table_foreach (module
->name_cache
,
2216 deregister_reflection_info_roots_name_space
, module
);
2218 deregister_reflection_info_roots_from_list (module
);
2222 mono_domain_assemblies_unlock (domain
);
2223 mono_loader_unlock ();
2227 static guint32 WINAPI
2228 unload_thread_main (void *arg
)
2230 unload_data
*data
= (unload_data
*)arg
;
2231 MonoDomain
*domain
= data
->domain
;
2234 /* Have to attach to the runtime so shutdown can wait for this thread */
2235 thread
= mono_thread_attach (mono_get_root_domain ());
2238 * FIXME: Abort our parent thread last, so we can return a failure
2239 * indication if aborting times out.
2241 if (!mono_threads_abort_appdomain_threads (domain
, -1)) {
2242 data
->failure_reason
= g_strdup_printf ("Aborting of threads in domain %s timed out.", domain
->friendly_name
);
2246 if (!mono_thread_pool_remove_domain_jobs (domain
, -1)) {
2247 data
->failure_reason
= g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain
->friendly_name
);
2251 /* Finalize all finalizable objects in the doomed appdomain */
2252 if (!mono_domain_finalize (domain
, -1)) {
2253 data
->failure_reason
= g_strdup_printf ("Finalization of domain %s timed out.", domain
->friendly_name
);
2257 /* Clear references to our vtables in class->runtime_info.
2258 * We also hold the loader lock because we're going to change
2259 * class->runtime_info.
2262 mono_loader_lock ();
2263 mono_domain_lock (domain
);
2266 * We need to make sure that we don't have any remsets
2267 * pointing into static data of the to-be-freed domain because
2268 * at the next collections they would be invalid. So what we
2269 * do is we first zero all static data and then do a minor
2270 * collection. Because all references in the static data will
2271 * now be null we won't do any unnecessary copies and after
2272 * the collection there won't be any more remsets.
2274 g_hash_table_foreach (domain
->class_vtable_hash
, zero_static_data
, domain
);
2275 mono_gc_collect (0);
2277 g_hash_table_foreach (domain
->class_vtable_hash
, clear_cached_vtable
, domain
);
2279 deregister_reflection_info_roots (domain
);
2281 mono_domain_unlock (domain
);
2282 mono_loader_unlock ();
2284 mono_threads_clear_cached_culture (domain
);
2286 domain
->state
= MONO_APPDOMAIN_UNLOADED
;
2288 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2290 /* remove from the handle table the items related to this domain */
2291 mono_gchandle_free_domain (domain
);
2293 mono_domain_free (domain
, FALSE
);
2295 mono_gc_collect (mono_gc_max_generation ());
2297 mono_thread_detach (thread
);
2303 * mono_domain_unload:
2304 * @domain: The domain to unload
2306 * Unloads an appdomain. Follows the process outlined in the comment
2307 * for mono_domain_try_unload.
2310 mono_domain_unload (MonoDomain
*domain
)
2312 MonoObject
*exc
= NULL
;
2313 mono_domain_try_unload (domain
, &exc
);
2315 mono_raise_exception ((MonoException
*)exc
);
2319 * mono_domain_unload:
2320 * @domain: The domain to unload
2321 * @exc: Exception information
2323 * Unloads an appdomain. Follows the process outlined in:
2324 * http://blogs.gotdotnet.com/cbrumme
2326 * If doing things the 'right' way is too hard or complex, we do it the
2327 * 'simple' way, which means do everything needed to avoid crashes and
2328 * memory leaks, but not much else.
2330 * It is required to pass a valid reference to the exc argument, upon return
2331 * from this function *exc will be set to the exception thrown, if any.
2333 * If this method is not called from an icall (embedded scenario for instance),
2334 * it must not be called with any managed frames on the stack, since the unload
2335 * process could end up trying to abort the current thread.
2338 mono_domain_try_unload (MonoDomain
*domain
, MonoObject
**exc
)
2340 HANDLE thread_handle
;
2343 MonoAppDomainState prev_state
;
2345 unload_data thread_data
;
2346 MonoDomain
*caller_domain
= mono_domain_get ();
2348 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2350 /* Atomically change our state to UNLOADING */
2351 prev_state
= InterlockedCompareExchange ((gint32
*)&domain
->state
,
2352 MONO_APPDOMAIN_UNLOADING_START
,
2353 MONO_APPDOMAIN_CREATED
);
2354 if (prev_state
!= MONO_APPDOMAIN_CREATED
) {
2355 switch (prev_state
) {
2356 case MONO_APPDOMAIN_UNLOADING_START
:
2357 case MONO_APPDOMAIN_UNLOADING
:
2358 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2360 case MONO_APPDOMAIN_UNLOADED
:
2361 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2364 g_warning ("Incalid appdomain state %d", prev_state
);
2365 g_assert_not_reached ();
2369 mono_debugger_event_unload_appdomain (domain
);
2371 mono_domain_set (domain
, FALSE
);
2372 /* Notify OnDomainUnload listeners */
2373 method
= mono_class_get_method_from_name (domain
->domain
->mbr
.obj
.vtable
->klass
, "DoDomainUnload", -1);
2376 mono_runtime_invoke (method
, domain
->domain
, NULL
, exc
);
2378 /* Roll back the state change */
2379 domain
->state
= MONO_APPDOMAIN_CREATED
;
2380 mono_domain_set (caller_domain
, FALSE
);
2383 mono_domain_set (caller_domain
, FALSE
);
2385 thread_data
.domain
= domain
;
2386 thread_data
.failure_reason
= NULL
;
2388 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2389 domain
->state
= MONO_APPDOMAIN_UNLOADING
;
2391 * First we create a separate thread for unloading, since
2392 * we might have to abort some threads, including the current one.
2395 * If we create a non-suspended thread, the runtime will hang.
2397 * http://bugzilla.ximian.com/show_bug.cgi?id=27663
2400 thread_handle
= mono_create_thread (NULL
, 0, unload_thread_main
, &thread_data
, 0, &tid
);
2402 thread_handle
= mono_create_thread (NULL
, 0, (LPTHREAD_START_ROUTINE
)unload_thread_main
, &thread_data
, CREATE_SUSPENDED
, &tid
);
2403 if (thread_handle
== NULL
) {
2406 ResumeThread (thread_handle
);
2409 /* Wait for the thread */
2410 while ((res
= WaitForSingleObjectEx (thread_handle
, INFINITE
, TRUE
) == WAIT_IO_COMPLETION
)) {
2411 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain
) && (mono_thread_interruption_requested ())) {
2412 /* The unload thread tries to abort us */
2413 /* The icall wrapper will execute the abort */
2414 CloseHandle (thread_handle
);
2418 CloseHandle (thread_handle
);
2420 if (thread_data
.failure_reason
) {
2421 /* Roll back the state change */
2422 domain
->state
= MONO_APPDOMAIN_CREATED
;
2424 g_warning ("%s", thread_data
.failure_reason
);
2426 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain (thread_data
.failure_reason
);
2428 g_free (thread_data
.failure_reason
);
2429 thread_data
.failure_reason
= NULL
;