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/domain-internals.h>
39 #include "mono/metadata/metadata-internals.h"
40 #include <mono/metadata/assembly.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/threads.h>
43 #include <mono/metadata/threadpool-ms.h>
44 #include <mono/metadata/socket-io.h>
45 #include <mono/metadata/tabledefs.h>
46 #include <mono/metadata/gc-internals.h>
47 #include <mono/metadata/mono-gc.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/monitor.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/mono-debug-debugger.h>
52 #include <mono/metadata/attach.h>
53 #include <mono/metadata/file-io.h>
54 #include <mono/metadata/lock-tracer.h>
55 #include <mono/metadata/console-io.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/tokentype.h>
58 #include <mono/metadata/profiler-private.h>
59 #include <mono/metadata/reflection-internals.h>
60 #include <mono/utils/mono-uri.h>
61 #include <mono/utils/mono-logger-internals.h>
62 #include <mono/utils/mono-path.h>
63 #include <mono/utils/mono-stdlib.h>
64 #include <mono/utils/mono-io-portability.h>
65 #include <mono/utils/mono-error-internals.h>
66 #include <mono/utils/atomic.h>
67 #include <mono/utils/mono-memory-model.h>
68 #include <mono/utils/mono-threads.h>
74 * This is the version number of the corlib-runtime interface. When
75 * making changes to this interface (by changing the layout
76 * of classes the runtime knows about, changing icall signature or
77 * semantics etc), increment this variable. Also increment the
78 * pair of this variable in mscorlib in:
79 * mcs/class/corlib/System/Environment.cs
81 * Changes which are already detected at runtime, like the addition
82 * of icalls, do not require an increment.
84 #define MONO_CORLIB_VERSION 145
89 int assemblybinding_count;
94 static gunichar2 process_guid [36];
95 static gboolean process_guid_set = FALSE;
97 static gboolean no_exec = FALSE;
100 mono_domain_assembly_preload (MonoAssemblyName *aname,
101 gchar **assemblies_path,
104 static MonoAssembly *
105 mono_domain_assembly_search (MonoAssemblyName *aname,
109 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
112 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
114 static MonoAppDomain *
115 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
118 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
120 static MonoLoadFunc load_function = NULL;
122 /* Lazy class loading functions */
123 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
126 mono_install_runtime_load (MonoLoadFunc func)
128 load_function = func;
132 mono_runtime_load (const char *filename, const char *runtime_version)
134 g_assert (load_function);
135 return load_function (filename, runtime_version);
139 * mono_runtime_set_no_exec:
141 * Instructs the runtime to operate in static mode, i.e. avoid/do not
142 * allow managed code execution. This is useful for running the AOT
143 * compiler on platforms which allow full-aot execution only. This
144 * should be called before mono_runtime_init ().
147 mono_runtime_set_no_exec (gboolean val)
153 * mono_runtime_get_no_exec:
155 * If true, then the runtime will not allow managed code execution.
158 mono_runtime_get_no_exec (void)
164 create_domain_objects (MonoDomain *domain)
167 MonoDomain *old_domain = mono_domain_get ();
169 MonoVTable *string_vt;
170 MonoClassField *string_empty_fld;
172 if (domain != old_domain) {
173 mono_thread_push_appdomain_ref (domain);
174 mono_domain_set_internal_with_options (domain, FALSE);
178 * Initialize String.Empty. This enables the removal of
179 * the static cctor of the String class.
181 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
182 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
183 g_assert (string_empty_fld);
184 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
185 mono_error_assert_ok (&error);
186 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
189 * Create an instance early since we can't do it when there is no memory.
191 arg = mono_string_new (domain, "Out of memory");
192 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
195 * These two are needed because the signal handlers might be executing on
196 * an alternate stack, and Boehm GC can't handle that.
198 arg = mono_string_new (domain, "A null value was found where an object instance was required");
199 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
200 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
201 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
203 /*The ephemeron tombstone i*/
204 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
205 mono_error_assert_ok (&error);
207 if (domain != old_domain) {
208 mono_thread_pop_appdomain_ref ();
209 mono_domain_set_internal_with_options (old_domain, FALSE);
213 * This class is used during exception handling, so initialize it here, to prevent
214 * stack overflows while handling stack overflows.
216 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
221 * @domain: domain returned by mono_init ()
223 * Initialize the core AppDomain: this function will run also some
224 * IL initialization code, so it needs the execution engine to be fully
227 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
228 * we know the entry_assembly.
232 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
235 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
236 mono_error_cleanup (&error);
240 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
242 MonoAppDomainSetup *setup;
246 mono_error_init (error);
248 mono_portability_helpers_init ();
250 mono_gc_base_init ();
251 mono_monitor_init ();
252 mono_marshal_init ();
254 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
255 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
256 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
257 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
258 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
259 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
260 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
262 mono_thread_init (start_cb, attach_cb);
264 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
265 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
266 return_if_nok (error);
268 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
270 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
275 domain->setup = setup;
277 mono_thread_attach (domain);
279 mono_type_initialization_init ();
281 if (!mono_runtime_get_no_exec ())
282 create_domain_objects (domain);
284 /* GC init has to happen after thread init */
287 /* contexts use GC handles, so they must be initialized after the GC */
288 mono_context_init_checked (domain, error);
289 return_if_nok (error);
290 mono_context_set (domain->default_context);
292 #ifndef DISABLE_SOCKETS
293 mono_network_init ();
296 mono_console_init ();
299 mono_locks_tracer_init ();
301 /* mscorlib is loaded before we install the load hook */
302 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
308 mono_get_corlib_version (void)
312 MonoClassField *field;
315 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
316 mono_class_init (klass);
317 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
320 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
322 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
323 mono_error_assert_ok (&error);
324 return *(gint32*)((gchar*)value + sizeof (MonoObject));
328 * mono_check_corlib_version
330 * Checks that the corlib that is loaded matches the version of this runtime.
332 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
333 * allocated string with the error otherwise.
336 mono_check_corlib_version (void)
338 int version = mono_get_corlib_version ();
339 if (version != MONO_CORLIB_VERSION)
340 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
347 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
349 * Initializes the @domain's default System.Runtime.Remoting's Context.
352 mono_context_init (MonoDomain *domain)
355 mono_context_init_checked (domain, &error);
356 mono_error_cleanup (&error);
360 mono_context_init_checked (MonoDomain *domain, MonoError *error)
363 MonoAppContext *context;
365 mono_error_init (error);
367 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
368 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
369 return_if_nok (error);
371 context->domain_id = domain->domain_id;
372 context->context_id = 0;
373 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
374 domain->default_context = context;
378 * mono_runtime_cleanup:
383 * This must not be called while there are still running threads executing
387 mono_runtime_cleanup (MonoDomain *domain)
389 mono_attach_cleanup ();
391 /* This ends up calling any pending pending (for at most 2 seconds) */
394 mono_thread_cleanup ();
396 #ifndef DISABLE_SOCKETS
397 mono_network_cleanup ();
399 mono_marshal_cleanup ();
401 mono_type_initialization_cleanup ();
403 mono_monitor_cleanup ();
406 static MonoDomainFunc quit_function = NULL;
409 mono_install_runtime_cleanup (MonoDomainFunc func)
411 quit_function = func;
417 if (quit_function != NULL)
418 quit_function (mono_get_root_domain (), NULL);
422 * mono_domain_create_appdomain:
423 * @friendly_name: The friendly name of the appdomain to create
424 * @configuration_file: The configuration file to initialize the appdomain with
426 * Returns a MonoDomain initialized with the appdomain
429 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
433 MonoAppDomainSetup *setup;
436 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
437 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
440 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
442 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
446 return mono_domain_from_appdomain (ad);
448 mono_error_cleanup (&error);
453 * mono_domain_set_config:
454 * @domain: MonoDomain initialized with the appdomain we want to change
455 * @base_dir: new base directory for the appdomain
456 * @config_file_name: path to the new configuration for the app domain
458 * Used to set the system configuration for an appdomain
460 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
461 * Error Initializing the configuration system. ---> System.ArgumentException:
462 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
465 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
467 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
468 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
471 static MonoAppDomainSetup*
472 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
474 MonoDomain *caller_domain;
475 MonoClass *ads_class;
476 MonoAppDomainSetup *copy;
478 mono_error_init (error);
480 caller_domain = mono_domain_get ();
481 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
483 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
484 return_val_if_nok (error, NULL);
486 mono_domain_set_internal (domain);
488 MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
489 MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
490 MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
491 MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
492 MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
493 MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
494 MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
495 MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
496 MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
497 MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
498 copy->publisher_policy = setup->publisher_policy;
499 copy->path_changed = setup->path_changed;
500 copy->loader_optimization = setup->loader_optimization;
501 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
502 copy->disallow_code_downloads = setup->disallow_code_downloads;
503 MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
504 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
505 MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
506 MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
507 MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
509 mono_domain_set_internal (caller_domain);
514 static MonoAppDomain *
515 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
520 char *shadow_location;
522 mono_error_init (error);
524 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
526 /* FIXME: pin all those objects */
527 data = mono_domain_create();
529 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
530 return_val_if_nok (error, NULL);
533 data->friendly_name = g_strdup (friendly_name);
535 mono_profiler_appdomain_name (data, data->friendly_name);
537 if (!setup->application_base) {
538 /* Inherit from the root domain since MS.NET does this */
539 MonoDomain *root = mono_get_root_domain ();
540 if (root->setup->application_base) {
541 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
542 mono_error_assert_ok (error); /* FIXME don't swallow the error */
543 MONO_OBJECT_SETREF (setup, application_base, s);
547 mono_context_init_checked (data, error);
548 return_val_if_nok (error, NULL);
550 data->setup = copy_app_domain_setup (data, setup, error);
551 if (!mono_error_ok (error)) {
552 g_free (data->friendly_name);
556 mono_domain_set_options_from_config (data);
557 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
559 #ifndef DISABLE_SHADOW_COPY
560 /*FIXME, guard this for when the debugger is not running */
561 shadow_location = get_shadow_assembly_location_base (data, error);
562 if (!mono_error_ok (error)) {
563 g_free (data->friendly_name);
567 g_free (shadow_location);
570 create_domain_objects (data);
576 * mono_domain_has_type_resolve:
577 * @domain: application domains being looked up
579 * Returns: TRUE if the AppDomain.TypeResolve field has been
583 mono_domain_has_type_resolve (MonoDomain *domain)
585 static MonoClassField *field = NULL;
589 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
593 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
597 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
602 * mono_domain_try_type_resolve:
603 * @domain: application domainwhere the name where the type is going to be resolved
604 * @name: the name of the type to resolve or NULL.
605 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
607 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
608 * the assembly that matches name.
610 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
612 * Returns: A MonoReflectionAssembly or NULL if not found
614 MonoReflectionAssembly *
615 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
618 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
619 mono_error_cleanup (&error);
624 MonoReflectionAssembly *
625 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
627 static MonoMethod *method = NULL;
628 MonoReflectionAssembly *ret;
632 mono_error_init (error);
634 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
636 if (method == NULL) {
637 klass = domain->domain->mbr.obj.vtable->klass;
640 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
641 if (method == NULL) {
642 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
648 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
652 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
653 return_val_if_nok (error, NULL);
659 * mono_domain_owns_vtable_slot:
661 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
664 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
668 mono_domain_lock (domain);
669 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
670 mono_domain_unlock (domain);
677 * @force: force setting.
679 * Set the current appdomain to @domain. If @force is set, set it even
680 * if it is being unloaded.
684 * FALSE if the domain is unloaded
687 mono_domain_set (MonoDomain *domain, gboolean force)
689 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
692 mono_domain_set_internal (domain);
698 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
704 MONO_CHECK_ARG_NULL (name, NULL);
710 str = mono_string_to_utf8 (name);
712 mono_domain_lock (add);
714 if (!strcmp (str, "APPBASE"))
715 o = (MonoObject *)add->setup->application_base;
716 else if (!strcmp (str, "APP_CONFIG_FILE"))
717 o = (MonoObject *)add->setup->configuration_file;
718 else if (!strcmp (str, "DYNAMIC_BASE"))
719 o = (MonoObject *)add->setup->dynamic_base;
720 else if (!strcmp (str, "APP_NAME"))
721 o = (MonoObject *)add->setup->application_name;
722 else if (!strcmp (str, "CACHE_BASE"))
723 o = (MonoObject *)add->setup->cache_path;
724 else if (!strcmp (str, "PRIVATE_BINPATH"))
725 o = (MonoObject *)add->setup->private_bin_path;
726 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
727 o = (MonoObject *)add->setup->private_bin_path_probe;
728 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
729 o = (MonoObject *)add->setup->shadow_copy_directories;
730 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
731 o = (MonoObject *)add->setup->shadow_copy_files;
733 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
735 mono_domain_unlock (add);
745 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
749 MONO_CHECK_ARG_NULL (name,);
755 mono_domain_lock (add);
757 mono_g_hash_table_insert (add->env, name, data);
759 mono_domain_unlock (add);
763 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
768 return ad->data->setup;
772 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
777 return mono_string_new (ad->data, ad->data->friendly_name);
781 ves_icall_System_AppDomain_getCurDomain ()
783 MonoDomain *add = mono_domain_get ();
789 ves_icall_System_AppDomain_getRootDomain ()
791 MonoDomain *root = mono_get_root_domain ();
797 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
799 MonoDomain *domain = mono_domain_get ();
801 return domain->throw_unobserved_task_exceptions;
805 get_attribute_value (const gchar **attribute_names,
806 const gchar **attribute_values,
807 const char *att_name)
810 for (n = 0; attribute_names [n] != NULL; n++) {
811 if (strcmp (attribute_names [n], att_name) == 0)
812 return g_strdup (attribute_values [n]);
818 start_element (GMarkupParseContext *context,
819 const gchar *element_name,
820 const gchar **attribute_names,
821 const gchar **attribute_values,
825 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
827 if (strcmp (element_name, "runtime") == 0) {
828 runtime_config->runtime_count++;
832 if (strcmp (element_name, "assemblyBinding") == 0) {
833 runtime_config->assemblybinding_count++;
837 if (runtime_config->runtime_count != 1)
840 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
841 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
843 if (value && g_ascii_strcasecmp (value, "true") == 0)
844 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
847 if (runtime_config->assemblybinding_count != 1)
850 if (strcmp (element_name, "probing") != 0)
853 g_free (runtime_config->domain->private_bin_path);
854 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
855 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
856 g_free (runtime_config->domain->private_bin_path);
857 runtime_config->domain->private_bin_path = NULL;
863 end_element (GMarkupParseContext *context,
864 const gchar *element_name,
868 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
869 if (strcmp (element_name, "runtime") == 0)
870 runtime_config->runtime_count--;
871 else if (strcmp (element_name, "assemblyBinding") == 0)
872 runtime_config->assemblybinding_count--;
876 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
878 RuntimeConfig *state = (RuntimeConfig *)user_data;
880 const gchar *filename;
882 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
883 msg = error && error->message ? error->message : "";
884 g_warning ("Error parsing %s: %s", filename, msg);
887 static const GMarkupParser
897 mono_domain_set_options_from_config (MonoDomain *domain)
900 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
902 GMarkupParseContext *context;
903 RuntimeConfig runtime_config;
906 if (!domain || !domain->setup || !domain->setup->configuration_file)
909 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
910 if (!mono_error_ok (&error)) {
911 mono_error_cleanup (&error);
915 config_file_path = mono_portability_find_file (config_file_name, TRUE);
916 if (!config_file_path)
917 config_file_path = config_file_name;
919 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
922 runtime_config.runtime_count = 0;
923 runtime_config.assemblybinding_count = 0;
924 runtime_config.domain = domain;
925 runtime_config.filename = config_file_path;
928 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
929 offset = 3; /* Skip UTF-8 BOM */
931 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
932 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
933 g_markup_parse_context_end_parse (context, NULL);
934 g_markup_parse_context_free (context);
938 if (config_file_name != config_file_path)
939 g_free (config_file_name);
940 g_free (config_file_path);
944 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
947 MonoAppDomain *ad = NULL;
948 #ifdef DISABLE_APPDOMAINS
949 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
953 fname = mono_string_to_utf8 (friendly_name);
954 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
958 mono_error_set_pending_exception (&error);
963 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
966 MonoDomain *domain = ad->data;
971 GPtrArray *assemblies;
973 mono_error_init (&error);
976 * Make a copy of the list of assemblies because we can't hold the assemblies
977 * lock while creating objects etc.
979 assemblies = g_ptr_array_new ();
980 /* Need to skip internal assembly builders created by remoting */
981 mono_domain_assemblies_lock (domain);
982 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
983 ass = (MonoAssembly *)tmp->data;
984 if (refonly != ass->ref_only)
986 if (ass->corlib_internal)
988 g_ptr_array_add (assemblies, ass);
990 mono_domain_assemblies_unlock (domain);
992 res = mono_array_new (domain, mono_class_get_assembly_class (), assemblies->len);
993 for (i = 0; i < assemblies->len; ++i) {
994 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
995 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
996 if (!mono_error_ok (&error))
998 mono_array_setref (res, i, ass_obj);
1002 g_ptr_array_free (assemblies, TRUE);
1003 if (!mono_error_ok (&error))
1004 mono_error_set_pending_exception (&error);
1008 MonoReflectionAssembly *
1009 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1011 MonoReflectionAssembly *ret;
1014 MonoBoolean isrefonly;
1015 gpointer params [3];
1017 mono_error_init (error);
1019 if (mono_runtime_get_no_exec ())
1022 g_assert (domain != NULL && fname != NULL);
1024 klass = domain->domain->mbr.obj.vtable->klass;
1027 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1028 if (method == NULL) {
1029 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1033 isrefonly = refonly ? 1 : 0;
1036 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1037 return_val_if_nok (error, NULL);
1040 params [2] = &isrefonly;
1042 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1043 return_val_if_nok (error, NULL);
1049 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1053 MonoReflectionAssembly *assembly;
1054 MonoDomain *domain = mono_domain_get ();
1058 aname_str = mono_stringify_assembly_name (aname);
1060 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1061 str = mono_string_new (domain, aname_str);
1067 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1068 mono_error_cleanup (&error);
1071 return assembly->assembly;
1077 * LOCKING: assumes assemblies_lock in the domain is already locked.
1080 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1084 gboolean destroy_ht = FALSE;
1086 if (!ass->aname.name)
1090 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1094 /* FIXME: handle lazy loaded assemblies */
1095 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1096 g_hash_table_insert (ht, tmp->data, tmp->data);
1098 if (!g_hash_table_lookup (ht, ass)) {
1099 mono_assembly_addref (ass);
1100 g_hash_table_insert (ht, ass, ass);
1101 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1102 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);
1105 if (ass->image->references) {
1106 for (i = 0; ass->image->references [i] != NULL; i++) {
1107 if (ass->image->references [i] != REFERENCE_MISSING)
1108 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1109 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1114 g_hash_table_destroy (ht);
1118 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1120 static MonoClassField *assembly_load_field;
1121 static MonoMethod *assembly_load_method;
1123 MonoDomain *domain = mono_domain_get ();
1124 MonoReflectionAssembly *ref_assembly;
1126 gpointer load_value;
1129 if (!domain->domain)
1130 /* This can happen during startup */
1132 #ifdef ASSEMBLY_LOAD_DEBUG
1133 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1135 klass = domain->domain->mbr.obj.vtable->klass;
1137 mono_domain_assemblies_lock (domain);
1138 add_assemblies_to_domain (domain, assembly, NULL);
1139 mono_domain_assemblies_unlock (domain);
1141 if (assembly_load_field == NULL) {
1142 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1143 g_assert (assembly_load_field);
1146 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1147 if (load_value == NULL) {
1148 /* No events waiting to be triggered */
1152 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1153 mono_error_assert_ok (&error);
1155 if (assembly_load_method == NULL) {
1156 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1157 g_assert (assembly_load_method);
1160 *params = ref_assembly;
1162 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1163 mono_error_cleanup (&error);
1167 * LOCKING: Acquires the domain assemblies lock.
1170 set_domain_search_path (MonoDomain *domain)
1173 MonoAppDomainSetup *setup;
1175 gchar *search_path = NULL;
1178 gchar **pvt_split = NULL;
1179 GError *gerror = NULL;
1180 gint appbaselen = -1;
1183 * We use the low-level domain assemblies lock, since this is called from
1184 * assembly loads hooks, which means this thread might hold the loader lock.
1186 mono_domain_assemblies_lock (domain);
1188 if (!domain->setup) {
1189 mono_domain_assemblies_unlock (domain);
1193 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1194 mono_domain_assemblies_unlock (domain);
1197 setup = domain->setup;
1198 if (!setup->application_base) {
1199 mono_domain_assemblies_unlock (domain);
1200 return; /* Must set application base to get private path working */
1205 if (setup->private_bin_path) {
1206 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1207 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1208 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1209 mono_error_cleanup (&error);
1210 mono_domain_assemblies_unlock (domain);
1215 if (domain->private_bin_path) {
1216 if (search_path == NULL)
1217 search_path = domain->private_bin_path;
1219 gchar *tmp2 = search_path;
1220 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1227 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1228 * directories relative to ApplicationBase separated by semicolons (see
1229 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1230 * The loop below copes with the fact that some Unix applications may use ':' (or
1231 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1232 * ';' for the subsequent split.
1234 * The issue was reported in bug #81446
1237 #ifndef TARGET_WIN32
1240 slen = strlen (search_path);
1241 for (i = 0; i < slen; i++)
1242 if (search_path [i] == ':')
1243 search_path [i] = ';';
1246 pvt_split = g_strsplit (search_path, ";", 1000);
1247 g_free (search_path);
1248 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1253 g_strfreev (pvt_split);
1255 * Don't do this because the first time is called, the domain
1256 * setup is not finished.
1258 * domain->search_path = g_malloc (sizeof (char *));
1259 * domain->search_path [0] = NULL;
1261 mono_domain_assemblies_unlock (domain);
1265 if (domain->search_path)
1266 g_strfreev (domain->search_path);
1268 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1269 tmp [npaths] = NULL;
1271 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1272 if (!mono_error_ok (&error)) {
1273 mono_error_cleanup (&error);
1274 g_strfreev (pvt_split);
1277 mono_domain_assemblies_unlock (domain);
1281 domain->search_path = tmp;
1283 /* FIXME: is this needed? */
1284 if (strncmp (*tmp, "file://", 7) == 0) {
1290 uri = g_strdup_printf ("file:///%s", uri + 7);
1293 uri = mono_escape_uri_string (tmpuri);
1294 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1300 if (gerror != NULL) {
1301 g_warning ("%s\n", gerror->message);
1302 g_error_free (gerror);
1309 for (i = 1; pvt_split && i < npaths; i++) {
1310 if (g_path_is_absolute (pvt_split [i - 1])) {
1311 tmp [i] = g_strdup (pvt_split [i - 1]);
1313 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1316 if (strchr (tmp [i], '.')) {
1320 reduced = mono_path_canonicalize (tmp [i]);
1321 if (appbaselen == -1)
1322 appbaselen = strlen (tmp [0]);
1324 if (strncmp (tmp [0], reduced, appbaselen)) {
1327 tmp [i] = g_strdup ("");
1337 if (setup->private_bin_path_probe != NULL) {
1339 tmp [0] = g_strdup ("");
1342 domain->setup->path_changed = FALSE;
1344 g_strfreev (pvt_split);
1346 mono_domain_assemblies_unlock (domain);
1349 #ifdef DISABLE_SHADOW_COPY
1351 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1357 mono_make_shadow_copy (const char *filename, MonoError *error)
1359 mono_error_init (error);
1360 return (char *) filename;
1364 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1366 guint16 *orig, *dest;
1367 gboolean copy_result;
1369 strcpy (src + srclen - tail_len, extension);
1371 if (IS_PORTABILITY_CASE) {
1372 gchar *file = mono_portability_find_file (src, TRUE);
1378 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1382 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1384 strcpy (target + targetlen - tail_len, extension);
1385 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1388 copy_result = CopyFile (orig, dest, FALSE);
1390 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1391 * overwritten when updated in their original locations. */
1393 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1402 get_cstring_hash (const char *str)
1408 if (!str || !str [0])
1413 for (i = 0; i < len; i++) {
1414 h = (h << 5) - h + *p;
1422 * Returned memory is malloc'd. Called must free it
1425 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1427 MonoAppDomainSetup *setup;
1428 char *cache_path, *appname;
1432 mono_error_init (error);
1434 setup = domain->setup;
1435 if (setup->cache_path != NULL && setup->application_name != NULL) {
1436 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1437 return_val_if_nok (error, NULL);
1439 #ifndef TARGET_WIN32
1442 for (i = strlen (cache_path) - 1; i >= 0; i--)
1443 if (cache_path [i] == '\\')
1444 cache_path [i] = '/';
1448 appname = mono_string_to_utf8_checked (setup->application_name, error);
1449 if (!mono_error_ok (error)) {
1450 g_free (cache_path);
1454 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1456 g_free (cache_path);
1458 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1459 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1466 get_shadow_assembly_location (const char *filename, MonoError *error)
1468 gint32 hash = 0, hash2 = 0;
1470 char path_hash [30];
1471 char *bname = g_path_get_basename (filename);
1472 char *dirname = g_path_get_dirname (filename);
1473 char *location, *tmploc;
1474 MonoDomain *domain = mono_domain_get ();
1476 mono_error_init (error);
1478 hash = get_cstring_hash (bname);
1479 hash2 = get_cstring_hash (dirname);
1480 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1481 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1482 tmploc = get_shadow_assembly_location_base (domain, error);
1483 if (!mono_error_ok (error)) {
1489 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1497 ensure_directory_exists (const char *filename)
1500 gchar *dir_utf8 = g_path_get_dirname (filename);
1502 gunichar2 *dir_utf16 = NULL;
1505 if (!dir_utf8 || !dir_utf8 [0])
1508 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1516 /* make life easy and only use one directory seperator */
1527 while (*p++ != '\\')
1533 p = wcschr (p, '\\');
1536 retval = _wmkdir (dir_utf16);
1537 if (retval != 0 && errno != EEXIST) {
1550 gchar *dir = g_path_get_dirname (filename);
1554 if (!dir || !dir [0]) {
1559 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1569 p = strchr (p, '/');
1572 retval = mkdir (dir, 0777);
1573 if (retval != 0 && errno != EEXIST) {
1588 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1590 struct stat sbuf_dest;
1592 gchar *real_src = mono_portability_find_file (src, TRUE);
1595 stat_src = (gchar*)src;
1597 stat_src = real_src;
1599 if (stat (stat_src, sbuf_src) == -1) {
1600 time_t tnow = time (NULL);
1605 memset (sbuf_src, 0, sizeof (*sbuf_src));
1606 sbuf_src->st_mtime = tnow;
1607 sbuf_src->st_atime = tnow;
1614 if (stat (dest, &sbuf_dest) == -1)
1617 if (sbuf_src->st_size == sbuf_dest.st_size &&
1618 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1625 shadow_copy_create_ini (const char *shadow, const char *filename)
1635 dir_name = g_path_get_dirname (shadow);
1636 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1638 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1643 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1648 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1649 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1651 if (handle == INVALID_HANDLE_VALUE) {
1655 full_path = mono_path_resolve_symlinks (filename);
1656 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1658 CloseHandle (handle);
1663 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1666 MonoAppDomainSetup *setup;
1669 gchar **directories;
1670 gchar *shadow_status_string;
1672 gboolean shadow_enabled;
1673 gboolean found = FALSE;
1678 setup = domain->setup;
1679 if (setup == NULL || setup->shadow_copy_files == NULL)
1682 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1683 if (!mono_error_ok (&error)) {
1684 mono_error_cleanup (&error);
1687 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1688 g_free (shadow_status_string);
1690 if (!shadow_enabled)
1693 if (setup->shadow_copy_directories == NULL)
1696 /* Is dir_name a shadow_copy destination already? */
1697 base_dir = get_shadow_assembly_location_base (domain, &error);
1698 if (!mono_error_ok (&error)) {
1699 mono_error_cleanup (&error);
1703 if (strstr (dir_name, base_dir)) {
1709 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1710 if (!mono_error_ok (&error)) {
1711 mono_error_cleanup (&error);
1715 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1716 dir_ptr = directories;
1718 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1724 g_strfreev (directories);
1730 This function raises exceptions so it can cause as sorts of nasty stuff if called
1731 while holding a lock.
1732 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1733 or NULL if source file not found.
1734 FIXME bubble up the error instead of raising it here
1737 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1740 gchar *sibling_source, *sibling_target;
1741 gint sibling_source_len, sibling_target_len;
1742 guint16 *orig, *dest;
1745 gboolean copy_result;
1746 struct stat src_sbuf;
1747 struct utimbuf utbuf;
1748 char *dir_name = g_path_get_dirname (filename);
1749 MonoDomain *domain = mono_domain_get ();
1752 mono_error_init (oerror);
1754 set_domain_search_path (domain);
1756 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1758 return (char *) filename;
1761 /* Is dir_name a shadow_copy destination already? */
1762 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1763 if (!mono_error_ok (&error)) {
1764 mono_error_cleanup (&error);
1766 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1770 if (strstr (dir_name, shadow_dir)) {
1771 g_free (shadow_dir);
1773 return (char *) filename;
1775 g_free (shadow_dir);
1778 shadow = get_shadow_assembly_location (filename, &error);
1779 if (!mono_error_ok (&error)) {
1780 mono_error_cleanup (&error);
1781 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1785 if (ensure_directory_exists (shadow) == FALSE) {
1787 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1791 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1792 return (char*) shadow;
1794 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1795 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1798 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1799 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1800 * and not have it runtime error" */
1801 attrs = GetFileAttributes (orig);
1802 if (attrs == INVALID_FILE_ATTRIBUTES) {
1804 return (char *)filename;
1807 copy_result = CopyFile (orig, dest, FALSE);
1809 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1810 * overwritten when updated in their original locations. */
1812 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1817 if (copy_result == FALSE) {
1820 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1821 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1822 return NULL; /* file not found, shadow copy failed */
1824 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1828 /* attempt to copy .mdb, .config if they exist */
1829 sibling_source = g_strconcat (filename, ".config", NULL);
1830 sibling_source_len = strlen (sibling_source);
1831 sibling_target = g_strconcat (shadow, ".config", NULL);
1832 sibling_target_len = strlen (sibling_target);
1834 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1835 if (copy_result == TRUE)
1836 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1838 g_free (sibling_source);
1839 g_free (sibling_target);
1841 if (copy_result == FALSE) {
1843 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1847 /* Create a .ini file containing the original assembly location */
1848 if (!shadow_copy_create_ini (shadow, filename)) {
1850 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1854 utbuf.actime = src_sbuf.st_atime;
1855 utbuf.modtime = src_sbuf.st_mtime;
1856 utime (shadow, &utbuf);
1860 #endif /* DISABLE_SHADOW_COPY */
1863 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1865 if (appdomain == NULL)
1868 return appdomain->data;
1872 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1873 const gchar *path3, const gchar *path4,
1874 gboolean refonly, gboolean is_private)
1877 gboolean found = FALSE;
1880 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1882 if (IS_PORTABILITY_SET) {
1883 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1886 fullpath = new_fullpath;
1890 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1893 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1896 return (*assembly != NULL);
1899 static MonoAssembly *
1900 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1902 MonoAssembly *result = NULL;
1905 const gchar *local_culture;
1907 gboolean is_private = FALSE;
1909 if (!culture || *culture == '\0') {
1912 local_culture = culture;
1915 filename = g_strconcat (name, ".dll", NULL);
1916 len = strlen (filename);
1918 for (path = search_path; *path; path++) {
1919 if (**path == '\0') {
1921 continue; /* Ignore empty ApplicationBase */
1924 /* See test cases in bug #58992 and bug #57710 */
1925 /* 1st try: [culture]/[name].dll (culture may be empty) */
1926 strcpy (filename + len - 4, ".dll");
1927 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1930 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1931 strcpy (filename + len - 4, ".exe");
1932 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1935 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1936 strcpy (filename + len - 4, ".dll");
1937 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1940 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1941 strcpy (filename + len - 4, ".exe");
1942 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1951 * Try loading the assembly from ApplicationBase and PrivateBinPath
1952 * and then from assemblies_path if any.
1953 * LOCKING: This is called from the assembly loading code, which means the caller
1954 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1956 static MonoAssembly *
1957 mono_domain_assembly_preload (MonoAssemblyName *aname,
1958 gchar **assemblies_path,
1961 MonoDomain *domain = mono_domain_get ();
1962 MonoAssembly *result = NULL;
1963 gboolean refonly = GPOINTER_TO_UINT (user_data);
1965 set_domain_search_path (domain);
1967 if (domain->search_path && domain->search_path [0] != NULL) {
1968 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1971 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1972 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1979 * Check whenever a given assembly was already loaded in the current appdomain.
1981 static MonoAssembly *
1982 mono_domain_assembly_search (MonoAssemblyName *aname,
1985 MonoDomain *domain = mono_domain_get ();
1988 gboolean refonly = GPOINTER_TO_UINT (user_data);
1990 mono_domain_assemblies_lock (domain);
1991 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1992 ass = (MonoAssembly *)tmp->data;
1993 /* Dynamic assemblies can't match here in MS.NET */
1994 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1997 mono_domain_assemblies_unlock (domain);
2000 mono_domain_assemblies_unlock (domain);
2005 MonoReflectionAssembly *
2006 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
2009 MonoReflectionAssembly *result;
2010 MonoDomain *domain = mono_domain_get ();
2011 char *name, *filename;
2012 MonoImageOpenStatus status = MONO_IMAGE_OK;
2015 if (fname == NULL) {
2016 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
2017 mono_set_pending_exception (exc);
2021 name = filename = mono_string_to_utf8 (fname);
2023 ass = mono_assembly_open_full (filename, &status, refOnly);
2028 if (status == MONO_IMAGE_IMAGE_INVALID)
2029 exc = mono_get_exception_bad_image_format2 (NULL, fname);
2031 exc = mono_get_exception_file_not_found2 (NULL, fname);
2033 mono_set_pending_exception (exc);
2039 result = mono_assembly_get_object_checked (domain, ass, &error);
2041 mono_error_set_pending_exception (&error);
2045 MonoReflectionAssembly *
2046 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
2047 MonoArray *raw_assembly,
2048 MonoArray *raw_symbol_store, MonoObject *evidence,
2049 MonoBoolean refonly)
2053 MonoReflectionAssembly *refass = NULL;
2054 MonoDomain *domain = ad->data;
2055 MonoImageOpenStatus status;
2056 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2057 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2060 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2064 if (raw_symbol_store != NULL)
2065 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2067 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2071 mono_image_close (image);
2072 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2076 refass = mono_assembly_get_object_checked (domain, ass, &error);
2078 mono_error_set_pending_exception (&error);
2080 MONO_OBJECT_SETREF (refass, evidence, evidence);
2084 MonoReflectionAssembly *
2085 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2088 MonoDomain *domain = ad->data;
2089 MonoImageOpenStatus status = MONO_IMAGE_OK;
2091 MonoAssemblyName aname;
2092 MonoReflectionAssembly *refass = NULL;
2098 name = mono_string_to_utf8 (assRef);
2099 parsed = mono_assembly_name_parse (name, &aname);
2103 /* This is a parse error... */
2105 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2106 if (!mono_error_ok (&error)) {
2107 mono_error_set_pending_exception (&error);
2114 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2115 mono_assembly_name_free (&aname);
2118 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2120 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2121 if (!mono_error_ok (&error)) {
2122 mono_error_set_pending_exception (&error);
2134 refass = mono_assembly_get_object_checked (domain, ass, &error);
2137 mono_error_set_pending_exception (&error);
2139 MONO_OBJECT_SETREF (refass, evidence, evidence);
2144 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2146 MonoException *exc = NULL;
2147 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2149 if (NULL == domain) {
2150 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2151 mono_set_pending_exception (exc);
2155 if (domain == mono_get_root_domain ()) {
2156 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2161 * Unloading seems to cause problems when running NUnit/NAnt, hence
2164 if (g_getenv ("MONO_NO_UNLOAD"))
2166 #ifdef __native_client__
2170 mono_domain_try_unload (domain, (MonoObject**)&exc);
2172 mono_set_pending_exception (exc);
2176 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2178 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2183 return mono_domain_is_unloading (domain);
2187 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2189 mono_unhandled_exception ((MonoObject*) exc);
2193 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2194 MonoReflectionAssembly *refass, MonoArray *args)
2201 image = refass->assembly->image;
2204 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2207 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2210 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
2212 return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
2216 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2218 return ad->data->domain_id;
2222 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2224 MonoDomain *old_domain = mono_domain_get();
2226 if (!mono_domain_set (ad->data, FALSE)) {
2227 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2231 return old_domain->domain;
2235 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2237 MonoDomain *current_domain = mono_domain_get ();
2238 MonoDomain *domain = mono_domain_get_by_id (domainid);
2240 if (!domain || !mono_domain_set (domain, FALSE)) {
2241 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2245 return current_domain->domain;
2249 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2251 mono_thread_push_appdomain_ref (ad->data);
2255 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2257 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2261 * Raise an exception to prevent the managed code from executing a pop
2264 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2268 mono_thread_push_appdomain_ref (domain);
2272 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2274 mono_thread_pop_appdomain_ref ();
2278 ves_icall_System_AppDomain_InternalGetContext ()
2280 return mono_context_get ();
2284 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2286 return mono_domain_get ()->default_context;
2290 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2292 MonoAppContext *old_context = mono_context_get ();
2294 mono_context_set (mc);
2300 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2302 MonoDomain* mono_root_domain = mono_get_root_domain ();
2303 mono_domain_lock (mono_root_domain);
2304 if (process_guid_set) {
2305 mono_domain_unlock (mono_root_domain);
2307 MonoString *res = NULL;
2308 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2309 mono_error_set_pending_exception (&error);
2312 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2313 process_guid_set = TRUE;
2314 mono_domain_unlock (mono_root_domain);
2319 mono_domain_is_unloading (MonoDomain *domain)
2321 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2328 clear_cached_vtable (MonoVTable *vtable)
2330 MonoClass *klass = vtable->klass;
2331 MonoDomain *domain = vtable->domain;
2332 MonoClassRuntimeInfo *runtime_info;
2335 runtime_info = klass->runtime_info;
2336 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2337 runtime_info->domain_vtables [domain->domain_id] = NULL;
2338 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2339 mono_gc_free_fixed (data);
2342 static G_GNUC_UNUSED void
2343 zero_static_data (MonoVTable *vtable)
2345 MonoClass *klass = vtable->klass;
2348 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2349 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2352 typedef struct unload_data {
2355 char *failure_reason;
2360 unload_data_unref (unload_data *data)
2364 mono_atomic_load_acquire (count, gint32, &data->refcount);
2365 g_assert (count >= 1 && count <= 2);
2370 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2374 deregister_reflection_info_roots_from_list (MonoImage *image)
2376 GSList *list = image->reflection_info_unregister_classes;
2379 MonoClass *klass = (MonoClass *)list->data;
2381 mono_class_free_ref_info (klass);
2386 image->reflection_info_unregister_classes = NULL;
2390 deregister_reflection_info_roots (MonoDomain *domain)
2394 mono_domain_assemblies_lock (domain);
2395 for (list = domain->domain_assemblies; list; list = list->next) {
2396 MonoAssembly *assembly = (MonoAssembly *)list->data;
2397 MonoImage *image = assembly->image;
2401 * No need to take the image lock here since dynamic images are appdomain bound and
2402 * at this point the mutator is gone. Taking the image lock here would mean
2403 * promoting it from a simple lock to a complex lock, which we better avoid if
2406 if (image_is_dynamic (image))
2407 deregister_reflection_info_roots_from_list (image);
2409 for (i = 0; i < image->module_count; ++i) {
2410 MonoImage *module = image->modules [i];
2411 if (module && image_is_dynamic (module))
2412 deregister_reflection_info_roots_from_list (module);
2415 mono_domain_assemblies_unlock (domain);
2418 static guint32 WINAPI
2419 unload_thread_main (void *arg)
2422 unload_data *data = (unload_data*)arg;
2423 MonoDomain *domain = data->domain;
2427 /* Have to attach to the runtime so shutdown can wait for this thread */
2428 /* Force it to be attached to avoid racing during shutdown. */
2429 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
2430 if (!is_ok (&error)) {
2431 data->failure_reason = g_strdup (mono_error_get_message (&error));
2432 mono_error_cleanup (&error);
2435 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2436 if (!is_ok (&error)) {
2437 data->failure_reason = g_strdup (mono_error_get_message (&error));
2438 mono_error_cleanup (&error);
2443 * FIXME: Abort our parent thread last, so we can return a failure
2444 * indication if aborting times out.
2446 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2447 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2451 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2452 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2456 /* Finalize all finalizable objects in the doomed appdomain */
2457 if (!mono_domain_finalize (domain, -1)) {
2458 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2462 /* Clear references to our vtables in class->runtime_info.
2463 * We also hold the loader lock because we're going to change
2464 * class->runtime_info.
2467 mono_loader_lock (); //FIXME why do we need the loader lock here?
2468 mono_domain_lock (domain);
2471 * We need to make sure that we don't have any remsets
2472 * pointing into static data of the to-be-freed domain because
2473 * at the next collections they would be invalid. So what we
2474 * do is we first zero all static data and then do a minor
2475 * collection. Because all references in the static data will
2476 * now be null we won't do any unnecessary copies and after
2477 * the collection there won't be any more remsets.
2479 for (i = 0; i < domain->class_vtable_array->len; ++i)
2480 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2481 mono_gc_collect (0);
2483 for (i = 0; i < domain->class_vtable_array->len; ++i)
2484 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2485 deregister_reflection_info_roots (domain);
2487 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2489 mono_domain_unlock (domain);
2490 mono_loader_unlock ();
2492 mono_threads_clear_cached_culture (domain);
2494 domain->state = MONO_APPDOMAIN_UNLOADED;
2496 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2498 /* remove from the handle table the items related to this domain */
2499 mono_gchandle_free_domain (domain);
2501 mono_domain_free (domain, FALSE);
2503 mono_gc_collect (mono_gc_max_generation ());
2505 mono_atomic_store_release (&data->done, TRUE);
2506 unload_data_unref (data);
2507 mono_thread_detach (thread);
2511 mono_atomic_store_release (&data->done, TRUE);
2512 unload_data_unref (data);
2513 mono_thread_detach (thread);
2518 * mono_domain_unload:
2519 * @domain: The domain to unload
2521 * Unloads an appdomain. Follows the process outlined in the comment
2522 * for mono_domain_try_unload.
2525 mono_domain_unload (MonoDomain *domain)
2527 MonoObject *exc = NULL;
2528 mono_domain_try_unload (domain, &exc);
2532 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2536 MONO_PREPARE_BLOCKING;
2537 result = WaitForSingleObjectEx (handle, timeout, alertable);
2538 MONO_FINISH_BLOCKING;
2544 * mono_domain_unload:
2545 * @domain: The domain to unload
2546 * @exc: Exception information
2548 * Unloads an appdomain. Follows the process outlined in:
2549 * http://blogs.gotdotnet.com/cbrumme
2551 * If doing things the 'right' way is too hard or complex, we do it the
2552 * 'simple' way, which means do everything needed to avoid crashes and
2553 * memory leaks, but not much else.
2555 * It is required to pass a valid reference to the exc argument, upon return
2556 * from this function *exc will be set to the exception thrown, if any.
2558 * If this method is not called from an icall (embedded scenario for instance),
2559 * it must not be called with any managed frames on the stack, since the unload
2560 * process could end up trying to abort the current thread.
2563 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2566 HANDLE thread_handle;
2567 MonoAppDomainState prev_state;
2569 unload_data *thread_data;
2570 MonoNativeThreadId tid;
2571 MonoDomain *caller_domain = mono_domain_get ();
2574 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2576 /* Atomically change our state to UNLOADING */
2577 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2578 MONO_APPDOMAIN_UNLOADING_START,
2579 MONO_APPDOMAIN_CREATED);
2580 if (prev_state != MONO_APPDOMAIN_CREATED) {
2581 switch (prev_state) {
2582 case MONO_APPDOMAIN_UNLOADING_START:
2583 case MONO_APPDOMAIN_UNLOADING:
2584 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2586 case MONO_APPDOMAIN_UNLOADED:
2587 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2590 g_warning ("Invalid appdomain state %d", prev_state);
2591 g_assert_not_reached ();
2595 mono_domain_set (domain, FALSE);
2596 /* Notify OnDomainUnload listeners */
2597 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2600 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2602 if (!mono_error_ok (&error)) {
2604 mono_error_cleanup (&error);
2606 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2610 /* Roll back the state change */
2611 domain->state = MONO_APPDOMAIN_CREATED;
2612 mono_domain_set (caller_domain, FALSE);
2615 mono_domain_set (caller_domain, FALSE);
2617 thread_data = g_new0 (unload_data, 1);
2618 thread_data->domain = domain;
2619 thread_data->failure_reason = NULL;
2620 thread_data->done = FALSE;
2621 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2623 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2624 domain->state = MONO_APPDOMAIN_UNLOADING;
2626 * First we create a separate thread for unloading, since
2627 * we might have to abort some threads, including the current one.
2629 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)unload_thread_main, thread_data, 0, CREATE_SUSPENDED, &tid);
2630 if (thread_handle == NULL)
2632 name = g_strdup_printf ("Unload thread for domain %x", domain);
2633 mono_thread_info_set_name (tid, name);
2634 mono_thread_info_resume (tid);
2637 /* Wait for the thread */
2638 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2639 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2640 /* The unload thread tries to abort us */
2641 /* The icall wrapper will execute the abort */
2642 CloseHandle (thread_handle);
2643 unload_data_unref (thread_data);
2647 CloseHandle (thread_handle);
2649 if (thread_data->failure_reason) {
2650 /* Roll back the state change */
2651 domain->state = MONO_APPDOMAIN_CREATED;
2653 g_warning ("%s", thread_data->failure_reason);
2655 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2657 g_free (thread_data->failure_reason);
2658 thread_data->failure_reason = NULL;
2661 unload_data_unref (thread_data);