[threads] Factor common attach code in mono_thread_attach_internal (#3530)
[mono-project.git] / mono / metadata / appdomain.c
blob79c8406d46f11f8706ebe024dfd451fcc5918e6f
1 /*
2 * appdomain.c: AppDomain functions
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Patrik Torstensson
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
15 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_UTIME_H
29 #include <utime.h>
30 #else
31 #ifdef HAVE_SYS_UTIME_H
32 #include <sys/utime.h>
33 #endif
34 #endif
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/exception-internals.h>
43 #include <mono/metadata/threads.h>
44 #include <mono/metadata/threadpool-ms.h>
45 #include <mono/metadata/socket-io.h>
46 #include <mono/metadata/tabledefs.h>
47 #include <mono/metadata/gc-internals.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/file-io.h>
55 #include <mono/metadata/lock-tracer.h>
56 #include <mono/metadata/console-io.h>
57 #include <mono/metadata/threads-types.h>
58 #include <mono/metadata/tokentype.h>
59 #include <mono/metadata/profiler-private.h>
60 #include <mono/metadata/reflection-internals.h>
61 #include <mono/utils/mono-uri.h>
62 #include <mono/utils/mono-logger-internals.h>
63 #include <mono/utils/mono-path.h>
64 #include <mono/utils/mono-stdlib.h>
65 #include <mono/utils/mono-io-portability.h>
66 #include <mono/utils/mono-error-internals.h>
67 #include <mono/utils/atomic.h>
68 #include <mono/utils/mono-memory-model.h>
69 #include <mono/utils/mono-threads.h>
70 #include <mono/utils/w32handle.h>
71 #ifdef HOST_WIN32
72 #include <direct.h>
73 #endif
76 * This is the version number of the corlib-runtime interface. When
77 * making changes to this interface (by changing the layout
78 * of classes the runtime knows about, changing icall signature or
79 * semantics etc), increment this variable. Also increment the
80 * pair of this variable in mscorlib in:
81 * mcs/class/corlib/System/Environment.cs
83 * Changes which are already detected at runtime, like the addition
84 * of icalls, do not require an increment.
86 #define MONO_CORLIB_VERSION 154
88 typedef struct
90 int runtime_count;
91 int assemblybinding_count;
92 MonoDomain *domain;
93 gchar *filename;
94 } RuntimeConfig;
96 static gunichar2 process_guid [36];
97 static gboolean process_guid_set = FALSE;
99 static gboolean no_exec = FALSE;
101 static MonoAssembly *
102 mono_domain_assembly_preload (MonoAssemblyName *aname,
103 gchar **assemblies_path,
104 gpointer user_data);
106 static MonoAssembly *
107 mono_domain_assembly_search (MonoAssemblyName *aname,
108 gpointer user_data);
110 static void
111 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
113 static void
114 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
116 static MonoAppDomain *
117 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error);
119 static char *
120 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
122 static MonoLoadFunc load_function = NULL;
124 /* Lazy class loading functions */
125 static GENERATE_GET_CLASS_WITH_CACHE (assembly, System.Reflection, Assembly)
127 void
128 mono_install_runtime_load (MonoLoadFunc func)
130 load_function = func;
133 MonoDomain*
134 mono_runtime_load (const char *filename, const char *runtime_version)
136 g_assert (load_function);
137 return load_function (filename, runtime_version);
141 * mono_runtime_set_no_exec:
143 * Instructs the runtime to operate in static mode, i.e. avoid/do not
144 * allow managed code execution. This is useful for running the AOT
145 * compiler on platforms which allow full-aot execution only. This
146 * should be called before mono_runtime_init ().
148 void
149 mono_runtime_set_no_exec (gboolean val)
151 no_exec = val;
155 * mono_runtime_get_no_exec:
157 * If true, then the runtime will not allow managed code execution.
159 gboolean
160 mono_runtime_get_no_exec (void)
162 return no_exec;
165 static void
166 create_domain_objects (MonoDomain *domain)
168 MonoError error;
169 MonoDomain *old_domain = mono_domain_get ();
170 MonoString *arg;
171 MonoVTable *string_vt;
172 MonoClassField *string_empty_fld;
174 if (domain != old_domain) {
175 mono_thread_push_appdomain_ref (domain);
176 mono_domain_set_internal_with_options (domain, FALSE);
180 * Initialize String.Empty. This enables the removal of
181 * the static cctor of the String class.
183 string_vt = mono_class_vtable (domain, mono_defaults.string_class);
184 string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
185 g_assert (string_empty_fld);
186 MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
187 mono_error_assert_ok (&error);
188 mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
191 * Create an instance early since we can't do it when there is no memory.
193 arg = mono_string_new (domain, "Out of memory");
194 domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
195 mono_error_assert_ok (&error);
198 * These two are needed because the signal handlers might be executing on
199 * an alternate stack, and Boehm GC can't handle that.
201 arg = mono_string_new (domain, "A null value was found where an object instance was required");
202 domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
203 mono_error_assert_ok (&error);
204 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
205 domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
206 mono_error_assert_ok (&error);
208 /*The ephemeron tombstone i*/
209 domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
210 mono_error_assert_ok (&error);
212 if (domain != old_domain) {
213 mono_thread_pop_appdomain_ref ();
214 mono_domain_set_internal_with_options (old_domain, FALSE);
218 * This class is used during exception handling, so initialize it here, to prevent
219 * stack overflows while handling stack overflows.
221 mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
225 * mono_runtime_init:
226 * @domain: domain returned by mono_init ()
228 * Initialize the core AppDomain: this function will run also some
229 * IL initialization code, so it needs the execution engine to be fully
230 * operational.
232 * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
233 * we know the entry_assembly.
236 void
237 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
239 MonoError error;
240 mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
241 mono_error_cleanup (&error);
244 void
245 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
247 MonoAppDomainSetup *setup;
248 MonoAppDomain *ad;
249 MonoClass *klass;
251 mono_error_init (error);
253 mono_portability_helpers_init ();
255 mono_gc_base_init ();
256 mono_monitor_init ();
257 mono_marshal_init ();
259 mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
260 mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
261 mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
262 mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
263 mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
264 mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
265 mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
267 mono_thread_init (start_cb, attach_cb);
269 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
270 setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
271 return_if_nok (error);
273 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
275 ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
276 return_if_nok (error);
278 ad->data = domain;
279 domain->domain = ad;
280 domain->setup = setup;
282 mono_thread_attach (domain);
284 mono_type_initialization_init ();
286 if (!mono_runtime_get_no_exec ())
287 create_domain_objects (domain);
289 /* GC init has to happen after thread init */
290 mono_gc_init ();
292 /* contexts use GC handles, so they must be initialized after the GC */
293 mono_context_init_checked (domain, error);
294 return_if_nok (error);
295 mono_context_set (domain->default_context);
297 #ifndef DISABLE_SOCKETS
298 mono_network_init ();
299 #endif
301 mono_console_init ();
302 mono_attach_init ();
304 mono_locks_tracer_init ();
306 /* mscorlib is loaded before we install the load hook */
307 mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
309 return;
312 static int
313 mono_get_corlib_version (void)
315 MonoError error;
316 MonoClass *klass;
317 MonoClassField *field;
318 MonoObject *value;
320 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
321 mono_class_init (klass);
322 field = mono_class_get_field_from_name (klass, "mono_corlib_version");
323 if (!field)
324 return -1;
325 if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
326 return -1;
327 value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
328 mono_error_assert_ok (&error);
329 return *(gint32*)((gchar*)value + sizeof (MonoObject));
333 * mono_check_corlib_version
335 * Checks that the corlib that is loaded matches the version of this runtime.
337 * Returns: NULL if the runtime will work with the corlib, or a g_malloc
338 * allocated string with the error otherwise.
340 const char*
341 mono_check_corlib_version (void)
343 int version = mono_get_corlib_version ();
344 if (version != MONO_CORLIB_VERSION)
345 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
346 else
347 return NULL;
351 * mono_context_init:
352 * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
354 * Initializes the @domain's default System.Runtime.Remoting's Context.
356 void
357 mono_context_init (MonoDomain *domain)
359 MonoError error;
360 mono_context_init_checked (domain, &error);
361 mono_error_cleanup (&error);
364 void
365 mono_context_init_checked (MonoDomain *domain, MonoError *error)
367 MonoClass *klass;
368 MonoAppContext *context;
370 mono_error_init (error);
372 klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
373 context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
374 return_if_nok (error);
376 context->domain_id = domain->domain_id;
377 context->context_id = 0;
378 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
379 domain->default_context = context;
383 * mono_runtime_cleanup:
384 * @domain: unused.
386 * Internal routine.
388 * This must not be called while there are still running threads executing
389 * managed code.
391 void
392 mono_runtime_cleanup (MonoDomain *domain)
394 mono_attach_cleanup ();
396 /* This ends up calling any pending pending (for at most 2 seconds) */
397 mono_gc_cleanup ();
399 mono_thread_cleanup ();
401 #ifndef DISABLE_SOCKETS
402 mono_network_cleanup ();
403 #endif
404 mono_marshal_cleanup ();
406 mono_type_initialization_cleanup ();
408 mono_monitor_cleanup ();
411 static MonoDomainFunc quit_function = NULL;
413 void
414 mono_install_runtime_cleanup (MonoDomainFunc func)
416 quit_function = func;
419 void
420 mono_runtime_quit ()
422 if (quit_function != NULL)
423 quit_function (mono_get_root_domain (), NULL);
427 * mono_domain_create_appdomain:
428 * @friendly_name: The friendly name of the appdomain to create
429 * @configuration_file: The configuration file to initialize the appdomain with
431 * Returns a MonoDomain initialized with the appdomain
433 MonoDomain *
434 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
436 MonoError error;
437 MonoAppDomain *ad;
438 MonoAppDomainSetup *setup;
439 MonoClass *klass;
441 klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
442 setup = (MonoAppDomainSetup *) mono_object_new_checked (mono_domain_get (), klass, &error);
443 if (!is_ok (&error))
444 goto fail;
445 setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
447 ad = mono_domain_create_appdomain_internal (friendly_name, setup, &error);
448 if (!is_ok (&error))
449 goto fail;
451 return mono_domain_from_appdomain (ad);
452 fail:
453 mono_error_cleanup (&error);
454 return NULL;
458 * mono_domain_set_config:
459 * @domain: MonoDomain initialized with the appdomain we want to change
460 * @base_dir: new base directory for the appdomain
461 * @config_file_name: path to the new configuration for the app domain
463 * Used to set the system configuration for an appdomain
465 * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException:
466 * Error Initializing the configuration system. ---> System.ArgumentException:
467 * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
469 void
470 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
472 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
473 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
476 static MonoAppDomainSetup*
477 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup, MonoError *error)
479 MonoDomain *caller_domain;
480 MonoClass *ads_class;
481 MonoAppDomainSetup *copy;
483 mono_error_init (error);
485 caller_domain = mono_domain_get ();
486 ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
488 copy = (MonoAppDomainSetup*)mono_object_new_checked (domain, ads_class, error);
489 return_val_if_nok (error, NULL);
491 mono_domain_set_internal (domain);
493 #define XCOPY_FIELD(dst,field,src,error) \
494 do { \
495 MonoObject *copied_val = mono_marshal_xdomain_copy_value ((MonoObject*)(src), error); \
496 return_val_if_nok (error, NULL); \
497 MONO_OBJECT_SETREF ((dst),field,copied_val); \
498 } while (0)
500 XCOPY_FIELD (copy, application_base, setup->application_base, error);
501 XCOPY_FIELD (copy, application_name, setup->application_name, error);
502 XCOPY_FIELD (copy, cache_path, setup->cache_path, error);
503 XCOPY_FIELD (copy, configuration_file, setup->configuration_file, error);
504 XCOPY_FIELD (copy, dynamic_base, setup->dynamic_base, error);
505 XCOPY_FIELD (copy, license_file, setup->license_file, error);
506 XCOPY_FIELD (copy, private_bin_path, setup->private_bin_path, error);
507 XCOPY_FIELD (copy, private_bin_path_probe, setup->private_bin_path_probe, error);
508 XCOPY_FIELD (copy, shadow_copy_directories, setup->shadow_copy_directories, error);
509 XCOPY_FIELD (copy, shadow_copy_files, setup->shadow_copy_files, error);
510 copy->publisher_policy = setup->publisher_policy;
511 copy->path_changed = setup->path_changed;
512 copy->loader_optimization = setup->loader_optimization;
513 copy->disallow_binding_redirects = setup->disallow_binding_redirects;
514 copy->disallow_code_downloads = setup->disallow_code_downloads;
515 XCOPY_FIELD (copy, domain_initializer_args, setup->domain_initializer_args, error);
516 copy->disallow_appbase_probe = setup->disallow_appbase_probe;
517 XCOPY_FIELD (copy, application_trust, setup->application_trust, error);
518 XCOPY_FIELD (copy, configuration_bytes, setup->configuration_bytes, error);
519 XCOPY_FIELD (copy, serialized_non_primitives, setup->serialized_non_primitives, error);
521 #undef COPY_FIELD
523 mono_domain_set_internal (caller_domain);
525 return copy;
528 static MonoAppDomain *
529 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup, MonoError *error)
531 MonoClass *adclass;
532 MonoAppDomain *ad;
533 MonoDomain *data;
534 char *shadow_location;
536 mono_error_init (error);
538 adclass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
540 /* FIXME: pin all those objects */
541 data = mono_domain_create();
543 ad = (MonoAppDomain *) mono_object_new_checked (data, adclass, error);
544 return_val_if_nok (error, NULL);
545 ad->data = data;
546 data->domain = ad;
547 data->friendly_name = g_strdup (friendly_name);
549 mono_profiler_appdomain_name (data, data->friendly_name);
551 if (!setup->application_base) {
552 /* Inherit from the root domain since MS.NET does this */
553 MonoDomain *root = mono_get_root_domain ();
554 if (root->setup->application_base) {
555 MonoString *s = mono_string_new_utf16_checked (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base), error);
556 mono_error_assert_ok (error); /* FIXME don't swallow the error */
557 MONO_OBJECT_SETREF (setup, application_base, s);
561 mono_context_init_checked (data, error);
562 return_val_if_nok (error, NULL);
564 data->setup = copy_app_domain_setup (data, setup, error);
565 if (!mono_error_ok (error)) {
566 g_free (data->friendly_name);
567 return NULL;
570 mono_domain_set_options_from_config (data);
571 add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
573 #ifndef DISABLE_SHADOW_COPY
574 /*FIXME, guard this for when the debugger is not running */
575 shadow_location = get_shadow_assembly_location_base (data, error);
576 if (!mono_error_ok (error)) {
577 g_free (data->friendly_name);
578 return NULL;
581 g_free (shadow_location);
582 #endif
584 create_domain_objects (data);
586 return ad;
590 * mono_domain_has_type_resolve:
591 * @domain: application domains being looked up
593 * Returns: TRUE if the AppDomain.TypeResolve field has been
594 * set.
596 gboolean
597 mono_domain_has_type_resolve (MonoDomain *domain)
599 static MonoClassField *field = NULL;
600 MonoObject *o;
602 if (field == NULL) {
603 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
604 g_assert (field);
607 /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
608 if (!domain->domain)
609 return FALSE;
611 mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
612 return o != NULL;
616 * mono_domain_try_type_resolve:
617 * @domain: application domainwhere the name where the type is going to be resolved
618 * @name: the name of the type to resolve or NULL.
619 * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
621 * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
622 * the assembly that matches name.
624 * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
626 * Returns: A MonoReflectionAssembly or NULL if not found
628 MonoReflectionAssembly *
629 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
631 MonoError error;
632 MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
633 mono_error_cleanup (&error);
635 return ret;
638 MonoReflectionAssembly *
639 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
641 static MonoMethod *method = NULL;
642 MonoReflectionAssembly *ret;
643 MonoClass *klass;
644 void *params [1];
646 mono_error_init (error);
648 g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
650 if (method == NULL) {
651 klass = domain->domain->mbr.obj.vtable->klass;
652 g_assert (klass);
654 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
655 if (method == NULL) {
656 g_warning ("Method AppDomain.DoTypeResolve not found.\n");
657 return NULL;
661 if (name)
662 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
663 else
664 *params = tb;
666 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
667 return_val_if_nok (error, NULL);
669 return ret;
673 * mono_domain_owns_vtable_slot:
675 * Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
677 gboolean
678 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
680 gboolean res;
682 mono_domain_lock (domain);
683 res = mono_mempool_contains_addr (domain->mp, vtable_slot);
684 mono_domain_unlock (domain);
685 return res;
689 * mono_domain_set:
690 * @domain: domain
691 * @force: force setting.
693 * Set the current appdomain to @domain. If @force is set, set it even
694 * if it is being unloaded.
696 * Returns:
697 * TRUE on success;
698 * FALSE if the domain is unloaded
700 gboolean
701 mono_domain_set (MonoDomain *domain, gboolean force)
703 if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
704 return FALSE;
706 mono_domain_set_internal (domain);
708 return TRUE;
711 MonoObject *
712 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
714 MonoError error;
715 MonoDomain *add;
716 MonoObject *o;
717 char *str;
719 MONO_CHECK_ARG_NULL (name, NULL);
721 g_assert (ad);
722 add = ad->data;
723 g_assert (add);
725 str = mono_string_to_utf8_checked (name, &error);
726 if (mono_error_set_pending_exception (&error))
727 return NULL;
729 mono_domain_lock (add);
731 if (!strcmp (str, "APPBASE"))
732 o = (MonoObject *)add->setup->application_base;
733 else if (!strcmp (str, "APP_CONFIG_FILE"))
734 o = (MonoObject *)add->setup->configuration_file;
735 else if (!strcmp (str, "DYNAMIC_BASE"))
736 o = (MonoObject *)add->setup->dynamic_base;
737 else if (!strcmp (str, "APP_NAME"))
738 o = (MonoObject *)add->setup->application_name;
739 else if (!strcmp (str, "CACHE_BASE"))
740 o = (MonoObject *)add->setup->cache_path;
741 else if (!strcmp (str, "PRIVATE_BINPATH"))
742 o = (MonoObject *)add->setup->private_bin_path;
743 else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
744 o = (MonoObject *)add->setup->private_bin_path_probe;
745 else if (!strcmp (str, "SHADOW_COPY_DIRS"))
746 o = (MonoObject *)add->setup->shadow_copy_directories;
747 else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
748 o = (MonoObject *)add->setup->shadow_copy_files;
749 else
750 o = (MonoObject *)mono_g_hash_table_lookup (add->env, name);
752 mono_domain_unlock (add);
753 g_free (str);
755 if (!o)
756 return NULL;
758 return o;
761 void
762 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
764 MonoDomain *add;
766 MONO_CHECK_ARG_NULL (name,);
768 g_assert (ad);
769 add = ad->data;
770 g_assert (add);
772 mono_domain_lock (add);
774 mono_g_hash_table_insert (add->env, name, data);
776 mono_domain_unlock (add);
779 MonoAppDomainSetup *
780 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
782 g_assert (ad);
783 g_assert (ad->data);
785 return ad->data->setup;
788 MonoString *
789 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
791 g_assert (ad);
792 g_assert (ad->data);
794 return mono_string_new (ad->data, ad->data->friendly_name);
797 MonoAppDomain *
798 ves_icall_System_AppDomain_getCurDomain ()
800 MonoDomain *add = mono_domain_get ();
802 return add->domain;
805 MonoAppDomain *
806 ves_icall_System_AppDomain_getRootDomain ()
808 MonoDomain *root = mono_get_root_domain ();
810 return root->domain;
813 MonoBoolean
814 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
816 MonoDomain *domain = mono_domain_get ();
818 return domain->throw_unobserved_task_exceptions;
821 static char*
822 get_attribute_value (const gchar **attribute_names,
823 const gchar **attribute_values,
824 const char *att_name)
826 int n;
827 for (n = 0; attribute_names [n] != NULL; n++) {
828 if (strcmp (attribute_names [n], att_name) == 0)
829 return g_strdup (attribute_values [n]);
831 return NULL;
834 static void
835 start_element (GMarkupParseContext *context,
836 const gchar *element_name,
837 const gchar **attribute_names,
838 const gchar **attribute_values,
839 gpointer user_data,
840 GError **error)
842 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
844 if (strcmp (element_name, "runtime") == 0) {
845 runtime_config->runtime_count++;
846 return;
849 if (strcmp (element_name, "assemblyBinding") == 0) {
850 runtime_config->assemblybinding_count++;
851 return;
854 if (runtime_config->runtime_count != 1)
855 return;
857 if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
858 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
860 if (value && g_ascii_strcasecmp (value, "true") == 0)
861 runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
864 if (runtime_config->assemblybinding_count != 1)
865 return;
867 if (strcmp (element_name, "probing") != 0)
868 return;
870 g_free (runtime_config->domain->private_bin_path);
871 runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
872 if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
873 g_free (runtime_config->domain->private_bin_path);
874 runtime_config->domain->private_bin_path = NULL;
875 return;
879 static void
880 end_element (GMarkupParseContext *context,
881 const gchar *element_name,
882 gpointer user_data,
883 GError **error)
885 RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
886 if (strcmp (element_name, "runtime") == 0)
887 runtime_config->runtime_count--;
888 else if (strcmp (element_name, "assemblyBinding") == 0)
889 runtime_config->assemblybinding_count--;
892 static void
893 parse_error (GMarkupParseContext *context, GError *error, gpointer user_data)
895 RuntimeConfig *state = (RuntimeConfig *)user_data;
896 const gchar *msg;
897 const gchar *filename;
899 filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
900 msg = error && error->message ? error->message : "";
901 g_warning ("Error parsing %s: %s", filename, msg);
904 static const GMarkupParser
905 mono_parser = {
906 start_element,
907 end_element,
908 NULL,
909 NULL,
910 parse_error
913 void
914 mono_domain_set_options_from_config (MonoDomain *domain)
916 MonoError error;
917 gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
918 gsize len;
919 GMarkupParseContext *context;
920 RuntimeConfig runtime_config;
921 gint offset;
923 if (!domain || !domain->setup || !domain->setup->configuration_file)
924 return;
926 config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
927 if (!mono_error_ok (&error)) {
928 mono_error_cleanup (&error);
929 goto free_and_out;
932 config_file_path = mono_portability_find_file (config_file_name, TRUE);
933 if (!config_file_path)
934 config_file_path = config_file_name;
936 if (!g_file_get_contents (config_file_path, &text, &len, NULL))
937 goto free_and_out;
939 runtime_config.runtime_count = 0;
940 runtime_config.assemblybinding_count = 0;
941 runtime_config.domain = domain;
942 runtime_config.filename = config_file_path;
944 offset = 0;
945 if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
946 offset = 3; /* Skip UTF-8 BOM */
948 context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
949 if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
950 g_markup_parse_context_end_parse (context, NULL);
951 g_markup_parse_context_free (context);
953 free_and_out:
954 g_free (text);
955 if (config_file_name != config_file_path)
956 g_free (config_file_name);
957 g_free (config_file_path);
960 MonoAppDomain *
961 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
963 MonoError error;
964 MonoAppDomain *ad = NULL;
966 #ifdef DISABLE_APPDOMAINS
967 mono_error_init (&error);
968 mono_error_set_not_supported (&error, "AppDomain creation is not supported on this runtime.");
969 #else
970 char *fname;
972 fname = mono_string_to_utf8_checked (friendly_name, &error);
973 if (mono_error_set_pending_exception (&error))
974 return NULL;
975 ad = mono_domain_create_appdomain_internal (fname, setup, &error);
977 g_free (fname);
978 #endif
979 mono_error_set_pending_exception (&error);
980 return ad;
983 MonoArray *
984 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
986 MonoError error;
987 MonoDomain *domain = ad->data;
988 MonoAssembly* ass;
989 MonoArray *res;
990 GSList *tmp;
991 int i;
992 GPtrArray *assemblies;
994 mono_error_init (&error);
997 * Make a copy of the list of assemblies because we can't hold the assemblies
998 * lock while creating objects etc.
1000 assemblies = g_ptr_array_new ();
1001 /* Need to skip internal assembly builders created by remoting */
1002 mono_domain_assemblies_lock (domain);
1003 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1004 ass = (MonoAssembly *)tmp->data;
1005 if (refonly != ass->ref_only)
1006 continue;
1007 if (ass->corlib_internal)
1008 continue;
1009 g_ptr_array_add (assemblies, ass);
1011 mono_domain_assemblies_unlock (domain);
1013 res = mono_array_new_checked (domain, mono_class_get_assembly_class (), assemblies->len, &error);
1014 if (!is_ok (&error))
1015 goto leave;
1016 for (i = 0; i < assemblies->len; ++i) {
1017 ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
1018 MonoReflectionAssembly *ass_obj = mono_assembly_get_object_checked (domain, ass, &error);
1019 if (!mono_error_ok (&error))
1020 goto leave;
1021 mono_array_setref (res, i, ass_obj);
1024 leave:
1025 g_ptr_array_free (assemblies, TRUE);
1026 if (!mono_error_ok (&error))
1027 mono_error_set_pending_exception (&error);
1028 return res;
1031 MonoReflectionAssembly *
1032 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1034 MonoReflectionAssembly *ret;
1035 MonoClass *klass;
1036 MonoMethod *method;
1037 MonoBoolean isrefonly;
1038 gpointer params [3];
1040 mono_error_init (error);
1042 if (mono_runtime_get_no_exec ())
1043 return NULL;
1045 g_assert (domain != NULL && fname != NULL);
1047 klass = domain->domain->mbr.obj.vtable->klass;
1048 g_assert (klass);
1050 method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
1051 if (method == NULL) {
1052 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
1053 return NULL;
1056 isrefonly = refonly ? 1 : 0;
1057 params [0] = fname;
1058 if (requesting) {
1059 params[1] = mono_assembly_get_object_checked (domain, requesting, error);
1060 return_val_if_nok (error, NULL);
1061 } else
1062 params [1] = NULL;
1063 params [2] = &isrefonly;
1065 ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
1066 return_val_if_nok (error, NULL);
1068 return ret;
1071 MonoAssembly *
1072 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1073 gboolean refonly)
1075 MonoError error;
1076 MonoReflectionAssembly *assembly;
1077 MonoDomain *domain = mono_domain_get ();
1078 char *aname_str;
1079 MonoString *str;
1081 aname_str = mono_stringify_assembly_name (aname);
1083 /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1084 str = mono_string_new (domain, aname_str);
1085 g_free (aname_str);
1086 if (!str) {
1087 return NULL;
1090 assembly = mono_try_assembly_resolve (domain, str, requesting, refonly, &error);
1091 mono_error_cleanup (&error);
1093 if (assembly)
1094 return assembly->assembly;
1095 else
1096 return NULL;
1100 * LOCKING: assumes assemblies_lock in the domain is already locked.
1102 static void
1103 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1105 gint i;
1106 GSList *tmp;
1107 gboolean destroy_ht = FALSE;
1109 if (!ass->aname.name)
1110 return;
1112 if (!ht) {
1113 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1114 destroy_ht = TRUE;
1117 /* FIXME: handle lazy loaded assemblies */
1118 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1119 g_hash_table_insert (ht, tmp->data, tmp->data);
1121 if (!g_hash_table_lookup (ht, ass)) {
1122 mono_assembly_addref (ass);
1123 g_hash_table_insert (ht, ass, ass);
1124 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1125 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);
1128 if (ass->image->references) {
1129 for (i = 0; ass->image->references [i] != NULL; i++) {
1130 if (ass->image->references [i] != REFERENCE_MISSING)
1131 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1132 add_assemblies_to_domain (domain, ass->image->references [i], ht);
1136 if (destroy_ht)
1137 g_hash_table_destroy (ht);
1140 static void
1141 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1143 static MonoClassField *assembly_load_field;
1144 static MonoMethod *assembly_load_method;
1145 MonoError error;
1146 MonoDomain *domain = mono_domain_get ();
1147 MonoReflectionAssembly *ref_assembly;
1148 MonoClass *klass;
1149 gpointer load_value;
1150 void *params [1];
1152 if (!domain->domain)
1153 /* This can happen during startup */
1154 return;
1155 #ifdef ASSEMBLY_LOAD_DEBUG
1156 fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1157 #endif
1158 klass = domain->domain->mbr.obj.vtable->klass;
1160 mono_domain_assemblies_lock (domain);
1161 add_assemblies_to_domain (domain, assembly, NULL);
1162 mono_domain_assemblies_unlock (domain);
1164 if (assembly_load_field == NULL) {
1165 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1166 g_assert (assembly_load_field);
1169 mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1170 if (load_value == NULL) {
1171 /* No events waiting to be triggered */
1172 return;
1175 ref_assembly = mono_assembly_get_object_checked (domain, assembly, &error);
1176 mono_error_assert_ok (&error);
1178 if (assembly_load_method == NULL) {
1179 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1180 g_assert (assembly_load_method);
1183 *params = ref_assembly;
1185 mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1186 mono_error_cleanup (&error);
1190 * LOCKING: Acquires the domain assemblies lock.
1192 static void
1193 set_domain_search_path (MonoDomain *domain)
1195 MonoError error;
1196 MonoAppDomainSetup *setup;
1197 gchar **tmp;
1198 gchar *search_path = NULL;
1199 gint i;
1200 gint npaths = 0;
1201 gchar **pvt_split = NULL;
1202 GError *gerror = NULL;
1203 gint appbaselen = -1;
1206 * We use the low-level domain assemblies lock, since this is called from
1207 * assembly loads hooks, which means this thread might hold the loader lock.
1209 mono_domain_assemblies_lock (domain);
1211 if (!domain->setup) {
1212 mono_domain_assemblies_unlock (domain);
1213 return;
1216 if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1217 mono_domain_assemblies_unlock (domain);
1218 return;
1220 setup = domain->setup;
1221 if (!setup->application_base) {
1222 mono_domain_assemblies_unlock (domain);
1223 return; /* Must set application base to get private path working */
1226 npaths++;
1228 if (setup->private_bin_path) {
1229 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1230 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1231 g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1232 mono_error_cleanup (&error);
1233 mono_domain_assemblies_unlock (domain);
1234 return;
1238 if (domain->private_bin_path) {
1239 if (search_path == NULL)
1240 search_path = domain->private_bin_path;
1241 else {
1242 gchar *tmp2 = search_path;
1243 search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1244 g_free (tmp2);
1248 if (search_path) {
1250 * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1251 * directories relative to ApplicationBase separated by semicolons (see
1252 * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1253 * The loop below copes with the fact that some Unix applications may use ':' (or
1254 * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1255 * ';' for the subsequent split.
1257 * The issue was reported in bug #81446
1260 #ifndef TARGET_WIN32
1261 gint slen;
1263 slen = strlen (search_path);
1264 for (i = 0; i < slen; i++)
1265 if (search_path [i] == ':')
1266 search_path [i] = ';';
1267 #endif
1269 pvt_split = g_strsplit (search_path, ";", 1000);
1270 g_free (search_path);
1271 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1274 if (!npaths) {
1275 if (pvt_split)
1276 g_strfreev (pvt_split);
1278 * Don't do this because the first time is called, the domain
1279 * setup is not finished.
1281 * domain->search_path = g_malloc (sizeof (char *));
1282 * domain->search_path [0] = NULL;
1284 mono_domain_assemblies_unlock (domain);
1285 return;
1288 if (domain->search_path)
1289 g_strfreev (domain->search_path);
1291 tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1292 tmp [npaths] = NULL;
1294 *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1295 if (!mono_error_ok (&error)) {
1296 mono_error_cleanup (&error);
1297 g_strfreev (pvt_split);
1298 g_free (tmp);
1300 mono_domain_assemblies_unlock (domain);
1301 return;
1304 domain->search_path = tmp;
1306 /* FIXME: is this needed? */
1307 if (strncmp (*tmp, "file://", 7) == 0) {
1308 gchar *file = *tmp;
1309 gchar *uri = *tmp;
1310 gchar *tmpuri;
1312 if (uri [7] != '/')
1313 uri = g_strdup_printf ("file:///%s", uri + 7);
1315 tmpuri = uri;
1316 uri = mono_escape_uri_string (tmpuri);
1317 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1318 g_free (uri);
1320 if (tmpuri != file)
1321 g_free (tmpuri);
1323 if (gerror != NULL) {
1324 g_warning ("%s\n", gerror->message);
1325 g_error_free (gerror);
1326 *tmp = file;
1327 } else {
1328 g_free (file);
1332 for (i = 1; pvt_split && i < npaths; i++) {
1333 if (g_path_is_absolute (pvt_split [i - 1])) {
1334 tmp [i] = g_strdup (pvt_split [i - 1]);
1335 } else {
1336 tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1339 if (strchr (tmp [i], '.')) {
1340 gchar *reduced;
1341 gchar *freeme;
1343 reduced = mono_path_canonicalize (tmp [i]);
1344 if (appbaselen == -1)
1345 appbaselen = strlen (tmp [0]);
1347 if (strncmp (tmp [0], reduced, appbaselen)) {
1348 g_free (reduced);
1349 g_free (tmp [i]);
1350 tmp [i] = g_strdup ("");
1351 continue;
1354 freeme = tmp [i];
1355 tmp [i] = reduced;
1356 g_free (freeme);
1360 if (setup->private_bin_path_probe != NULL) {
1361 g_free (tmp [0]);
1362 tmp [0] = g_strdup ("");
1365 domain->setup->path_changed = FALSE;
1367 g_strfreev (pvt_split);
1369 mono_domain_assemblies_unlock (domain);
1372 #ifdef DISABLE_SHADOW_COPY
1373 gboolean
1374 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1376 return FALSE;
1379 char *
1380 mono_make_shadow_copy (const char *filename, MonoError *error)
1382 mono_error_init (error);
1383 return (char *) filename;
1385 #else
1386 static gboolean
1387 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1389 guint16 *orig, *dest;
1390 gboolean copy_result;
1392 strcpy (src + srclen - tail_len, extension);
1394 if (IS_PORTABILITY_CASE) {
1395 gchar *file = mono_portability_find_file (src, TRUE);
1397 if (file == NULL)
1398 return TRUE;
1400 g_free (file);
1401 } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1402 return TRUE;
1405 orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1407 strcpy (target + targetlen - tail_len, extension);
1408 dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1410 DeleteFile (dest);
1411 copy_result = CopyFile (orig, dest, FALSE);
1413 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1414 * overwritten when updated in their original locations. */
1415 if (copy_result)
1416 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1418 g_free (orig);
1419 g_free (dest);
1421 return copy_result;
1424 static gint32
1425 get_cstring_hash (const char *str)
1427 int len, i;
1428 const char *p;
1429 gint32 h = 0;
1431 if (!str || !str [0])
1432 return 0;
1434 len = strlen (str);
1435 p = str;
1436 for (i = 0; i < len; i++) {
1437 h = (h << 5) - h + *p;
1438 p++;
1441 return h;
1445 * Returned memory is malloc'd. Called must free it
1447 static char *
1448 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1450 MonoAppDomainSetup *setup;
1451 char *cache_path, *appname;
1452 char *userdir;
1453 char *location;
1455 mono_error_init (error);
1457 setup = domain->setup;
1458 if (setup->cache_path != NULL && setup->application_name != NULL) {
1459 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1460 return_val_if_nok (error, NULL);
1462 #ifndef TARGET_WIN32
1464 gint i;
1465 for (i = strlen (cache_path) - 1; i >= 0; i--)
1466 if (cache_path [i] == '\\')
1467 cache_path [i] = '/';
1469 #endif
1471 appname = mono_string_to_utf8_checked (setup->application_name, error);
1472 if (!mono_error_ok (error)) {
1473 g_free (cache_path);
1474 return NULL;
1477 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1478 g_free (appname);
1479 g_free (cache_path);
1480 } else {
1481 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1482 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1483 g_free (userdir);
1485 return location;
1488 static char *
1489 get_shadow_assembly_location (const char *filename, MonoError *error)
1491 gint32 hash = 0, hash2 = 0;
1492 char name_hash [9];
1493 char path_hash [30];
1494 char *bname = g_path_get_basename (filename);
1495 char *dirname = g_path_get_dirname (filename);
1496 char *location, *tmploc;
1497 MonoDomain *domain = mono_domain_get ();
1499 mono_error_init (error);
1501 hash = get_cstring_hash (bname);
1502 hash2 = get_cstring_hash (dirname);
1503 g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1504 g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1505 tmploc = get_shadow_assembly_location_base (domain, error);
1506 if (!mono_error_ok (error)) {
1507 g_free (bname);
1508 g_free (dirname);
1509 return NULL;
1512 location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1513 g_free (tmploc);
1514 g_free (bname);
1515 g_free (dirname);
1516 return location;
1519 static gboolean
1520 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1522 struct stat sbuf_dest;
1523 gchar *stat_src;
1524 gchar *real_src = mono_portability_find_file (src, TRUE);
1526 if (!real_src)
1527 stat_src = (gchar*)src;
1528 else
1529 stat_src = real_src;
1531 if (stat (stat_src, sbuf_src) == -1) {
1532 time_t tnow = time (NULL);
1534 if (real_src)
1535 g_free (real_src);
1537 memset (sbuf_src, 0, sizeof (*sbuf_src));
1538 sbuf_src->st_mtime = tnow;
1539 sbuf_src->st_atime = tnow;
1540 return TRUE;
1543 if (real_src)
1544 g_free (real_src);
1546 if (stat (dest, &sbuf_dest) == -1)
1547 return TRUE;
1549 if (sbuf_src->st_size == sbuf_dest.st_size &&
1550 sbuf_src->st_mtime == sbuf_dest.st_mtime)
1551 return FALSE;
1553 return TRUE;
1556 static gboolean
1557 shadow_copy_create_ini (const char *shadow, const char *filename)
1559 char *dir_name;
1560 char *ini_file;
1561 guint16 *u16_ini;
1562 gboolean result;
1563 guint32 n;
1564 HANDLE *handle;
1565 gchar *full_path;
1567 dir_name = g_path_get_dirname (shadow);
1568 ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1569 g_free (dir_name);
1570 if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1571 g_free (ini_file);
1572 return TRUE;
1575 u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1576 g_free (ini_file);
1577 if (!u16_ini) {
1578 return FALSE;
1580 handle = (void **)CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1581 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1582 g_free (u16_ini);
1583 if (handle == INVALID_HANDLE_VALUE) {
1584 return FALSE;
1587 full_path = mono_path_resolve_symlinks (filename);
1588 result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1589 g_free (full_path);
1590 CloseHandle (handle);
1591 return result;
1594 gboolean
1595 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1597 MonoError error;
1598 MonoAppDomainSetup *setup;
1599 gchar *all_dirs;
1600 gchar **dir_ptr;
1601 gchar **directories;
1602 gchar *shadow_status_string;
1603 gchar *base_dir;
1604 gboolean shadow_enabled;
1605 gboolean found = FALSE;
1607 if (domain == NULL)
1608 return FALSE;
1610 setup = domain->setup;
1611 if (setup == NULL || setup->shadow_copy_files == NULL)
1612 return FALSE;
1614 shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1615 if (!mono_error_ok (&error)) {
1616 mono_error_cleanup (&error);
1617 return FALSE;
1619 shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1620 g_free (shadow_status_string);
1622 if (!shadow_enabled)
1623 return FALSE;
1625 if (setup->shadow_copy_directories == NULL)
1626 return TRUE;
1628 /* Is dir_name a shadow_copy destination already? */
1629 base_dir = get_shadow_assembly_location_base (domain, &error);
1630 if (!mono_error_ok (&error)) {
1631 mono_error_cleanup (&error);
1632 return FALSE;
1635 if (strstr (dir_name, base_dir)) {
1636 g_free (base_dir);
1637 return TRUE;
1639 g_free (base_dir);
1641 all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1642 if (!mono_error_ok (&error)) {
1643 mono_error_cleanup (&error);
1644 return FALSE;
1647 directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1648 dir_ptr = directories;
1649 while (*dir_ptr) {
1650 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1651 found = TRUE;
1652 break;
1654 dir_ptr++;
1656 g_strfreev (directories);
1657 g_free (all_dirs);
1658 return found;
1662 This function raises exceptions so it can cause as sorts of nasty stuff if called
1663 while holding a lock.
1664 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1665 or NULL if source file not found.
1666 FIXME bubble up the error instead of raising it here
1668 char *
1669 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1671 MonoError error;
1672 gchar *sibling_source, *sibling_target;
1673 gint sibling_source_len, sibling_target_len;
1674 guint16 *orig, *dest;
1675 guint32 attrs;
1676 char *shadow;
1677 gboolean copy_result;
1678 struct stat src_sbuf;
1679 struct utimbuf utbuf;
1680 char *dir_name = g_path_get_dirname (filename);
1681 MonoDomain *domain = mono_domain_get ();
1682 char *shadow_dir;
1684 mono_error_init (oerror);
1686 set_domain_search_path (domain);
1688 if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1689 g_free (dir_name);
1690 return (char *) filename;
1693 /* Is dir_name a shadow_copy destination already? */
1694 shadow_dir = get_shadow_assembly_location_base (domain, &error);
1695 if (!mono_error_ok (&error)) {
1696 mono_error_cleanup (&error);
1697 g_free (dir_name);
1698 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1699 return NULL;
1702 if (strstr (dir_name, shadow_dir)) {
1703 g_free (shadow_dir);
1704 g_free (dir_name);
1705 return (char *) filename;
1707 g_free (shadow_dir);
1708 g_free (dir_name);
1710 shadow = get_shadow_assembly_location (filename, &error);
1711 if (!mono_error_ok (&error)) {
1712 mono_error_cleanup (&error);
1713 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1714 return NULL;
1717 if (g_ensure_directory_exists (shadow) == FALSE) {
1718 g_free (shadow);
1719 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1720 return NULL;
1723 if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1724 return (char*) shadow;
1726 orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1727 dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1728 DeleteFile (dest);
1730 /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather
1731 * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1732 * and not have it runtime error" */
1733 attrs = GetFileAttributes (orig);
1734 if (attrs == INVALID_FILE_ATTRIBUTES) {
1735 g_free (shadow);
1736 return (char *)filename;
1739 copy_result = CopyFile (orig, dest, FALSE);
1741 /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1742 * overwritten when updated in their original locations. */
1743 if (copy_result)
1744 copy_result = SetFileAttributes (dest, FILE_ATTRIBUTE_NORMAL);
1746 g_free (dest);
1747 g_free (orig);
1749 if (copy_result == FALSE) {
1750 g_free (shadow);
1752 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1753 if (GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_PATH_NOT_FOUND)
1754 return NULL; /* file not found, shadow copy failed */
1756 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (CopyFile).");
1757 return NULL;
1760 /* attempt to copy .mdb, .config if they exist */
1761 sibling_source = g_strconcat (filename, ".config", NULL);
1762 sibling_source_len = strlen (sibling_source);
1763 sibling_target = g_strconcat (shadow, ".config", NULL);
1764 sibling_target_len = strlen (sibling_target);
1766 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1767 if (copy_result)
1768 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1770 g_free (sibling_source);
1771 g_free (sibling_target);
1773 if (!copy_result) {
1774 g_free (shadow);
1775 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (CopyFile).");
1776 return NULL;
1779 /* Create a .ini file containing the original assembly location */
1780 if (!shadow_copy_create_ini (shadow, filename)) {
1781 g_free (shadow);
1782 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1783 return NULL;
1786 utbuf.actime = src_sbuf.st_atime;
1787 utbuf.modtime = src_sbuf.st_mtime;
1788 utime (shadow, &utbuf);
1790 return shadow;
1792 #endif /* DISABLE_SHADOW_COPY */
1794 MonoDomain *
1795 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1797 if (appdomain == NULL)
1798 return NULL;
1800 return appdomain->data;
1803 static gboolean
1804 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1805 const gchar *path3, const gchar *path4,
1806 gboolean refonly, gboolean is_private)
1808 gchar *fullpath;
1809 gboolean found = FALSE;
1811 *assembly = NULL;
1812 fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1814 if (IS_PORTABILITY_SET) {
1815 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1816 if (new_fullpath) {
1817 g_free (fullpath);
1818 fullpath = new_fullpath;
1819 found = TRUE;
1821 } else
1822 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1824 if (found)
1825 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1827 g_free (fullpath);
1828 return (*assembly != NULL);
1831 static MonoAssembly *
1832 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1834 MonoAssembly *result = NULL;
1835 gchar **path;
1836 gchar *filename;
1837 const gchar *local_culture;
1838 gint len;
1839 gboolean is_private = FALSE;
1841 if (!culture || *culture == '\0') {
1842 local_culture = "";
1843 } else {
1844 local_culture = culture;
1847 filename = g_strconcat (name, ".dll", NULL);
1848 len = strlen (filename);
1850 for (path = search_path; *path; path++) {
1851 if (**path == '\0') {
1852 is_private = TRUE;
1853 continue; /* Ignore empty ApplicationBase */
1856 /* See test cases in bug #58992 and bug #57710 */
1857 /* 1st try: [culture]/[name].dll (culture may be empty) */
1858 strcpy (filename + len - 4, ".dll");
1859 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1860 break;
1862 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1863 strcpy (filename + len - 4, ".exe");
1864 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1865 break;
1867 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1868 strcpy (filename + len - 4, ".dll");
1869 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1870 break;
1872 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1873 strcpy (filename + len - 4, ".exe");
1874 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1875 break;
1878 g_free (filename);
1879 return result;
1883 * Try loading the assembly from ApplicationBase and PrivateBinPath
1884 * and then from assemblies_path if any.
1885 * LOCKING: This is called from the assembly loading code, which means the caller
1886 * might hold the loader lock. Thus, this function must not acquire the domain lock.
1888 static MonoAssembly *
1889 mono_domain_assembly_preload (MonoAssemblyName *aname,
1890 gchar **assemblies_path,
1891 gpointer user_data)
1893 MonoDomain *domain = mono_domain_get ();
1894 MonoAssembly *result = NULL;
1895 gboolean refonly = GPOINTER_TO_UINT (user_data);
1897 set_domain_search_path (domain);
1899 if (domain->search_path && domain->search_path [0] != NULL) {
1900 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1903 if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1904 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1907 return result;
1911 * Check whenever a given assembly was already loaded in the current appdomain.
1913 static MonoAssembly *
1914 mono_domain_assembly_search (MonoAssemblyName *aname,
1915 gpointer user_data)
1917 MonoDomain *domain = mono_domain_get ();
1918 GSList *tmp;
1919 MonoAssembly *ass;
1920 gboolean refonly = GPOINTER_TO_UINT (user_data);
1922 mono_domain_assemblies_lock (domain);
1923 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1924 ass = (MonoAssembly *)tmp->data;
1925 /* Dynamic assemblies can't match here in MS.NET */
1926 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1927 continue;
1929 mono_domain_assemblies_unlock (domain);
1930 return ass;
1932 mono_domain_assemblies_unlock (domain);
1934 return NULL;
1937 static gboolean
1938 prevent_running_reference_assembly (MonoAssembly *ass, MonoError *error)
1940 mono_error_init (error);
1941 gboolean refasm = mono_assembly_get_reference_assembly_attribute (ass, error);
1942 if (!is_ok (error))
1943 return TRUE;
1944 if (refasm) {
1945 mono_error_set_bad_image (error, ass->image, "Could not load file or assembly or one of its dependencies. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context.\n");
1946 return TRUE;
1948 return FALSE;
1951 MonoReflectionAssembly *
1952 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1954 MonoError error;
1955 MonoReflectionAssembly *result;
1956 MonoDomain *domain = mono_domain_get ();
1957 char *name, *filename;
1958 MonoImageOpenStatus status = MONO_IMAGE_OK;
1959 MonoAssembly *ass = NULL;
1961 name = NULL;
1962 result = NULL;
1964 mono_error_init (&error);
1966 if (fname == NULL) {
1967 mono_error_set_argument_null (&error, "assemblyFile", "");
1968 goto leave;
1971 name = filename = mono_string_to_utf8_checked (fname, &error);
1972 if (!is_ok (&error))
1973 goto leave;
1975 ass = mono_assembly_open_full (filename, &status, refOnly);
1977 if (!ass) {
1978 if (status == MONO_IMAGE_IMAGE_INVALID)
1979 mono_error_set_bad_image_name (&error, name, "");
1980 else
1981 mono_error_set_exception_instance (&error, mono_get_exception_file_not_found2 (NULL, fname));
1982 goto leave;
1985 if (!refOnly && prevent_running_reference_assembly (ass, &error))
1986 goto leave;
1988 result = mono_assembly_get_object_checked (domain, ass, &error);
1990 leave:
1991 mono_error_set_pending_exception (&error);
1992 g_free (name);
1993 return result;
1996 MonoReflectionAssembly *
1997 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad,
1998 MonoArray *raw_assembly,
1999 MonoArray *raw_symbol_store, MonoObject *evidence,
2000 MonoBoolean refonly)
2002 MonoError error;
2003 MonoAssembly *ass;
2004 MonoReflectionAssembly *refass = NULL;
2005 MonoDomain *domain = ad->data;
2006 MonoImageOpenStatus status;
2007 guint32 raw_assembly_len = mono_array_length (raw_assembly);
2008 MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
2010 if (!image) {
2011 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2012 return NULL;
2015 if (raw_symbol_store != NULL)
2016 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
2018 ass = mono_assembly_load_from_full (image, "", &status, refonly);
2021 if (!ass) {
2022 mono_image_close (image);
2023 mono_set_pending_exception (mono_get_exception_bad_image_format (""));
2024 return NULL;
2027 if (!refonly && prevent_running_reference_assembly (ass, &error)) {
2028 mono_error_set_pending_exception (&error);
2029 return NULL;
2032 refass = mono_assembly_get_object_checked (domain, ass, &error);
2033 if (!refass)
2034 mono_error_set_pending_exception (&error);
2035 else
2036 MONO_OBJECT_SETREF (refass, evidence, evidence);
2037 return refass;
2040 MonoReflectionAssembly *
2041 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad, MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
2043 MonoError error;
2044 MonoDomain *domain = ad->data;
2045 MonoImageOpenStatus status = MONO_IMAGE_OK;
2046 MonoAssembly *ass;
2047 MonoAssemblyName aname;
2048 MonoReflectionAssembly *refass = NULL;
2049 gchar *name = NULL;
2050 gboolean parsed;
2052 g_assert (assRef);
2054 name = mono_string_to_utf8_checked (assRef, &error);
2055 if (mono_error_set_pending_exception (&error))
2056 return NULL;
2057 parsed = mono_assembly_name_parse (name, &aname);
2059 if (!parsed) {
2060 /* This is a parse error... */
2061 if (!refOnly) {
2062 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2063 if (!is_ok (&error))
2064 goto leave;
2066 return refass;
2069 ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2070 mono_assembly_name_free (&aname);
2072 if (!ass) {
2073 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2074 if (!refOnly) {
2075 refass = mono_try_assembly_resolve (domain, assRef, NULL, refOnly, &error);
2076 if (!is_ok (&error))
2077 goto leave;
2079 else
2080 refass = NULL;
2081 if (!refass)
2082 goto leave;
2083 ass = refass->assembly;
2086 if (!refOnly && prevent_running_reference_assembly (ass, &error))
2087 goto leave;
2089 g_assert (ass);
2090 if (refass == NULL) {
2091 refass = mono_assembly_get_object_checked (domain, ass, &error);
2092 if (!is_ok (&error))
2093 goto leave;
2096 MONO_OBJECT_SETREF (refass, evidence, evidence);
2098 leave:
2099 g_free (name);
2100 mono_error_set_pending_exception (&error);
2101 return refass;
2104 void
2105 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
2107 MonoException *exc = NULL;
2108 MonoDomain * domain = mono_domain_get_by_id (domain_id);
2110 if (NULL == domain) {
2111 mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
2112 mono_set_pending_exception (exc);
2113 return;
2116 if (domain == mono_get_root_domain ()) {
2117 mono_set_pending_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
2118 return;
2122 * Unloading seems to cause problems when running NUnit/NAnt, hence
2123 * this workaround.
2125 if (g_getenv ("MONO_NO_UNLOAD"))
2126 return;
2127 #ifdef __native_client__
2128 return;
2129 #endif
2131 mono_domain_try_unload (domain, (MonoObject**)&exc);
2132 if (exc)
2133 mono_set_pending_exception (exc);
2136 gboolean
2137 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
2139 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2141 if (!domain)
2142 return TRUE;
2144 return mono_domain_is_unloading (domain);
2147 void
2148 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2150 mono_unhandled_exception ((MonoObject*) exc);
2153 gint32
2154 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad,
2155 MonoReflectionAssembly *refass, MonoArray *args)
2157 MonoError error;
2158 MonoImage *image;
2159 MonoMethod *method;
2161 g_assert (refass);
2162 image = refass->assembly->image;
2163 g_assert (image);
2165 method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
2167 if (!method)
2168 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (&error));
2170 if (!args) {
2171 args = (MonoArray *) mono_array_new_checked (ad->data, mono_defaults.string_class, 0, &error);
2172 mono_error_assert_ok (&error);
2175 int res = mono_runtime_exec_main_checked (method, (MonoArray *)args, &error);
2176 mono_error_set_pending_exception (&error);
2177 return res;
2180 gint32
2181 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad)
2183 return ad->data->domain_id;
2186 MonoAppDomain *
2187 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
2189 MonoDomain *old_domain = mono_domain_get();
2191 if (!mono_domain_set (ad->data, FALSE)) {
2192 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2193 return NULL;
2196 return old_domain->domain;
2199 MonoAppDomain *
2200 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
2202 MonoDomain *current_domain = mono_domain_get ();
2203 MonoDomain *domain = mono_domain_get_by_id (domainid);
2205 if (!domain || !mono_domain_set (domain, FALSE)) {
2206 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2207 return NULL;
2210 return current_domain->domain;
2213 void
2214 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
2216 mono_thread_push_appdomain_ref (ad->data);
2219 void
2220 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
2222 MonoDomain *domain = mono_domain_get_by_id (domain_id);
2224 if (!domain) {
2226 * Raise an exception to prevent the managed code from executing a pop
2227 * later.
2229 mono_set_pending_exception (mono_get_exception_appdomain_unloaded ());
2230 return;
2233 mono_thread_push_appdomain_ref (domain);
2236 void
2237 ves_icall_System_AppDomain_InternalPopDomainRef (void)
2239 mono_thread_pop_appdomain_ref ();
2242 MonoAppContext *
2243 ves_icall_System_AppDomain_InternalGetContext ()
2245 return mono_context_get ();
2248 MonoAppContext *
2249 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2251 return mono_domain_get ()->default_context;
2254 MonoAppContext *
2255 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2257 MonoAppContext *old_context = mono_context_get ();
2259 mono_context_set (mc);
2261 return old_context;
2264 MonoString *
2265 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
2267 MonoDomain* mono_root_domain = mono_get_root_domain ();
2268 mono_domain_lock (mono_root_domain);
2269 if (process_guid_set) {
2270 mono_domain_unlock (mono_root_domain);
2271 MonoError error;
2272 MonoString *res = NULL;
2273 res = mono_string_new_utf16_checked (mono_domain_get (), process_guid, sizeof(process_guid)/2, &error);
2274 mono_error_set_pending_exception (&error);
2275 return res;
2277 memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
2278 process_guid_set = TRUE;
2279 mono_domain_unlock (mono_root_domain);
2280 return newguid;
2283 gboolean
2284 mono_domain_is_unloading (MonoDomain *domain)
2286 if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2287 return TRUE;
2288 else
2289 return FALSE;
2292 static void
2293 clear_cached_vtable (MonoVTable *vtable)
2295 MonoClass *klass = vtable->klass;
2296 MonoDomain *domain = vtable->domain;
2297 MonoClassRuntimeInfo *runtime_info;
2298 void *data;
2300 runtime_info = klass->runtime_info;
2301 if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2302 runtime_info->domain_vtables [domain->domain_id] = NULL;
2303 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2304 mono_gc_free_fixed (data);
2307 static G_GNUC_UNUSED void
2308 zero_static_data (MonoVTable *vtable)
2310 MonoClass *klass = vtable->klass;
2311 void *data;
2313 if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2314 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2317 typedef struct unload_data {
2318 gboolean done;
2319 MonoDomain *domain;
2320 char *failure_reason;
2321 gint32 refcount;
2322 } unload_data;
2324 static void
2325 unload_data_unref (unload_data *data)
2327 gint32 count;
2328 do {
2329 mono_atomic_load_acquire (count, gint32, &data->refcount);
2330 g_assert (count >= 1 && count <= 2);
2331 if (count == 1) {
2332 g_free (data);
2333 return;
2335 } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2338 static void
2339 deregister_reflection_info_roots_from_list (MonoImage *image)
2341 GSList *list = image->reflection_info_unregister_classes;
2343 while (list) {
2344 MonoClass *klass = (MonoClass *)list->data;
2346 mono_class_free_ref_info (klass);
2348 list = list->next;
2351 image->reflection_info_unregister_classes = NULL;
2354 static void
2355 deregister_reflection_info_roots (MonoDomain *domain)
2357 GSList *list;
2359 mono_domain_assemblies_lock (domain);
2360 for (list = domain->domain_assemblies; list; list = list->next) {
2361 MonoAssembly *assembly = (MonoAssembly *)list->data;
2362 MonoImage *image = assembly->image;
2363 int i;
2366 * No need to take the image lock here since dynamic images are appdomain bound and
2367 * at this point the mutator is gone. Taking the image lock here would mean
2368 * promoting it from a simple lock to a complex lock, which we better avoid if
2369 * possible.
2371 if (image_is_dynamic (image))
2372 deregister_reflection_info_roots_from_list (image);
2374 for (i = 0; i < image->module_count; ++i) {
2375 MonoImage *module = image->modules [i];
2376 if (module && image_is_dynamic (module))
2377 deregister_reflection_info_roots_from_list (module);
2380 mono_domain_assemblies_unlock (domain);
2383 static gsize WINAPI
2384 unload_thread_main (void *arg)
2386 MonoError error;
2387 unload_data *data = (unload_data*)arg;
2388 MonoDomain *domain = data->domain;
2389 MonoThread *thread;
2390 int i;
2392 /* Have to attach to the runtime so shutdown can wait for this thread */
2393 /* Force it to be attached to avoid racing during shutdown. */
2394 thread = mono_thread_attach_full (mono_get_root_domain (), TRUE);
2396 mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
2397 if (!is_ok (&error)) {
2398 data->failure_reason = g_strdup (mono_error_get_message (&error));
2399 mono_error_cleanup (&error);
2400 goto failure;
2404 * FIXME: Abort our parent thread last, so we can return a failure
2405 * indication if aborting times out.
2407 if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2408 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2409 goto failure;
2412 if (!mono_threadpool_ms_remove_domain_jobs (domain, -1)) {
2413 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2414 goto failure;
2417 /* Finalize all finalizable objects in the doomed appdomain */
2418 if (!mono_domain_finalize (domain, -1)) {
2419 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2420 goto failure;
2423 /* Clear references to our vtables in class->runtime_info.
2424 * We also hold the loader lock because we're going to change
2425 * class->runtime_info.
2428 mono_loader_lock (); //FIXME why do we need the loader lock here?
2429 mono_domain_lock (domain);
2430 #ifdef HAVE_SGEN_GC
2432 * We need to make sure that we don't have any remsets
2433 * pointing into static data of the to-be-freed domain because
2434 * at the next collections they would be invalid. So what we
2435 * do is we first zero all static data and then do a minor
2436 * collection. Because all references in the static data will
2437 * now be null we won't do any unnecessary copies and after
2438 * the collection there won't be any more remsets.
2440 for (i = 0; i < domain->class_vtable_array->len; ++i)
2441 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2442 mono_gc_collect (0);
2443 #endif
2444 for (i = 0; i < domain->class_vtable_array->len; ++i)
2445 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2446 deregister_reflection_info_roots (domain);
2448 mono_assembly_cleanup_domain_bindings (domain->domain_id);
2450 mono_domain_unlock (domain);
2451 mono_loader_unlock ();
2453 mono_threads_clear_cached_culture (domain);
2455 domain->state = MONO_APPDOMAIN_UNLOADED;
2457 /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2459 /* remove from the handle table the items related to this domain */
2460 mono_gchandle_free_domain (domain);
2462 mono_domain_free (domain, FALSE);
2464 mono_gc_collect (mono_gc_max_generation ());
2466 mono_atomic_store_release (&data->done, TRUE);
2467 unload_data_unref (data);
2468 mono_thread_detach (thread);
2469 return 0;
2471 failure:
2472 mono_atomic_store_release (&data->done, TRUE);
2473 unload_data_unref (data);
2474 mono_thread_detach (thread);
2475 return 1;
2479 * mono_domain_unload:
2480 * @domain: The domain to unload
2482 * Unloads an appdomain. Follows the process outlined in the comment
2483 * for mono_domain_try_unload.
2485 void
2486 mono_domain_unload (MonoDomain *domain)
2488 MonoObject *exc = NULL;
2489 mono_domain_try_unload (domain, &exc);
2492 static guint32
2493 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
2495 guint32 result;
2497 MONO_ENTER_GC_SAFE;
2498 result = WaitForSingleObjectEx (handle, timeout, alertable);
2499 MONO_EXIT_GC_SAFE;
2501 return result;
2505 * mono_domain_unload:
2506 * @domain: The domain to unload
2507 * @exc: Exception information
2509 * Unloads an appdomain. Follows the process outlined in:
2510 * http://blogs.gotdotnet.com/cbrumme
2512 * If doing things the 'right' way is too hard or complex, we do it the
2513 * 'simple' way, which means do everything needed to avoid crashes and
2514 * memory leaks, but not much else.
2516 * It is required to pass a valid reference to the exc argument, upon return
2517 * from this function *exc will be set to the exception thrown, if any.
2519 * If this method is not called from an icall (embedded scenario for instance),
2520 * it must not be called with any managed frames on the stack, since the unload
2521 * process could end up trying to abort the current thread.
2523 void
2524 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2526 MonoError error;
2527 HANDLE thread_handle;
2528 MonoAppDomainState prev_state;
2529 MonoMethod *method;
2530 unload_data *thread_data;
2531 MonoNativeThreadId tid;
2532 MonoDomain *caller_domain = mono_domain_get ();
2533 MonoThreadParm tp;
2535 /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2537 /* Atomically change our state to UNLOADING */
2538 prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2539 MONO_APPDOMAIN_UNLOADING_START,
2540 MONO_APPDOMAIN_CREATED);
2541 if (prev_state != MONO_APPDOMAIN_CREATED) {
2542 switch (prev_state) {
2543 case MONO_APPDOMAIN_UNLOADING_START:
2544 case MONO_APPDOMAIN_UNLOADING:
2545 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2546 return;
2547 case MONO_APPDOMAIN_UNLOADED:
2548 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2549 return;
2550 default:
2551 g_warning ("Invalid appdomain state %d", prev_state);
2552 g_assert_not_reached ();
2556 mono_domain_set (domain, FALSE);
2557 /* Notify OnDomainUnload listeners */
2558 method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1);
2559 g_assert (method);
2561 mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2563 if (!mono_error_ok (&error)) {
2564 if (*exc)
2565 mono_error_cleanup (&error);
2566 else
2567 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2570 if (*exc) {
2571 /* Roll back the state change */
2572 domain->state = MONO_APPDOMAIN_CREATED;
2573 mono_domain_set (caller_domain, FALSE);
2574 return;
2576 mono_domain_set (caller_domain, FALSE);
2578 thread_data = g_new0 (unload_data, 1);
2579 thread_data->domain = domain;
2580 thread_data->failure_reason = NULL;
2581 thread_data->done = FALSE;
2582 thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2584 /*The managed callback finished successfully, now we start tearing down the appdomain*/
2585 domain->state = MONO_APPDOMAIN_UNLOADING;
2587 * First we create a separate thread for unloading, since
2588 * we might have to abort some threads, including the current one.
2590 tp.priority = MONO_THREAD_PRIORITY_NORMAL;
2591 tp.stack_size = 0;
2592 tp.creation_flags = 0;
2593 thread_handle = mono_threads_create_thread (unload_thread_main, thread_data, &tp, &tid);
2594 if (thread_handle == NULL)
2595 return;
2597 /* Wait for the thread */
2598 while (!thread_data->done && guarded_wait (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION) {
2599 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2600 /* The unload thread tries to abort us */
2601 /* The icall wrapper will execute the abort */
2602 unload_data_unref (thread_data);
2603 return;
2607 if (thread_data->failure_reason) {
2608 /* Roll back the state change */
2609 domain->state = MONO_APPDOMAIN_CREATED;
2611 g_warning ("%s", thread_data->failure_reason);
2613 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2615 g_free (thread_data->failure_reason);
2616 thread_data->failure_reason = NULL;
2619 unload_data_unref (thread_data);