2 * appdomain.c: AppDomain functions
5 * Dietmar Maurer (dietmar@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2012 Xamarin Inc
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #undef ASSEMBLY_LOAD_DEBUG
20 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/appdomain-icalls.h>
39 #include <mono/metadata/domain-internals.h>
40 #include "mono/metadata/metadata-internals.h"
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/exception.h>
43 #include <mono/metadata/exception-internals.h>
44 #include <mono/metadata/threads.h>
45 #include <mono/metadata/threadpool.h>
46 #include <mono/metadata/socket-io.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/mono-gc.h>
50 #include <mono/metadata/marshal.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/mono-debug-debugger.h>
54 #include <mono/metadata/attach.h>
55 #include <mono/metadata/file-io.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/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/io-layer/io-layer.h>
79 * This is the version number of the corlib-runtime interface. When
80 * making changes to this interface (by changing the layout
81 * of classes the runtime knows about, changing icall signature or
82 * semantics etc), increment this variable. Also increment the
83 * pair of this variable in mscorlib in:
84 * mcs/class/corlib/System/Environment.cs
86 * Changes which are already detected at runtime, like the addition
87 * of icalls, do not require an increment.
89 #define MONO_CORLIB_VERSION 165
94 int assemblybinding_count
;
99 static gunichar2 process_guid
[36];
100 static gboolean process_guid_set
= FALSE
;
102 static gboolean no_exec
= FALSE
;
104 static MonoAssembly
*
105 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
106 gchar
**assemblies_path
,
109 static MonoAssembly
*
110 mono_domain_assembly_search (MonoAssemblyName
*aname
,
114 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
);
117 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*hash
);
119 static MonoAppDomain
*
120 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetup
*setup
, MonoError
*error
);
123 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
);
125 static MonoLoadFunc load_function
= NULL
;
127 /* Lazy class loading functions */
128 static GENERATE_GET_CLASS_WITH_CACHE (assembly
, System
.Reflection
, Assembly
);
130 static GENERATE_GET_CLASS_WITH_CACHE (appdomain
, System
, AppDomain
);
133 mono_install_runtime_load (MonoLoadFunc func
)
135 load_function
= func
;
139 mono_runtime_load (const char *filename
, const char *runtime_version
)
141 g_assert (load_function
);
142 return load_function (filename
, runtime_version
);
146 * mono_runtime_set_no_exec:
148 * Instructs the runtime to operate in static mode, i.e. avoid/do not
149 * allow managed code execution. This is useful for running the AOT
150 * compiler on platforms which allow full-aot execution only. This
151 * should be called before mono_runtime_init ().
154 mono_runtime_set_no_exec (gboolean val
)
160 * mono_runtime_get_no_exec:
162 * If true, then the runtime will not allow managed code execution.
165 mono_runtime_get_no_exec (void)
171 create_domain_objects (MonoDomain
*domain
)
174 MonoDomain
*old_domain
= mono_domain_get ();
176 MonoVTable
*string_vt
;
177 MonoClassField
*string_empty_fld
;
179 if (domain
!= old_domain
) {
180 mono_thread_push_appdomain_ref (domain
);
181 mono_domain_set_internal_with_options (domain
, FALSE
);
185 * Initialize String.Empty. This enables the removal of
186 * the static cctor of the String class.
188 string_vt
= mono_class_vtable (domain
, mono_defaults
.string_class
);
189 string_empty_fld
= mono_class_get_field_from_name (mono_defaults
.string_class
, "Empty");
190 g_assert (string_empty_fld
);
191 MonoString
*empty_str
= mono_string_intern_checked (mono_string_new (domain
, ""), &error
);
192 mono_error_assert_ok (&error
);
193 mono_field_static_set_value (string_vt
, string_empty_fld
, empty_str
);
194 domain
->empty_string
= empty_str
;
197 * Create an instance early since we can't do it when there is no memory.
199 arg
= mono_string_new (domain
, "Out of memory");
200 domain
->out_of_memory_ex
= mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "OutOfMemoryException", arg
, NULL
, &error
);
201 mono_error_assert_ok (&error
);
204 * These two are needed because the signal handlers might be executing on
205 * an alternate stack, and Boehm GC can't handle that.
207 arg
= mono_string_new (domain
, "A null value was found where an object instance was required");
208 domain
->null_reference_ex
= mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "NullReferenceException", arg
, NULL
, &error
);
209 mono_error_assert_ok (&error
);
210 arg
= mono_string_new (domain
, "The requested operation caused a stack overflow.");
211 domain
->stack_overflow_ex
= mono_exception_from_name_two_strings_checked (mono_defaults
.corlib
, "System", "StackOverflowException", arg
, NULL
, &error
);
212 mono_error_assert_ok (&error
);
214 /*The ephemeron tombstone i*/
215 domain
->ephemeron_tombstone
= mono_object_new_checked (domain
, mono_defaults
.object_class
, &error
);
216 mono_error_assert_ok (&error
);
218 if (domain
!= old_domain
) {
219 mono_thread_pop_appdomain_ref ();
220 mono_domain_set_internal_with_options (old_domain
, FALSE
);
224 * This class is used during exception handling, so initialize it here, to prevent
225 * stack overflows while handling stack overflows.
227 mono_class_init (mono_array_class_get (mono_defaults
.int_class
, 1));
232 * @domain: domain returned by mono_init ()
234 * Initialize the core AppDomain: this function will run also some
235 * IL initialization code, so it needs the execution engine to be fully
238 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
239 * we know the entry_assembly.
243 mono_runtime_init (MonoDomain
*domain
, MonoThreadStartCB start_cb
, MonoThreadAttachCB attach_cb
)
246 mono_runtime_init_checked (domain
, start_cb
, attach_cb
, &error
);
247 mono_error_cleanup (&error
);
251 mono_runtime_init_checked (MonoDomain
*domain
, MonoThreadStartCB start_cb
, MonoThreadAttachCB attach_cb
, MonoError
*error
)
253 MonoAppDomainSetup
*setup
;
257 mono_error_init (error
);
259 mono_portability_helpers_init ();
261 mono_gc_base_init ();
262 mono_monitor_init ();
263 mono_marshal_init ();
265 mono_install_assembly_preload_hook (mono_domain_assembly_preload
, GUINT_TO_POINTER (FALSE
));
266 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload
, GUINT_TO_POINTER (TRUE
));
267 mono_install_assembly_search_hook (mono_domain_assembly_search
, GUINT_TO_POINTER (FALSE
));
268 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search
, GUINT_TO_POINTER (TRUE
));
269 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc
)mono_domain_assembly_postload_search
, GUINT_TO_POINTER (FALSE
));
270 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc
)mono_domain_assembly_postload_search
, GUINT_TO_POINTER (TRUE
));
271 mono_install_assembly_load_hook (mono_domain_fire_assembly_load
, NULL
);
273 mono_thread_init (start_cb
, attach_cb
);
275 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
276 setup
= (MonoAppDomainSetup
*) mono_object_new_pinned (domain
, klass
, error
);
277 return_if_nok (error
);
279 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomain");
281 ad
= (MonoAppDomain
*) mono_object_new_pinned (domain
, klass
, error
);
282 return_if_nok (error
);
286 domain
->setup
= setup
;
288 mono_thread_attach (domain
);
290 mono_type_initialization_init ();
292 if (!mono_runtime_get_no_exec ())
293 create_domain_objects (domain
);
295 /* GC init has to happen after thread init */
298 /* contexts use GC handles, so they must be initialized after the GC */
299 mono_context_init_checked (domain
, error
);
300 return_if_nok (error
);
301 mono_context_set (domain
->default_context
);
303 #ifndef DISABLE_SOCKETS
304 mono_network_init ();
307 mono_console_init ();
310 mono_locks_tracer_init ();
312 /* mscorlib is loaded before we install the load hook */
313 mono_domain_fire_assembly_load (mono_defaults
.corlib
->assembly
, NULL
);
319 mono_get_corlib_version (void)
323 MonoClassField
*field
;
326 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "Environment");
327 mono_class_init (klass
);
328 field
= mono_class_get_field_from_name (klass
, "mono_corlib_version");
331 if (! (field
->type
->attrs
& FIELD_ATTRIBUTE_STATIC
))
333 value
= mono_field_get_value_object_checked (mono_domain_get (), field
, NULL
, &error
);
334 mono_error_assert_ok (&error
);
335 return *(gint32
*)((gchar
*)value
+ sizeof (MonoObject
));
339 * mono_check_corlib_version
341 * Checks that the corlib that is loaded matches the version of this runtime.
343 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
344 * allocated string with the error otherwise.
347 mono_check_corlib_version (void)
349 int version
= mono_get_corlib_version ();
350 if (version
!= MONO_CORLIB_VERSION
)
351 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION
, version
);
353 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
354 guint32 native_offset
= (guint32
) MONO_STRUCT_OFFSET (MonoInternalThread
, last
);
355 guint32 managed_offset
= mono_field_get_offset (mono_class_get_field_from_name (mono_defaults
.internal_thread_class
, "last"));
356 if (native_offset
!= managed_offset
)
357 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset
, managed_offset
);
364 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
366 * Initializes the @domain's default System.Runtime.Remoting's Context.
369 mono_context_init (MonoDomain
*domain
)
372 mono_context_init_checked (domain
, &error
);
373 mono_error_cleanup (&error
);
377 mono_context_init_checked (MonoDomain
*domain
, MonoError
*error
)
380 MonoAppContext
*context
;
382 mono_error_init (error
);
384 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System.Runtime.Remoting.Contexts", "Context");
385 context
= (MonoAppContext
*) mono_object_new_pinned (domain
, klass
, error
);
386 return_if_nok (error
);
388 context
->domain_id
= domain
->domain_id
;
389 context
->context_id
= 0;
390 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context
);
391 domain
->default_context
= context
;
395 * mono_runtime_cleanup:
400 * This must not be called while there are still running threads executing
404 mono_runtime_cleanup (MonoDomain
*domain
)
406 mono_attach_cleanup ();
408 /* This ends up calling any pending pending (for at most 2 seconds) */
411 mono_thread_cleanup ();
413 #ifndef DISABLE_SOCKETS
414 mono_network_cleanup ();
416 mono_marshal_cleanup ();
418 mono_type_initialization_cleanup ();
420 mono_monitor_cleanup ();
423 static MonoDomainFunc quit_function
= NULL
;
426 mono_install_runtime_cleanup (MonoDomainFunc func
)
428 quit_function
= func
;
434 if (quit_function
!= NULL
)
435 quit_function (mono_get_root_domain (), NULL
);
439 * mono_domain_create_appdomain:
440 * @friendly_name: The friendly name of the appdomain to create
441 * @configuration_file: The configuration file to initialize the appdomain with
443 * Returns a MonoDomain initialized with the appdomain
446 mono_domain_create_appdomain (char *friendly_name
, char *configuration_file
)
450 MonoAppDomainSetup
*setup
;
453 klass
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
454 setup
= (MonoAppDomainSetup
*) mono_object_new_checked (mono_domain_get (), klass
, &error
);
457 setup
->configuration_file
= configuration_file
!= NULL
? mono_string_new (mono_domain_get (), configuration_file
) : NULL
;
459 ad
= mono_domain_create_appdomain_internal (friendly_name
, setup
, &error
);
463 return mono_domain_from_appdomain (ad
);
465 mono_error_cleanup (&error
);
470 * mono_domain_set_config:
471 * @domain: MonoDomain initialized with the appdomain we want to change
472 * @base_dir: new base directory for the appdomain
473 * @config_file_name: path to the new configuration for the app domain
475 * Used to set the system configuration for an appdomain
477 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
478 * Error Initializing the configuration system. ---> System.ArgumentException:
479 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
482 mono_domain_set_config (MonoDomain
*domain
, const char *base_dir
, const char *config_file_name
)
484 MONO_OBJECT_SETREF (domain
->setup
, application_base
, mono_string_new (domain
, base_dir
));
485 MONO_OBJECT_SETREF (domain
->setup
, configuration_file
, mono_string_new (domain
, config_file_name
));
488 static MonoAppDomainSetup
*
489 copy_app_domain_setup (MonoDomain
*domain
, MonoAppDomainSetup
*setup
, MonoError
*error
)
491 MonoDomain
*caller_domain
;
492 MonoClass
*ads_class
;
493 MonoAppDomainSetup
*copy
;
495 mono_error_init (error
);
497 caller_domain
= mono_domain_get ();
498 ads_class
= mono_class_load_from_name (mono_defaults
.corlib
, "System", "AppDomainSetup");
500 copy
= (MonoAppDomainSetup
*)mono_object_new_checked (domain
, ads_class
, error
);
501 return_val_if_nok (error
, NULL
);
503 mono_domain_set_internal (domain
);
505 #define XCOPY_FIELD(dst,field,src,error) \
507 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
508 return_val_if_nok (error, NULL); \
509 MONO_OBJECT_SETREF ((dst),field,copied_val); \
512 XCOPY_FIELD (copy
, application_base
, setup
->application_base
, error
);
513 XCOPY_FIELD (copy
, application_name
, setup
->application_name
, error
);
514 XCOPY_FIELD (copy
, cache_path
, setup
->cache_path
, error
);
515 XCOPY_FIELD (copy
, configuration_file
, setup
->configuration_file
, error
);
516 XCOPY_FIELD (copy
, dynamic_base
, setup
->dynamic_base
, error
);
517 XCOPY_FIELD (copy
, license_file
, setup
->license_file
, error
);
518 XCOPY_FIELD (copy
, private_bin_path
, setup
->private_bin_path
, error
);
519 XCOPY_FIELD (copy
, private_bin_path_probe
, setup
->private_bin_path_probe
, error
);
520 XCOPY_FIELD (copy
, shadow_copy_directories
, setup
->shadow_copy_directories
, error
);
521 XCOPY_FIELD (copy
, shadow_copy_files
, setup
->shadow_copy_files
, error
);
522 copy
->publisher_policy
= setup
->publisher_policy
;
523 copy
->path_changed
= setup
->path_changed
;
524 copy
->loader_optimization
= setup
->loader_optimization
;
525 copy
->disallow_binding_redirects
= setup
->disallow_binding_redirects
;
526 copy
->disallow_code_downloads
= setup
->disallow_code_downloads
;
527 XCOPY_FIELD (copy
, domain_initializer_args
, setup
->domain_initializer_args
, error
);
528 copy
->disallow_appbase_probe
= setup
->disallow_appbase_probe
;
529 XCOPY_FIELD (copy
, application_trust
, setup
->application_trust
, error
);
530 XCOPY_FIELD (copy
, configuration_bytes
, setup
->configuration_bytes
, error
);
531 XCOPY_FIELD (copy
, serialized_non_primitives
, setup
->serialized_non_primitives
, error
);
535 mono_domain_set_internal (caller_domain
);
540 static MonoAppDomain
*
541 mono_domain_create_appdomain_internal (char *friendly_name
, MonoAppDomainSetup
*setup
, MonoError
*error
)
546 char *shadow_location
;
548 mono_error_init (error
);
550 adclass
= mono_class_get_appdomain_class ();
552 /* FIXME: pin all those objects */
553 data
= mono_domain_create();
555 ad
= (MonoAppDomain
*) mono_object_new_checked (data
, adclass
, error
);
556 return_val_if_nok (error
, NULL
);
559 data
->friendly_name
= g_strdup (friendly_name
);
561 mono_profiler_appdomain_name (data
, data
->friendly_name
);
563 if (!setup
->application_base
) {
564 /* Inherit from the root domain since MS.NET does this */
565 MonoDomain
*root
= mono_get_root_domain ();
566 if (root
->setup
->application_base
) {
567 MonoString
*s
= mono_string_new_utf16_checked (data
, mono_string_chars (root
->setup
->application_base
), mono_string_length (root
->setup
->application_base
), error
);
568 mono_error_assert_ok (error
); /* FIXME don't swallow the error */
569 MONO_OBJECT_SETREF (setup
, application_base
, s
);
573 mono_context_init_checked (data
, error
);
574 return_val_if_nok (error
, NULL
);
576 data
->setup
= copy_app_domain_setup (data
, setup
, error
);
577 if (!mono_error_ok (error
)) {
578 g_free (data
->friendly_name
);
582 mono_domain_set_options_from_config (data
);
583 add_assemblies_to_domain (data
, mono_defaults
.corlib
->assembly
, NULL
);
585 #ifndef DISABLE_SHADOW_COPY
586 /*FIXME, guard this for when the debugger is not running */
587 shadow_location
= get_shadow_assembly_location_base (data
, error
);
588 if (!mono_error_ok (error
)) {
589 g_free (data
->friendly_name
);
593 g_free (shadow_location
);
596 create_domain_objects (data
);
602 * mono_domain_has_type_resolve:
603 * @domain: application domains being looked up
605 * Returns: TRUE if the AppDomain.TypeResolve field has been
609 mono_domain_has_type_resolve (MonoDomain
*domain
)
611 static MonoClassField
*field
= NULL
;
615 field
= mono_class_get_field_from_name (mono_defaults
.appdomain_class
, "TypeResolve");
619 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
623 mono_field_get_value ((MonoObject
*)(domain
->domain
), field
, &o
);
628 * mono_domain_try_type_resolve:
629 * @domain: application domainwhere the name where the type is going to be resolved
630 * @name: the name of the type to resolve or NULL.
631 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
633 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
634 * the assembly that matches name.
636 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
638 * Returns: A MonoReflectionAssembly or NULL if not found
640 MonoReflectionAssembly
*
641 mono_domain_try_type_resolve (MonoDomain
*domain
, char *name
, MonoObject
*tb
)
644 MonoReflectionAssembly
*ret
= mono_domain_try_type_resolve_checked (domain
, name
, tb
, &error
);
645 mono_error_cleanup (&error
);
650 MonoReflectionAssembly
*
651 mono_domain_try_type_resolve_checked (MonoDomain
*domain
, char *name
, MonoObject
*tb
, MonoError
*error
)
653 static MonoMethod
*method
= NULL
;
654 MonoReflectionAssembly
*ret
;
657 mono_error_init (error
);
659 g_assert (domain
!= NULL
&& ((name
!= NULL
) || (tb
!= NULL
)));
661 if (method
== NULL
) {
662 method
= mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
663 if (method
== NULL
) {
664 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
670 *params
= (MonoObject
*)mono_string_new (mono_domain_get (), name
);
674 ret
= (MonoReflectionAssembly
*) mono_runtime_invoke_checked (method
, domain
->domain
, params
, error
);
675 return_val_if_nok (error
, NULL
);
681 * mono_domain_owns_vtable_slot:
683 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
686 mono_domain_owns_vtable_slot (MonoDomain
*domain
, gpointer vtable_slot
)
690 mono_domain_lock (domain
);
691 res
= mono_mempool_contains_addr (domain
->mp
, vtable_slot
);
692 mono_domain_unlock (domain
);
699 * @force: force setting.
701 * Set the current appdomain to @domain. If @force is set, set it even
702 * if it is being unloaded.
706 * FALSE if the domain is unloaded
709 mono_domain_set (MonoDomain
*domain
, gboolean force
)
711 if (!force
&& domain
->state
== MONO_APPDOMAIN_UNLOADED
)
714 mono_domain_set_internal (domain
);
720 ves_icall_System_AppDomain_GetData (MonoAppDomain
*ad
, MonoString
*name
)
727 MONO_CHECK_ARG_NULL (name
, NULL
);
733 str
= mono_string_to_utf8_checked (name
, &error
);
734 if (mono_error_set_pending_exception (&error
))
737 mono_domain_lock (add
);
739 if (!strcmp (str
, "APPBASE"))
740 o
= (MonoObject
*)add
->setup
->application_base
;
741 else if (!strcmp (str
, "APP_CONFIG_FILE"))
742 o
= (MonoObject
*)add
->setup
->configuration_file
;
743 else if (!strcmp (str
, "DYNAMIC_BASE"))
744 o
= (MonoObject
*)add
->setup
->dynamic_base
;
745 else if (!strcmp (str
, "APP_NAME"))
746 o
= (MonoObject
*)add
->setup
->application_name
;
747 else if (!strcmp (str
, "CACHE_BASE"))
748 o
= (MonoObject
*)add
->setup
->cache_path
;
749 else if (!strcmp (str
, "PRIVATE_BINPATH"))
750 o
= (MonoObject
*)add
->setup
->private_bin_path
;
751 else if (!strcmp (str
, "BINPATH_PROBE_ONLY"))
752 o
= (MonoObject
*)add
->setup
->private_bin_path_probe
;
753 else if (!strcmp (str
, "SHADOW_COPY_DIRS"))
754 o
= (MonoObject
*)add
->setup
->shadow_copy_directories
;
755 else if (!strcmp (str
, "FORCE_CACHE_INSTALL"))
756 o
= (MonoObject
*)add
->setup
->shadow_copy_files
;
758 o
= (MonoObject
*)mono_g_hash_table_lookup (add
->env
, name
);
760 mono_domain_unlock (add
);
770 ves_icall_System_AppDomain_SetData (MonoAppDomain
*ad
, MonoString
*name
, MonoObject
*data
)
774 MONO_CHECK_ARG_NULL (name
,);
780 mono_domain_lock (add
);
782 mono_g_hash_table_insert (add
->env
, name
, data
);
784 mono_domain_unlock (add
);
788 ves_icall_System_AppDomain_getSetup (MonoAppDomain
*ad
)
793 return ad
->data
->setup
;
797 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain
*ad
)
802 return mono_string_new (ad
->data
, ad
->data
->friendly_name
);
806 ves_icall_System_AppDomain_getCurDomain ()
808 MonoDomain
*add
= mono_domain_get ();
814 ves_icall_System_AppDomain_getRootDomain ()
816 MonoDomain
*root
= mono_get_root_domain ();
822 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
824 MonoDomain
*domain
= mono_domain_get ();
826 return domain
->throw_unobserved_task_exceptions
;
830 get_attribute_value (const gchar
**attribute_names
,
831 const gchar
**attribute_values
,
832 const char *att_name
)
835 for (n
= 0; attribute_names
[n
] != NULL
; n
++) {
836 if (strcmp (attribute_names
[n
], att_name
) == 0)
837 return g_strdup (attribute_values
[n
]);
843 start_element (GMarkupParseContext
*context
,
844 const gchar
*element_name
,
845 const gchar
**attribute_names
,
846 const gchar
**attribute_values
,
850 RuntimeConfig
*runtime_config
= (RuntimeConfig
*)user_data
;
852 if (strcmp (element_name
, "runtime") == 0) {
853 runtime_config
->runtime_count
++;
857 if (strcmp (element_name
, "assemblyBinding") == 0) {
858 runtime_config
->assemblybinding_count
++;
862 if (runtime_config
->runtime_count
!= 1)
865 if (strcmp (element_name
, "ThrowUnobservedTaskExceptions") == 0) {
866 const char *value
= get_attribute_value (attribute_names
, attribute_values
, "enabled");
868 if (value
&& g_ascii_strcasecmp (value
, "true") == 0)
869 runtime_config
->domain
->throw_unobserved_task_exceptions
= TRUE
;
872 if (runtime_config
->assemblybinding_count
!= 1)
875 if (strcmp (element_name
, "probing") != 0)
878 g_free (runtime_config
->domain
->private_bin_path
);
879 runtime_config
->domain
->private_bin_path
= get_attribute_value (attribute_names
, attribute_values
, "privatePath");
880 if (runtime_config
->domain
->private_bin_path
&& !runtime_config
->domain
->private_bin_path
[0]) {
881 g_free (runtime_config
->domain
->private_bin_path
);
882 runtime_config
->domain
->private_bin_path
= NULL
;
888 end_element (GMarkupParseContext
*context
,
889 const gchar
*element_name
,
893 RuntimeConfig
*runtime_config
= (RuntimeConfig
*)user_data
;
894 if (strcmp (element_name
, "runtime") == 0)
895 runtime_config
->runtime_count
--;
896 else if (strcmp (element_name
, "assemblyBinding") == 0)
897 runtime_config
->assemblybinding_count
--;
901 parse_error (GMarkupParseContext
*context
, GError
*error
, gpointer user_data
)
903 RuntimeConfig
*state
= (RuntimeConfig
*)user_data
;
905 const gchar
*filename
;
907 filename
= state
&& state
->filename
? (gchar
*) state
->filename
: "<unknown>";
908 msg
= error
&& error
->message
? error
->message
: "";
909 g_warning ("Error parsing %s: %s", filename
, msg
);
912 static const GMarkupParser
922 mono_domain_set_options_from_config (MonoDomain
*domain
)
925 gchar
*config_file_name
= NULL
, *text
= NULL
, *config_file_path
= NULL
;
927 GMarkupParseContext
*context
;
928 RuntimeConfig runtime_config
;
931 if (!domain
|| !domain
->setup
|| !domain
->setup
->configuration_file
)
934 config_file_name
= mono_string_to_utf8_checked (domain
->setup
->configuration_file
, &error
);
935 if (!mono_error_ok (&error
)) {
936 mono_error_cleanup (&error
);
940 config_file_path
= mono_portability_find_file (config_file_name
, TRUE
);
941 if (!config_file_path
)
942 config_file_path
= config_file_name
;
944 if (!g_file_get_contents (config_file_path
, &text
, &len
, NULL
))
947 runtime_config
.runtime_count
= 0;
948 runtime_config
.assemblybinding_count
= 0;
949 runtime_config
.domain
= domain
;
950 runtime_config
.filename
= config_file_path
;
953 if (len
> 3 && text
[0] == '\xef' && text
[1] == (gchar
) '\xbb' && text
[2] == '\xbf')
954 offset
= 3; /* Skip UTF-8 BOM */
956 context
= g_markup_parse_context_new (&mono_parser
, (GMarkupParseFlags
)0, &runtime_config
, NULL
);
957 if (g_markup_parse_context_parse (context
, text
+ offset
, len
- offset
, NULL
))
958 g_markup_parse_context_end_parse (context
, NULL
);
959 g_markup_parse_context_free (context
);
963 if (config_file_name
!= config_file_path
)
964 g_free (config_file_name
);
965 g_free (config_file_path
);
969 ves_icall_System_AppDomain_createDomain (MonoString
*friendly_name
, MonoAppDomainSetup
*setup
)
972 MonoAppDomain
*ad
= NULL
;
974 #ifdef DISABLE_APPDOMAINS
975 mono_error_init (&error
);
976 mono_error_set_not_supported (&error
, "AppDomain creation is not supported on this runtime.");
980 fname
= mono_string_to_utf8_checked (friendly_name
, &error
);
981 if (mono_error_set_pending_exception (&error
))
983 ad
= mono_domain_create_appdomain_internal (fname
, setup
, &error
);
987 mono_error_set_pending_exception (&error
);
992 add_assembly_to_array (MonoDomain
*domain
, MonoArrayHandle dest
, int dest_idx
, MonoAssembly
* assm
, MonoError
*error
)
994 HANDLE_FUNCTION_ENTER ();
995 mono_error_init (error
);
996 MonoReflectionAssemblyHandle assm_obj
= mono_assembly_get_object_handle (domain
, assm
, error
);
999 MONO_HANDLE_ARRAY_SETREF (dest
, dest_idx
, assm_obj
);
1001 HANDLE_FUNCTION_RETURN_VAL (is_ok (error
));
1005 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad
, MonoBoolean refonly
, MonoError
*error
)
1007 mono_error_init (error
);
1008 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
1012 GPtrArray
*assemblies
;
1015 * Make a copy of the list of assemblies because we can't hold the assemblies
1016 * lock while creating objects etc.
1018 assemblies
= g_ptr_array_new ();
1019 /* Need to skip internal assembly builders created by remoting */
1020 mono_domain_assemblies_lock (domain
);
1021 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1022 ass
= (MonoAssembly
*)tmp
->data
;
1023 if (refonly
!= ass
->ref_only
)
1025 if (ass
->corlib_internal
)
1027 g_ptr_array_add (assemblies
, ass
);
1029 mono_domain_assemblies_unlock (domain
);
1031 MonoArrayHandle res
= mono_array_new_handle (domain
, mono_class_get_assembly_class (), assemblies
->len
, error
);
1034 for (i
= 0; i
< assemblies
->len
; ++i
) {
1035 if (!add_assembly_to_array (domain
, res
, i
, (MonoAssembly
*)g_ptr_array_index (assemblies
, i
), error
))
1040 g_ptr_array_free (assemblies
, TRUE
);
1045 mono_try_assembly_resolve (MonoDomain
*domain
, const char *fname_raw
, MonoAssembly
*requesting
, gboolean refonly
, MonoError
*error
)
1047 HANDLE_FUNCTION_ENTER ();
1048 mono_error_init (error
);
1049 MonoAssembly
*result
= NULL
;
1050 MonoStringHandle fname
= mono_string_new_handle (domain
, fname_raw
, error
);
1053 result
= mono_try_assembly_resolve_handle (domain
, fname
, requesting
, refonly
, error
);
1055 HANDLE_FUNCTION_RETURN_VAL (result
);
1059 mono_try_assembly_resolve_handle (MonoDomain
*domain
, MonoStringHandle fname
, MonoAssembly
*requesting
, gboolean refonly
, MonoError
*error
)
1061 MonoAssembly
*ret
= NULL
;
1063 MonoBoolean isrefonly
;
1064 gpointer params
[3];
1066 mono_error_init (error
);
1068 if (mono_runtime_get_no_exec ())
1071 g_assert (domain
!= NULL
&& !MONO_HANDLE_IS_NULL (fname
));
1073 method
= mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1074 g_assert (method
!= NULL
);
1076 isrefonly
= refonly
? 1 : 0;
1077 MonoReflectionAssemblyHandle requesting_handle
;
1079 requesting_handle
= mono_assembly_get_object_handle (domain
, requesting
, error
);
1080 return_val_if_nok (error
, ret
);
1082 params
[0] = MONO_HANDLE_RAW (fname
);
1083 params
[1] = requesting
? MONO_HANDLE_RAW (requesting_handle
) : NULL
;
1084 params
[2] = &isrefonly
;
1085 MonoReflectionAssemblyHandle result
= MONO_HANDLE_NEW (MonoReflectionAssembly
, mono_runtime_invoke_checked (method
, domain
->domain
, params
, error
));
1086 ret
= !MONO_HANDLE_IS_NULL (result
) ? MONO_HANDLE_GETVAL (result
, assembly
) : NULL
;
1091 mono_domain_assembly_postload_search (MonoAssemblyName
*aname
, MonoAssembly
*requesting
,
1095 MonoAssembly
*assembly
;
1096 MonoDomain
*domain
= mono_domain_get ();
1099 aname_str
= mono_stringify_assembly_name (aname
);
1101 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1103 assembly
= mono_try_assembly_resolve (domain
, aname_str
, requesting
, refonly
, &error
);
1105 mono_error_cleanup (&error
);
1111 * LOCKING: assumes assemblies_lock in the domain is already locked.
1114 add_assemblies_to_domain (MonoDomain
*domain
, MonoAssembly
*ass
, GHashTable
*ht
)
1118 gboolean destroy_ht
= FALSE
;
1120 if (!ass
->aname
.name
)
1124 ht
= g_hash_table_new (mono_aligned_addr_hash
, NULL
);
1128 /* FIXME: handle lazy loaded assemblies */
1129 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1130 g_hash_table_insert (ht
, tmp
->data
, tmp
->data
);
1132 if (!g_hash_table_lookup (ht
, ass
)) {
1133 mono_assembly_addref (ass
);
1134 g_hash_table_insert (ht
, ass
, ass
);
1135 domain
->domain_assemblies
= g_slist_append (domain
->domain_assemblies
, ass
);
1136 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
);
1139 if (ass
->image
->references
) {
1140 for (i
= 0; ass
->image
->references
[i
] != NULL
; i
++) {
1141 if (ass
->image
->references
[i
] != REFERENCE_MISSING
)
1142 if (!g_hash_table_lookup (ht
, ass
->image
->references
[i
])) {
1143 add_assemblies_to_domain (domain
, ass
->image
->references
[i
], ht
);
1148 g_hash_table_destroy (ht
);
1152 mono_domain_fire_assembly_load (MonoAssembly
*assembly
, gpointer user_data
)
1154 static MonoClassField
*assembly_load_field
;
1155 static MonoMethod
*assembly_load_method
;
1157 MonoDomain
*domain
= mono_domain_get ();
1159 gpointer load_value
;
1162 if (!domain
->domain
)
1163 /* This can happen during startup */
1165 #ifdef ASSEMBLY_LOAD_DEBUG
1166 fprintf (stderr
, "Loading %s into domain %s\n", assembly
->aname
.name
, domain
->friendly_name
);
1168 klass
= domain
->domain
->mbr
.obj
.vtable
->klass
;
1170 mono_domain_assemblies_lock (domain
);
1171 add_assemblies_to_domain (domain
, assembly
, NULL
);
1172 mono_domain_assemblies_unlock (domain
);
1174 if (assembly_load_field
== NULL
) {
1175 assembly_load_field
= mono_class_get_field_from_name (klass
, "AssemblyLoad");
1176 g_assert (assembly_load_field
);
1179 mono_field_get_value ((MonoObject
*) domain
->domain
, assembly_load_field
, &load_value
);
1180 if (load_value
== NULL
) {
1181 /* No events waiting to be triggered */
1185 MonoReflectionAssemblyHandle ref_assembly
= mono_assembly_get_object_handle (domain
, assembly
, &error
);
1186 mono_error_assert_ok (&error
);
1188 if (assembly_load_method
== NULL
) {
1189 assembly_load_method
= mono_class_get_method_from_name (klass
, "DoAssemblyLoad", -1);
1190 g_assert (assembly_load_method
);
1193 *params
= MONO_HANDLE_RAW(ref_assembly
);
1195 mono_runtime_invoke_checked (assembly_load_method
, domain
->domain
, params
, &error
);
1196 mono_error_cleanup (&error
);
1200 * LOCKING: Acquires the domain assemblies lock.
1203 set_domain_search_path (MonoDomain
*domain
)
1206 MonoAppDomainSetup
*setup
;
1208 gchar
*search_path
= NULL
;
1211 gchar
**pvt_split
= NULL
;
1212 GError
*gerror
= NULL
;
1213 gint appbaselen
= -1;
1216 * We use the low-level domain assemblies lock, since this is called from
1217 * assembly loads hooks, which means this thread might hold the loader lock.
1219 mono_domain_assemblies_lock (domain
);
1221 if (!domain
->setup
) {
1222 mono_domain_assemblies_unlock (domain
);
1226 if ((domain
->search_path
!= NULL
) && !domain
->setup
->path_changed
) {
1227 mono_domain_assemblies_unlock (domain
);
1230 setup
= domain
->setup
;
1231 if (!setup
->application_base
) {
1232 mono_domain_assemblies_unlock (domain
);
1233 return; /* Must set application base to get private path working */
1238 if (setup
->private_bin_path
) {
1239 search_path
= mono_string_to_utf8_checked (setup
->private_bin_path
, &error
);
1240 if (!mono_error_ok (&error
)) { /*FIXME maybe we should bubble up the error.*/
1241 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1242 mono_error_cleanup (&error
);
1243 mono_domain_assemblies_unlock (domain
);
1248 if (domain
->private_bin_path
) {
1249 if (search_path
== NULL
)
1250 search_path
= domain
->private_bin_path
;
1252 gchar
*tmp2
= search_path
;
1253 search_path
= g_strjoin (";", search_path
, domain
->private_bin_path
, NULL
);
1260 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1261 * directories relative to ApplicationBase separated by semicolons (see
1262 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1263 * The loop below copes with the fact that some Unix applications may use ':' (or
1264 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1265 * ';' for the subsequent split.
1267 * The issue was reported in bug #81446
1270 #ifndef TARGET_WIN32
1273 slen
= strlen (search_path
);
1274 for (i
= 0; i
< slen
; i
++)
1275 if (search_path
[i
] == ':')
1276 search_path
[i
] = ';';
1279 pvt_split
= g_strsplit (search_path
, ";", 1000);
1280 g_free (search_path
);
1281 for (tmp
= pvt_split
; *tmp
; tmp
++, npaths
++);
1286 g_strfreev (pvt_split
);
1288 * Don't do this because the first time is called, the domain
1289 * setup is not finished.
1291 * domain->search_path = g_malloc (sizeof (char *));
1292 * domain->search_path [0] = NULL;
1294 mono_domain_assemblies_unlock (domain
);
1298 if (domain
->search_path
)
1299 g_strfreev (domain
->search_path
);
1301 tmp
= (gchar
**)g_malloc ((npaths
+ 1) * sizeof (gchar
*));
1302 tmp
[npaths
] = NULL
;
1304 *tmp
= mono_string_to_utf8_checked (setup
->application_base
, &error
);
1305 if (!mono_error_ok (&error
)) {
1306 mono_error_cleanup (&error
);
1307 g_strfreev (pvt_split
);
1310 mono_domain_assemblies_unlock (domain
);
1314 domain
->search_path
= tmp
;
1316 /* FIXME: is this needed? */
1317 if (strncmp (*tmp
, "file://", 7) == 0) {
1323 uri
= g_strdup_printf ("file:///%s", uri
+ 7);
1326 uri
= mono_escape_uri_string (tmpuri
);
1327 *tmp
= g_filename_from_uri (uri
, NULL
, &gerror
);
1333 if (gerror
!= NULL
) {
1334 g_warning ("%s\n", gerror
->message
);
1335 g_error_free (gerror
);
1342 for (i
= 1; pvt_split
&& i
< npaths
; i
++) {
1343 if (g_path_is_absolute (pvt_split
[i
- 1])) {
1344 tmp
[i
] = g_strdup (pvt_split
[i
- 1]);
1346 tmp
[i
] = g_build_filename (tmp
[0], pvt_split
[i
- 1], NULL
);
1349 if (strchr (tmp
[i
], '.')) {
1353 reduced
= mono_path_canonicalize (tmp
[i
]);
1354 if (appbaselen
== -1)
1355 appbaselen
= strlen (tmp
[0]);
1357 if (strncmp (tmp
[0], reduced
, appbaselen
)) {
1360 tmp
[i
] = g_strdup ("");
1370 if (setup
->private_bin_path_probe
!= NULL
) {
1372 tmp
[0] = g_strdup ("");
1375 domain
->setup
->path_changed
= FALSE
;
1377 g_strfreev (pvt_split
);
1379 mono_domain_assemblies_unlock (domain
);
1382 #ifdef DISABLE_SHADOW_COPY
1384 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1390 mono_make_shadow_copy (const char *filename
, MonoError
*error
)
1392 mono_error_init (error
);
1393 return (char *) filename
;
1397 shadow_copy_sibling (gchar
*src
, gint srclen
, const char *extension
, gchar
*target
, gint targetlen
, gint tail_len
)
1399 guint16
*orig
, *dest
;
1400 gboolean copy_result
;
1402 strcpy (src
+ srclen
- tail_len
, extension
);
1404 if (IS_PORTABILITY_CASE
) {
1405 gchar
*file
= mono_portability_find_file (src
, TRUE
);
1411 } else if (!g_file_test (src
, G_FILE_TEST_IS_REGULAR
)) {
1415 orig
= g_utf8_to_utf16 (src
, strlen (src
), NULL
, NULL
, NULL
);
1417 strcpy (target
+ targetlen
- tail_len
, extension
);
1418 dest
= g_utf8_to_utf16 (target
, strlen (target
), NULL
, NULL
, NULL
);
1422 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1423 copy_result
= CopyFile (orig
, dest
, FALSE
);
1425 copy_result
= SUCCEEDED (CopyFile2 (orig
, dest
, NULL
));
1428 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1429 * overwritten when updated in their original locations. */
1431 copy_result
= SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1440 get_cstring_hash (const char *str
)
1446 if (!str
|| !str
[0])
1451 for (i
= 0; i
< len
; i
++) {
1452 h
= (h
<< 5) - h
+ *p
;
1460 * Returned memory is malloc'd. Called must free it
1463 get_shadow_assembly_location_base (MonoDomain
*domain
, MonoError
*error
)
1465 MonoAppDomainSetup
*setup
;
1466 char *cache_path
, *appname
;
1470 mono_error_init (error
);
1472 setup
= domain
->setup
;
1473 if (setup
->cache_path
!= NULL
&& setup
->application_name
!= NULL
) {
1474 cache_path
= mono_string_to_utf8_checked (setup
->cache_path
, error
);
1475 return_val_if_nok (error
, NULL
);
1477 #ifndef TARGET_WIN32
1480 for (i
= strlen (cache_path
) - 1; i
>= 0; i
--)
1481 if (cache_path
[i
] == '\\')
1482 cache_path
[i
] = '/';
1486 appname
= mono_string_to_utf8_checked (setup
->application_name
, error
);
1487 if (!mono_error_ok (error
)) {
1488 g_free (cache_path
);
1492 location
= g_build_filename (cache_path
, appname
, "assembly", "shadow", NULL
);
1494 g_free (cache_path
);
1496 userdir
= g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1497 location
= g_build_filename (g_get_tmp_dir (), userdir
, "assembly", "shadow", NULL
);
1504 get_shadow_assembly_location (const char *filename
, MonoError
*error
)
1506 gint32 hash
= 0, hash2
= 0;
1508 char path_hash
[30];
1509 char *bname
= g_path_get_basename (filename
);
1510 char *dirname
= g_path_get_dirname (filename
);
1511 char *location
, *tmploc
;
1512 MonoDomain
*domain
= mono_domain_get ();
1514 mono_error_init (error
);
1516 hash
= get_cstring_hash (bname
);
1517 hash2
= get_cstring_hash (dirname
);
1518 g_snprintf (name_hash
, sizeof (name_hash
), "%08x", hash
);
1519 g_snprintf (path_hash
, sizeof (path_hash
), "%08x_%08x_%08x", hash
^ hash2
, hash2
, domain
->shadow_serial
);
1520 tmploc
= get_shadow_assembly_location_base (domain
, error
);
1521 if (!mono_error_ok (error
)) {
1527 location
= g_build_filename (tmploc
, name_hash
, path_hash
, bname
, NULL
);
1535 private_file_needs_copying (const char *src
, struct stat
*sbuf_src
, char *dest
)
1537 struct stat sbuf_dest
;
1539 gchar
*real_src
= mono_portability_find_file (src
, TRUE
);
1542 stat_src
= (gchar
*)src
;
1544 stat_src
= real_src
;
1546 if (stat (stat_src
, sbuf_src
) == -1) {
1547 time_t tnow
= time (NULL
);
1552 memset (sbuf_src
, 0, sizeof (*sbuf_src
));
1553 sbuf_src
->st_mtime
= tnow
;
1554 sbuf_src
->st_atime
= tnow
;
1561 if (stat (dest
, &sbuf_dest
) == -1)
1564 if (sbuf_src
->st_size
== sbuf_dest
.st_size
&&
1565 sbuf_src
->st_mtime
== sbuf_dest
.st_mtime
)
1572 shadow_copy_create_ini (const char *shadow
, const char *filename
)
1582 dir_name
= g_path_get_dirname (shadow
);
1583 ini_file
= g_build_filename (dir_name
, "__AssemblyInfo__.ini", NULL
);
1585 if (g_file_test (ini_file
, G_FILE_TEST_IS_REGULAR
)) {
1590 u16_ini
= g_utf8_to_utf16 (ini_file
, strlen (ini_file
), NULL
, NULL
, NULL
);
1595 handle
= (void **)CreateFile (u16_ini
, GENERIC_WRITE
, FILE_SHARE_READ
|FILE_SHARE_WRITE
,
1596 NULL
, CREATE_NEW
, FileAttributes_Normal
, NULL
);
1598 if (handle
== INVALID_HANDLE_VALUE
) {
1602 full_path
= mono_path_resolve_symlinks (filename
);
1603 result
= WriteFile (handle
, full_path
, strlen (full_path
), &n
, NULL
);
1605 CloseHandle (handle
);
1610 mono_is_shadow_copy_enabled (MonoDomain
*domain
, const gchar
*dir_name
)
1613 MonoAppDomainSetup
*setup
;
1616 gchar
**directories
;
1617 gchar
*shadow_status_string
;
1619 gboolean shadow_enabled
;
1620 gboolean found
= FALSE
;
1625 setup
= domain
->setup
;
1626 if (setup
== NULL
|| setup
->shadow_copy_files
== NULL
)
1629 shadow_status_string
= mono_string_to_utf8_checked (setup
->shadow_copy_files
, &error
);
1630 if (!mono_error_ok (&error
)) {
1631 mono_error_cleanup (&error
);
1634 shadow_enabled
= !g_ascii_strncasecmp (shadow_status_string
, "true", 4);
1635 g_free (shadow_status_string
);
1637 if (!shadow_enabled
)
1640 if (setup
->shadow_copy_directories
== NULL
)
1643 /* Is dir_name a shadow_copy destination already? */
1644 base_dir
= get_shadow_assembly_location_base (domain
, &error
);
1645 if (!mono_error_ok (&error
)) {
1646 mono_error_cleanup (&error
);
1650 if (strstr (dir_name
, base_dir
)) {
1656 all_dirs
= mono_string_to_utf8_checked (setup
->shadow_copy_directories
, &error
);
1657 if (!mono_error_ok (&error
)) {
1658 mono_error_cleanup (&error
);
1662 directories
= g_strsplit (all_dirs
, G_SEARCHPATH_SEPARATOR_S
, 1000);
1663 dir_ptr
= directories
;
1665 if (**dir_ptr
!= '\0' && !strcmp (*dir_ptr
, dir_name
)) {
1671 g_strfreev (directories
);
1677 This function raises exceptions so it can cause as sorts of nasty stuff if called
1678 while holding a lock.
1679 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1680 or NULL if source file not found.
1681 FIXME bubble up the error instead of raising it here
1684 mono_make_shadow_copy (const char *filename
, MonoError
*oerror
)
1687 gchar
*sibling_source
, *sibling_target
;
1688 gint sibling_source_len
, sibling_target_len
;
1689 guint16
*orig
, *dest
;
1692 gboolean copy_result
;
1693 struct stat src_sbuf
;
1694 struct utimbuf utbuf
;
1695 char *dir_name
= g_path_get_dirname (filename
);
1696 MonoDomain
*domain
= mono_domain_get ();
1699 mono_error_init (oerror
);
1701 set_domain_search_path (domain
);
1703 if (!mono_is_shadow_copy_enabled (domain
, dir_name
)) {
1705 return (char *) filename
;
1708 /* Is dir_name a shadow_copy destination already? */
1709 shadow_dir
= get_shadow_assembly_location_base (domain
, &error
);
1710 if (!mono_error_ok (&error
)) {
1711 mono_error_cleanup (&error
);
1713 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (invalid characters in shadow directory name).");
1717 if (strstr (dir_name
, shadow_dir
)) {
1718 g_free (shadow_dir
);
1720 return (char *) filename
;
1722 g_free (shadow_dir
);
1725 shadow
= get_shadow_assembly_location (filename
, &error
);
1726 if (!mono_error_ok (&error
)) {
1727 mono_error_cleanup (&error
);
1728 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (invalid characters in file name).");
1732 if (g_ensure_directory_exists (shadow
) == FALSE
) {
1734 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (ensure directory exists).");
1738 if (!private_file_needs_copying (filename
, &src_sbuf
, shadow
))
1739 return (char*) shadow
;
1741 orig
= g_utf8_to_utf16 (filename
, strlen (filename
), NULL
, NULL
, NULL
);
1742 dest
= g_utf8_to_utf16 (shadow
, strlen (shadow
), NULL
, NULL
, NULL
);
1745 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1746 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1747 * and not have it runtime error" */
1748 attrs
= GetFileAttributes (orig
);
1749 if (attrs
== INVALID_FILE_ATTRIBUTES
) {
1751 return (char *)filename
;
1754 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
1755 copy_result
= CopyFile (orig
, dest
, FALSE
);
1757 copy_result
= SUCCEEDED (CopyFile2 (orig
, dest
, NULL
));
1760 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1761 * overwritten when updated in their original locations. */
1763 copy_result
= SetFileAttributes (dest
, FILE_ATTRIBUTE_NORMAL
);
1768 if (copy_result
== FALSE
) {
1771 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1772 if (GetLastError() == ERROR_FILE_NOT_FOUND
|| GetLastError() == ERROR_PATH_NOT_FOUND
)
1773 return NULL
; /* file not found, shadow copy failed */
1775 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy (CopyFile).");
1779 /* attempt to copy .mdb, .config if they exist */
1780 sibling_source
= g_strconcat (filename
, ".config", NULL
);
1781 sibling_source_len
= strlen (sibling_source
);
1782 sibling_target
= g_strconcat (shadow
, ".config", NULL
);
1783 sibling_target_len
= strlen (sibling_target
);
1785 copy_result
= shadow_copy_sibling (sibling_source
, sibling_source_len
, ".mdb", sibling_target
, sibling_target_len
, 7);
1787 copy_result
= shadow_copy_sibling (sibling_source
, sibling_source_len
, ".config", sibling_target
, sibling_target_len
, 7);
1789 g_free (sibling_source
);
1790 g_free (sibling_target
);
1794 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy of sibling data (CopyFile).");
1798 /* Create a .ini file containing the original assembly location */
1799 if (!shadow_copy_create_ini (shadow
, filename
)) {
1801 mono_error_set_execution_engine (oerror
, "Failed to create shadow copy .ini file.");
1805 utbuf
.actime
= src_sbuf
.st_atime
;
1806 utbuf
.modtime
= src_sbuf
.st_mtime
;
1807 utime (shadow
, &utbuf
);
1811 #endif /* DISABLE_SHADOW_COPY */
1814 mono_domain_from_appdomain (MonoAppDomain
*appdomain
)
1816 if (appdomain
== NULL
)
1819 return appdomain
->data
;
1823 try_load_from (MonoAssembly
**assembly
, const gchar
*path1
, const gchar
*path2
,
1824 const gchar
*path3
, const gchar
*path4
,
1825 gboolean refonly
, gboolean is_private
)
1828 gboolean found
= FALSE
;
1831 fullpath
= g_build_filename (path1
, path2
, path3
, path4
, NULL
);
1833 if (IS_PORTABILITY_SET
) {
1834 gchar
*new_fullpath
= mono_portability_find_file (fullpath
, TRUE
);
1837 fullpath
= new_fullpath
;
1841 found
= g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
);
1844 *assembly
= mono_assembly_open_full (fullpath
, NULL
, refonly
);
1847 return (*assembly
!= NULL
);
1850 static MonoAssembly
*
1851 real_load (gchar
**search_path
, const gchar
*culture
, const gchar
*name
, gboolean refonly
)
1853 MonoAssembly
*result
= NULL
;
1856 const gchar
*local_culture
;
1858 gboolean is_private
= FALSE
;
1860 if (!culture
|| *culture
== '\0') {
1863 local_culture
= culture
;
1866 filename
= g_strconcat (name
, ".dll", NULL
);
1867 len
= strlen (filename
);
1869 for (path
= search_path
; *path
; path
++) {
1870 if (**path
== '\0') {
1872 continue; /* Ignore empty ApplicationBase */
1875 /* See test cases in bug #58992 and bug #57710 */
1876 /* 1st try: [culture]/[name].dll (culture may be empty) */
1877 strcpy (filename
+ len
- 4, ".dll");
1878 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
, is_private
))
1881 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1882 strcpy (filename
+ len
- 4, ".exe");
1883 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
, is_private
))
1886 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1887 strcpy (filename
+ len
- 4, ".dll");
1888 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
, is_private
))
1891 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1892 strcpy (filename
+ len
- 4, ".exe");
1893 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
, is_private
))
1902 * Try loading the assembly from ApplicationBase and PrivateBinPath
1903 * and then from assemblies_path if any.
1904 * LOCKING: This is called from the assembly loading code, which means the caller
1905 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1907 static MonoAssembly
*
1908 mono_domain_assembly_preload (MonoAssemblyName
*aname
,
1909 gchar
**assemblies_path
,
1912 MonoDomain
*domain
= mono_domain_get ();
1913 MonoAssembly
*result
= NULL
;
1914 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
1916 set_domain_search_path (domain
);
1918 if (domain
->search_path
&& domain
->search_path
[0] != NULL
) {
1919 result
= real_load (domain
->search_path
, aname
->culture
, aname
->name
, refonly
);
1922 if (result
== NULL
&& assemblies_path
&& assemblies_path
[0] != NULL
) {
1923 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, refonly
);
1930 * Check whenever a given assembly was already loaded in the current appdomain.
1932 static MonoAssembly
*
1933 mono_domain_assembly_search (MonoAssemblyName
*aname
,
1936 MonoDomain
*domain
= mono_domain_get ();
1939 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
1941 mono_domain_assemblies_lock (domain
);
1942 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
1943 ass
= (MonoAssembly
*)tmp
->data
;
1944 /* Dynamic assemblies can't match here in MS.NET */
1945 if (assembly_is_dynamic (ass
) || refonly
!= ass
->ref_only
|| !mono_assembly_names_equal (aname
, &ass
->aname
))
1948 mono_domain_assemblies_unlock (domain
);
1951 mono_domain_assemblies_unlock (domain
);
1956 MonoReflectionAssemblyHandle
1957 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname
, MonoBoolean refOnly
, MonoError
*error
)
1959 mono_error_init (error
);
1960 MonoDomain
*domain
= mono_domain_get ();
1961 char *name
, *filename
;
1962 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
1963 MonoReflectionAssemblyHandle result
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
1968 if (fname
== NULL
) {
1969 mono_error_set_argument_null (error
, "assemblyFile", "");
1973 name
= filename
= mono_string_handle_to_utf8 (fname
, error
);
1977 MonoAssembly
*ass
= mono_assembly_open_full (filename
, &status
, refOnly
);
1980 if (status
== MONO_IMAGE_IMAGE_INVALID
)
1981 mono_error_set_bad_image_name (error
, g_strdup (name
), "");
1983 mono_error_set_assembly_load (error
, g_strdup (name
), "%s", "");
1987 result
= mono_assembly_get_object_handle (domain
, ass
, error
);
1994 MonoReflectionAssemblyHandle
1995 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad
,
1996 MonoArrayHandle raw_assembly
,
1997 MonoArrayHandle raw_symbol_store
, MonoObjectHandle evidence
,
1998 MonoBoolean refonly
,
2001 mono_error_init (error
);
2003 MonoReflectionAssemblyHandle refass
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2004 MonoDomain
*domain
= MONO_HANDLE_GETVAL(ad
, data
);
2005 MonoImageOpenStatus status
;
2006 guint32 raw_assembly_len
= mono_array_handle_length (raw_assembly
);
2008 /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2009 char *assembly_data
= (char*) g_try_malloc (raw_assembly_len
);
2010 if (!assembly_data
) {
2011 mono_error_set_out_of_memory (error
, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len
);
2015 mono_byte
*raw_data
= (mono_byte
*) MONO_ARRAY_HANDLE_PIN (raw_assembly
, gchar
, 0, &gchandle
);
2016 memcpy (assembly_data
, raw_data
, raw_assembly_len
);
2017 mono_gchandle_free (gchandle
); /* unpin */
2018 MONO_HANDLE_ASSIGN (raw_assembly
, NULL_HANDLE
); /* don't reference the data anymore */
2020 MonoImage
*image
= mono_image_open_from_data_full (assembly_data
, raw_assembly_len
, FALSE
, NULL
, refonly
);
2023 mono_error_set_bad_image_name (error
, g_strdup (""), "%s", "");
2027 if (!MONO_HANDLE_IS_NULL(raw_symbol_store
)) {
2028 guint32 symbol_len
= mono_array_handle_length (raw_symbol_store
);
2029 uint32_t symbol_gchandle
;
2030 mono_byte
*raw_symbol_data
= (mono_byte
*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store
, mono_byte
, 0, &symbol_gchandle
);
2031 mono_debug_open_image_from_memory (image
, raw_symbol_data
, symbol_len
);
2032 mono_gchandle_free (symbol_gchandle
);
2035 ass
= mono_assembly_load_from_full (image
, "", &status
, refonly
);
2039 mono_image_close (image
);
2040 mono_error_set_bad_image_name (error
, g_strdup (""), "%s", "");
2044 refass
= mono_assembly_get_object_handle (domain
, ass
, error
);
2045 if (!MONO_HANDLE_IS_NULL(refass
))
2046 MONO_HANDLE_SET (refass
, evidence
, evidence
);
2050 MonoReflectionAssemblyHandle
2051 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad
, MonoStringHandle assRef
, MonoObjectHandle evidence
, MonoBoolean refOnly
, MonoError
*error
)
2053 mono_error_init (error
);
2054 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
2055 MonoImageOpenStatus status
= MONO_IMAGE_OK
;
2057 MonoAssemblyName aname
;
2063 name
= mono_string_handle_to_utf8 (assRef
, error
);
2066 parsed
= mono_assembly_name_parse (name
, &aname
);
2070 MonoReflectionAssemblyHandle refass
= MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2071 /* This is a parse error... */
2073 MonoAssembly
*assm
= mono_try_assembly_resolve_handle (domain
, assRef
, NULL
, refOnly
, error
);
2077 refass
= mono_assembly_get_object_handle (domain
, assm
, error
);
2085 ass
= mono_assembly_load_full_nosearch (&aname
, NULL
, &status
, refOnly
);
2086 mono_assembly_name_free (&aname
);
2089 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2091 ass
= mono_try_assembly_resolve_handle (domain
, assRef
, NULL
, refOnly
, error
);
2100 MonoReflectionAssemblyHandle refass
= mono_assembly_get_object_handle (domain
, ass
, error
);
2104 MONO_HANDLE_SET (refass
, evidence
, evidence
);
2108 return MONO_HANDLE_CAST (MonoReflectionAssembly
, NULL_HANDLE
);
2112 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id
)
2114 MonoException
*exc
= NULL
;
2115 MonoDomain
* domain
= mono_domain_get_by_id (domain_id
);
2117 if (NULL
== domain
) {
2118 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2119 mono_set_pending_exception (exc
);
2123 if (domain
== mono_get_root_domain ()) {
2124 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2129 * Unloading seems to cause problems when running NUnit/NAnt, hence
2132 if (g_getenv ("MONO_NO_UNLOAD"))
2134 #ifdef __native_client__
2138 mono_domain_try_unload (domain
, (MonoObject
**)&exc
);
2140 mono_set_pending_exception (exc
);
2144 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id
)
2146 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2151 return mono_domain_is_unloading (domain
);
2155 ves_icall_System_AppDomain_DoUnhandledException (MonoException
*exc
)
2157 mono_unhandled_exception ((MonoObject
*) exc
);
2161 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad
,
2162 MonoReflectionAssemblyHandle refass
, MonoArrayHandle args
,
2165 mono_error_init (error
);
2169 g_assert (!MONO_HANDLE_IS_NULL (refass
));
2170 MonoAssembly
*assembly
= MONO_HANDLE_GETVAL (refass
, assembly
);
2171 image
= assembly
->image
;
2174 method
= mono_get_method_checked (image
, mono_image_get_entry_point (image
), NULL
, NULL
, error
);
2177 g_error ("No entry point method found in %s due to %s", image
->name
, mono_error_get_message (error
));
2179 if (MONO_HANDLE_IS_NULL (args
)) {
2180 MonoDomain
*domain
= MONO_HANDLE_GETVAL (ad
, data
);
2181 MONO_HANDLE_ASSIGN (args
, mono_array_new_handle (domain
, mono_defaults
.string_class
, 0, error
));
2182 mono_error_assert_ok (error
);
2185 int res
= mono_runtime_exec_main_checked (method
, MONO_HANDLE_RAW (args
), error
);
2190 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain
* ad
)
2192 return ad
->data
->domain_id
;
2196 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain
*ad
)
2198 MonoDomain
*old_domain
= mono_domain_get();
2200 if (!mono_domain_set (ad
->data
, FALSE
)) {
2201 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2205 return old_domain
->domain
;
2209 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid
)
2211 MonoDomain
*current_domain
= mono_domain_get ();
2212 MonoDomain
*domain
= mono_domain_get_by_id (domainid
);
2214 if (!domain
|| !mono_domain_set (domain
, FALSE
)) {
2215 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2219 return current_domain
->domain
;
2223 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain
*ad
)
2225 mono_thread_push_appdomain_ref (ad
->data
);
2229 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id
)
2231 MonoDomain
*domain
= mono_domain_get_by_id (domain_id
);
2235 * Raise an exception to prevent the managed code from executing a pop
2238 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2242 mono_thread_push_appdomain_ref (domain
);
2246 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2248 mono_thread_pop_appdomain_ref ();
2252 ves_icall_System_AppDomain_InternalGetContext ()
2254 return mono_context_get ();
2258 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2260 return mono_domain_get ()->default_context
;
2264 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext
*mc
)
2266 MonoAppContext
*old_context
= mono_context_get ();
2268 mono_context_set (mc
);
2274 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString
* newguid
)
2276 MonoDomain
* mono_root_domain
= mono_get_root_domain ();
2277 mono_domain_lock (mono_root_domain
);
2278 if (process_guid_set
) {
2279 mono_domain_unlock (mono_root_domain
);
2281 MonoString
*res
= NULL
;
2282 res
= mono_string_new_utf16_checked (mono_domain_get (), process_guid
, sizeof(process_guid
)/2, &error
);
2283 mono_error_set_pending_exception (&error
);
2286 memcpy (process_guid
, mono_string_chars(newguid
), sizeof(process_guid
));
2287 process_guid_set
= TRUE
;
2288 mono_domain_unlock (mono_root_domain
);
2293 mono_domain_is_unloading (MonoDomain
*domain
)
2295 if (domain
->state
== MONO_APPDOMAIN_UNLOADING
|| domain
->state
== MONO_APPDOMAIN_UNLOADED
)
2302 clear_cached_vtable (MonoVTable
*vtable
)
2304 MonoClass
*klass
= vtable
->klass
;
2305 MonoDomain
*domain
= vtable
->domain
;
2306 MonoClassRuntimeInfo
*runtime_info
;
2309 runtime_info
= klass
->runtime_info
;
2310 if (runtime_info
&& runtime_info
->max_domain
>= domain
->domain_id
)
2311 runtime_info
->domain_vtables
[domain
->domain_id
] = NULL
;
2312 if (klass
->has_static_refs
&& (data
= mono_vtable_get_static_field_data (vtable
)))
2313 mono_gc_free_fixed (data
);
2316 static G_GNUC_UNUSED
void
2317 zero_static_data (MonoVTable
*vtable
)
2319 MonoClass
*klass
= vtable
->klass
;
2322 if (klass
->has_static_refs
&& (data
= mono_vtable_get_static_field_data (vtable
)))
2323 mono_gc_bzero_aligned (data
, mono_class_data_size (klass
));
2326 typedef struct unload_data
{
2329 char *failure_reason
;
2334 unload_data_unref (unload_data
*data
)
2338 mono_atomic_load_acquire (count
, gint32
, &data
->refcount
);
2339 g_assert (count
>= 1 && count
<= 2);
2344 } while (InterlockedCompareExchange (&data
->refcount
, count
- 1, count
) != count
);
2348 deregister_reflection_info_roots_from_list (MonoImage
*image
)
2350 GSList
*list
= image
->reflection_info_unregister_classes
;
2353 MonoClass
*klass
= (MonoClass
*)list
->data
;
2355 mono_class_free_ref_info (klass
);
2360 image
->reflection_info_unregister_classes
= NULL
;
2364 deregister_reflection_info_roots (MonoDomain
*domain
)
2368 mono_domain_assemblies_lock (domain
);
2369 for (list
= domain
->domain_assemblies
; list
; list
= list
->next
) {
2370 MonoAssembly
*assembly
= (MonoAssembly
*)list
->data
;
2371 MonoImage
*image
= assembly
->image
;
2375 * No need to take the image lock here since dynamic images are appdomain bound and
2376 * at this point the mutator is gone. Taking the image lock here would mean
2377 * promoting it from a simple lock to a complex lock, which we better avoid if
2380 if (image_is_dynamic (image
))
2381 deregister_reflection_info_roots_from_list (image
);
2383 for (i
= 0; i
< image
->module_count
; ++i
) {
2384 MonoImage
*module
= image
->modules
[i
];
2385 if (module
&& image_is_dynamic (module
))
2386 deregister_reflection_info_roots_from_list (module
);
2389 mono_domain_assemblies_unlock (domain
);
2393 unload_thread_main (void *arg
)
2396 unload_data
*data
= (unload_data
*)arg
;
2397 MonoDomain
*domain
= data
->domain
;
2401 /* Have to attach to the runtime so shutdown can wait for this thread */
2402 /* Force it to be attached to avoid racing during shutdown. */
2403 thread
= mono_thread_attach_full (mono_get_root_domain (), TRUE
);
2405 mono_thread_set_name_internal (thread
->internal_thread
, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE
, &error
);
2406 if (!is_ok (&error
)) {
2407 data
->failure_reason
= g_strdup (mono_error_get_message (&error
));
2408 mono_error_cleanup (&error
);
2413 * FIXME: Abort our parent thread last, so we can return a failure
2414 * indication if aborting times out.
2416 if (!mono_threads_abort_appdomain_threads (domain
, -1)) {
2417 data
->failure_reason
= g_strdup_printf ("Aborting of threads in domain %s timed out.", domain
->friendly_name
);
2421 if (!mono_threadpool_remove_domain_jobs (domain
, -1)) {
2422 data
->failure_reason
= g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain
->friendly_name
);
2426 /* Finalize all finalizable objects in the doomed appdomain */
2427 if (!mono_domain_finalize (domain
, -1)) {
2428 data
->failure_reason
= g_strdup_printf ("Finalization of domain %s timed out.", domain
->friendly_name
);
2432 /* Clear references to our vtables in class->runtime_info.
2433 * We also hold the loader lock because we're going to change
2434 * class->runtime_info.
2437 mono_loader_lock (); //FIXME why do we need the loader lock here?
2438 mono_domain_lock (domain
);
2441 * We need to make sure that we don't have any remsets
2442 * pointing into static data of the to-be-freed domain because
2443 * at the next collections they would be invalid. So what we
2444 * do is we first zero all static data and then do a minor
2445 * collection. Because all references in the static data will
2446 * now be null we won't do any unnecessary copies and after
2447 * the collection there won't be any more remsets.
2449 for (i
= 0; i
< domain
->class_vtable_array
->len
; ++i
)
2450 zero_static_data ((MonoVTable
*)g_ptr_array_index (domain
->class_vtable_array
, i
));
2451 mono_gc_collect (0);
2453 for (i
= 0; i
< domain
->class_vtable_array
->len
; ++i
)
2454 clear_cached_vtable ((MonoVTable
*)g_ptr_array_index (domain
->class_vtable_array
, i
));
2455 deregister_reflection_info_roots (domain
);
2457 mono_assembly_cleanup_domain_bindings (domain
->domain_id
);
2459 mono_domain_unlock (domain
);
2460 mono_loader_unlock ();
2462 mono_threads_clear_cached_culture (domain
);
2464 domain
->state
= MONO_APPDOMAIN_UNLOADED
;
2466 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2468 /* remove from the handle table the items related to this domain */
2469 mono_gchandle_free_domain (domain
);
2471 mono_domain_free (domain
, FALSE
);
2473 mono_gc_collect (mono_gc_max_generation ());
2475 mono_atomic_store_release (&data
->done
, TRUE
);
2476 unload_data_unref (data
);
2477 mono_thread_detach (thread
);
2481 mono_atomic_store_release (&data
->done
, TRUE
);
2482 unload_data_unref (data
);
2483 mono_thread_detach (thread
);
2488 * mono_domain_unload:
2489 * @domain: The domain to unload
2491 * Unloads an appdomain. Follows the process outlined in the comment
2492 * for mono_domain_try_unload.
2495 mono_domain_unload (MonoDomain
*domain
)
2497 MonoObject
*exc
= NULL
;
2498 mono_domain_try_unload (domain
, &exc
);
2501 static MonoThreadInfoWaitRet
2502 guarded_wait (MonoThreadHandle
*thread_handle
, guint32 timeout
, gboolean alertable
)
2504 MonoThreadInfoWaitRet result
;
2507 result
= mono_thread_info_wait_one_handle (thread_handle
, timeout
, alertable
);
2514 * mono_domain_unload:
2515 * @domain: The domain to unload
2516 * @exc: Exception information
2518 * Unloads an appdomain. Follows the process outlined in:
2519 * http://blogs.gotdotnet.com/cbrumme
2521 * If doing things the 'right' way is too hard or complex, we do it the
2522 * 'simple' way, which means do everything needed to avoid crashes and
2523 * memory leaks, but not much else.
2525 * It is required to pass a valid reference to the exc argument, upon return
2526 * from this function *exc will be set to the exception thrown, if any.
2528 * If this method is not called from an icall (embedded scenario for instance),
2529 * it must not be called with any managed frames on the stack, since the unload
2530 * process could end up trying to abort the current thread.
2533 mono_domain_try_unload (MonoDomain
*domain
, MonoObject
**exc
)
2536 MonoThreadHandle
*thread_handle
;
2537 MonoAppDomainState prev_state
;
2539 unload_data
*thread_data
;
2540 MonoNativeThreadId tid
;
2541 MonoDomain
*caller_domain
= mono_domain_get ();
2543 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2545 /* Atomically change our state to UNLOADING */
2546 prev_state
= (MonoAppDomainState
)InterlockedCompareExchange ((gint32
*)&domain
->state
,
2547 MONO_APPDOMAIN_UNLOADING_START
,
2548 MONO_APPDOMAIN_CREATED
);
2549 if (prev_state
!= MONO_APPDOMAIN_CREATED
) {
2550 switch (prev_state
) {
2551 case MONO_APPDOMAIN_UNLOADING_START
:
2552 case MONO_APPDOMAIN_UNLOADING
:
2553 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2555 case MONO_APPDOMAIN_UNLOADED
:
2556 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2559 g_warning ("Invalid appdomain state %d", prev_state
);
2560 g_assert_not_reached ();
2564 mono_domain_set (domain
, FALSE
);
2565 /* Notify OnDomainUnload listeners */
2566 method
= mono_class_get_method_from_name (domain
->domain
->mbr
.obj
.vtable
->klass
, "DoDomainUnload", -1);
2569 mono_runtime_try_invoke (method
, domain
->domain
, NULL
, exc
, &error
);
2571 if (!mono_error_ok (&error
)) {
2573 mono_error_cleanup (&error
);
2575 *exc
= (MonoObject
*)mono_error_convert_to_exception (&error
);
2579 /* Roll back the state change */
2580 domain
->state
= MONO_APPDOMAIN_CREATED
;
2581 mono_domain_set (caller_domain
, FALSE
);
2584 mono_domain_set (caller_domain
, FALSE
);
2586 thread_data
= g_new0 (unload_data
, 1);
2587 thread_data
->domain
= domain
;
2588 thread_data
->failure_reason
= NULL
;
2589 thread_data
->done
= FALSE
;
2590 thread_data
->refcount
= 2; /*Must be 2: unload thread + initiator */
2592 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2593 domain
->state
= MONO_APPDOMAIN_UNLOADING
;
2595 * First we create a separate thread for unloading, since
2596 * we might have to abort some threads, including the current one.
2598 thread_handle
= mono_threads_create_thread (unload_thread_main
, thread_data
, NULL
, &tid
);
2599 if (thread_handle
== NULL
)
2602 /* Wait for the thread */
2603 while (!thread_data
->done
&& guarded_wait (thread_handle
, MONO_INFINITE_WAIT
, TRUE
) == MONO_THREAD_INFO_WAIT_RET_ALERTED
) {
2604 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain
) && (mono_thread_interruption_requested ())) {
2605 /* The unload thread tries to abort us */
2606 /* The icall wrapper will execute the abort */
2607 mono_threads_close_thread_handle (thread_handle
);
2608 unload_data_unref (thread_data
);
2613 mono_threads_close_thread_handle (thread_handle
);
2615 if (thread_data
->failure_reason
) {
2616 /* Roll back the state change */
2617 domain
->state
= MONO_APPDOMAIN_CREATED
;
2619 g_warning ("%s", thread_data
->failure_reason
);
2621 *exc
= (MonoObject
*) mono_get_exception_cannot_unload_appdomain (thread_data
->failure_reason
);
2623 g_free (thread_data
->failure_reason
);
2624 thread_data
->failure_reason
= NULL
;
2627 unload_data_unref (thread_data
);