Include Mono version in corlib version
[mono.git] / mono / metadata / appdomain.c
1 /*
2  * appdomain.c: AppDomain functions
3  *
4  * Authors:
5  *      Dietmar Maurer (dietmar@ximian.com)
6  *      Patrik Torstensson
7  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
8  *
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.
13  */
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
35
36 #include <mono/metadata/gc-internals.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/appdomain-icalls.h>
39 #include <mono/metadata/domain-internals.h>
40 #include "mono/metadata/metadata-internals.h"
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/assembly-internals.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/exception-internals.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/mono-gc.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/marshal-internals.h>
51 #include <mono/metadata/monitor.h>
52 #include <mono/metadata/mono-debug.h>
53 #include <mono/metadata/attach.h>
54 #include <mono/metadata/w32file.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/metadata/abi-details.h>
62 #include <mono/metadata/w32socket.h>
63 #include <mono/utils/mono-uri.h>
64 #include <mono/utils/mono-logger-internals.h>
65 #include <mono/utils/mono-path.h>
66 #include <mono/utils/mono-stdlib.h>
67 #include <mono/utils/mono-io-portability.h>
68 #include <mono/utils/mono-error-internals.h>
69 #include <mono/utils/atomic.h>
70 #include <mono/utils/mono-memory-model.h>
71 #include <mono/utils/mono-threads.h>
72 #include <mono/metadata/w32handle.h>
73 #include <mono/metadata/w32error.h>
74 #include <mono/utils/w32api.h>
75 #ifdef HOST_WIN32
76 #include <direct.h>
77 #endif
78
79 typedef struct
80 {
81         int runtime_count;
82         int assemblybinding_count;
83         MonoDomain *domain;
84         gchar *filename;
85 } RuntimeConfig;
86
87 static gunichar2 process_guid [36];
88 static gboolean process_guid_set = FALSE;
89
90 static gboolean no_exec = FALSE;
91
92 static MonoAssembly *
93 mono_domain_assembly_preload (MonoAssemblyName *aname,
94                               gchar **assemblies_path,
95                               gpointer user_data);
96
97 static MonoAssembly *
98 mono_domain_assembly_search (MonoAssemblyName *aname,
99                                                          gpointer user_data);
100
101 static void
102 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
103
104 static void
105 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
106
107 static MonoAppDomainHandle
108 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error);
109
110 static MonoDomain *
111 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error);
112
113
114 static char *
115 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error);
116
117 static MonoLoadFunc load_function = NULL;
118
119 /* Lazy class loading functions */
120 static GENERATE_GET_CLASS_WITH_CACHE (assembly, "System.Reflection", "Assembly");
121
122 static GENERATE_GET_CLASS_WITH_CACHE (appdomain, "System", "AppDomain");
123
124 static MonoDomain *
125 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain);
126
127 static void
128 mono_error_set_appdomain_unloaded (MonoError *error)
129 {
130         mono_error_set_generic_error (error, "System", "AppDomainUnloadedException", "");
131 }
132
133 void
134 mono_install_runtime_load (MonoLoadFunc func)
135 {
136         load_function = func;
137 }
138
139 MonoDomain*
140 mono_runtime_load (const char *filename, const char *runtime_version)
141 {
142         g_assert (load_function);
143         return load_function (filename, runtime_version);
144 }
145
146 /**
147  * mono_runtime_set_no_exec:
148  *
149  * Instructs the runtime to operate in static mode, i.e. avoid/do not
150  * allow managed code execution. This is useful for running the AOT
151  * compiler on platforms which allow full-aot execution only.  This
152  * should be called before mono_runtime_init ().
153  */
154 void
155 mono_runtime_set_no_exec (gboolean val)
156 {
157         no_exec = val;
158 }
159
160 /**
161  * mono_runtime_get_no_exec:
162  *
163  * If true, then the runtime will not allow managed code execution.
164  */
165 gboolean
166 mono_runtime_get_no_exec (void)
167 {
168         return no_exec;
169 }
170
171 static void
172 create_domain_objects (MonoDomain *domain)
173 {
174         MonoError error;
175         MonoDomain *old_domain = mono_domain_get ();
176         MonoString *arg;
177         MonoVTable *string_vt;
178         MonoClassField *string_empty_fld;
179
180         if (domain != old_domain) {
181                 mono_thread_push_appdomain_ref (domain);
182                 mono_domain_set_internal_with_options (domain, FALSE);
183         }
184
185         /*
186          * Initialize String.Empty. This enables the removal of
187          * the static cctor of the String class.
188          */
189         string_vt = mono_class_vtable (domain, mono_defaults.string_class);
190         string_empty_fld = mono_class_get_field_from_name (mono_defaults.string_class, "Empty");
191         g_assert (string_empty_fld);
192         MonoString *empty_str = mono_string_intern_checked (mono_string_new (domain, ""), &error);
193         mono_error_assert_ok (&error);
194         mono_field_static_set_value (string_vt, string_empty_fld, empty_str);
195         domain->empty_string = empty_str;
196
197         /*
198          * Create an instance early since we can't do it when there is no memory.
199          */
200         arg = mono_string_new (domain, "Out of memory");
201         domain->out_of_memory_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL, &error);
202         mono_error_assert_ok (&error);
203
204         /* 
205          * These two are needed because the signal handlers might be executing on
206          * an alternate stack, and Boehm GC can't handle that.
207          */
208         arg = mono_string_new (domain, "A null value was found where an object instance was required");
209         domain->null_reference_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL, &error);
210         mono_error_assert_ok (&error);
211         arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
212         domain->stack_overflow_ex = mono_exception_from_name_two_strings_checked (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL, &error);
213         mono_error_assert_ok (&error);
214
215         /*The ephemeron tombstone i*/
216         domain->ephemeron_tombstone = mono_object_new_checked (domain, mono_defaults.object_class, &error);
217         mono_error_assert_ok (&error);
218
219         if (domain != old_domain) {
220                 mono_thread_pop_appdomain_ref ();
221                 mono_domain_set_internal_with_options (old_domain, FALSE);
222         }
223
224         /* 
225          * This class is used during exception handling, so initialize it here, to prevent
226          * stack overflows while handling stack overflows.
227          */
228         mono_class_init (mono_array_class_get (mono_defaults.int_class, 1));
229 }
230
231 /**
232  * mono_runtime_init:
233  * @domain: domain returned by mono_init ()
234  *
235  * Initialize the core AppDomain: this function will run also some
236  * IL initialization code, so it needs the execution engine to be fully 
237  * operational.
238  *
239  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
240  * we know the entry_assembly.
241  *
242  */
243 void
244 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb)
245 {
246         MonoError error;
247         mono_runtime_init_checked (domain, start_cb, attach_cb, &error);
248         mono_error_cleanup (&error);
249 }
250
251 void
252 mono_runtime_init_checked (MonoDomain *domain, MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb, MonoError *error)
253 {
254         MonoAppDomainSetup *setup;
255         MonoAppDomain *ad;
256         MonoClass *klass;
257
258         error_init (error);
259
260         mono_portability_helpers_init ();
261         
262         mono_gc_base_init ();
263         mono_monitor_init ();
264         mono_marshal_init ();
265
266         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
267         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
268         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
269         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
270         mono_install_assembly_postload_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
271         mono_install_assembly_postload_refonly_search_hook ((MonoAssemblySearchFunc)mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
272         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
273
274         mono_thread_init (start_cb, attach_cb);
275
276         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
277         setup = (MonoAppDomainSetup *) mono_object_new_pinned (domain, klass, error);
278         return_if_nok (error);
279
280         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomain");
281
282         ad = (MonoAppDomain *) mono_object_new_pinned (domain, klass, error);
283         return_if_nok (error);
284
285         ad->data = domain;
286         domain->domain = ad;
287         domain->setup = setup;
288
289         mono_thread_attach (domain);
290
291         mono_type_initialization_init ();
292
293         if (!mono_runtime_get_no_exec ())
294                 create_domain_objects (domain);
295
296         /* GC init has to happen after thread init */
297         mono_gc_init ();
298
299         /* contexts use GC handles, so they must be initialized after the GC */
300         mono_context_init_checked (domain, error);
301         return_if_nok (error);
302         mono_context_set (domain->default_context);
303
304 #ifndef DISABLE_SOCKETS
305         mono_network_init ();
306 #endif
307         
308         mono_console_init ();
309         mono_attach_init ();
310
311         mono_locks_tracer_init ();
312
313         /* mscorlib is loaded before we install the load hook */
314         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
315
316         return;
317 }
318
319 static int
320 mono_get_corlib_version (void)
321 {
322         MonoError error;
323         MonoClass *klass;
324         MonoClassField *field;
325         MonoObject *value;
326
327         klass = mono_class_load_from_name (mono_defaults.corlib, "System", "Environment");
328         mono_class_init (klass);
329         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
330         if (!field)
331                 return -1;
332         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
333                 return -1;
334         value = mono_field_get_value_object_checked (mono_domain_get (), field, NULL, &error);
335         mono_error_assert_ok (&error);
336         return *(gint32*)((gchar*)value + sizeof (MonoObject));
337 }
338
339 /**
340  * mono_check_corlib_version
341  *
342  * Checks that the corlib that is loaded matches the version of this runtime.
343  *
344  * Returns: NULL if the runtime will work with the corlib, or a g_malloc
345  * allocated string with the error otherwise.
346  */
347 const char*
348 mono_check_corlib_version (void)
349 {
350         int version = mono_get_corlib_version ();
351         if (version != MONO_CORLIB_VERSION)
352                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
353
354         /* Check that the managed and unmanaged layout of MonoInternalThread matches */
355         guint32 native_offset = (guint32) MONO_STRUCT_OFFSET (MonoInternalThread, last);
356         guint32 managed_offset = mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last"));
357         if (native_offset != managed_offset)
358                 return g_strdup_printf ("expected InternalThread.last field offset %u, found %u. See InternalThread.last comment", native_offset, managed_offset);
359
360         return NULL;
361 }
362
363 /**
364  * mono_context_init:
365  * @domain: The domain where the System.Runtime.Remoting.Context.Context is initialized
366  *
367  * Initializes the @domain's default System.Runtime.Remoting's Context.
368  */
369 void
370 mono_context_init (MonoDomain *domain)
371 {
372         MonoError error;
373         mono_context_init_checked (domain, &error);
374         mono_error_cleanup (&error);
375 }
376
377 void
378 mono_context_init_checked (MonoDomain *domain, MonoError *error)
379 {
380         MonoClass *klass;
381         MonoAppContext *context;
382
383         error_init (error);
384
385         klass = mono_class_load_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
386         context = (MonoAppContext *) mono_object_new_pinned (domain, klass, error);
387         return_if_nok (error);
388
389         context->domain_id = domain->domain_id;
390         context->context_id = 0;
391         ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (context);
392         domain->default_context = context;
393 }
394
395 /**
396  * mono_runtime_cleanup:
397  * @domain: unused.
398  *
399  * Internal routine.
400  *
401  * This must not be called while there are still running threads executing
402  * managed code.
403  */
404 void
405 mono_runtime_cleanup (MonoDomain *domain)
406 {
407         mono_attach_cleanup ();
408
409         /* This ends up calling any pending pending (for at most 2 seconds) */
410         mono_gc_cleanup ();
411
412         mono_thread_cleanup ();
413
414 #ifndef DISABLE_SOCKETS
415         mono_network_cleanup ();
416 #endif
417         mono_marshal_cleanup ();
418
419         mono_type_initialization_cleanup ();
420
421         mono_monitor_cleanup ();
422 }
423
424 static MonoDomainFunc quit_function = NULL;
425
426 void
427 mono_install_runtime_cleanup (MonoDomainFunc func)
428 {
429         quit_function = func;
430 }
431
432 void
433 mono_runtime_quit ()
434 {
435         if (quit_function != NULL)
436                 quit_function (mono_get_root_domain (), NULL);
437 }
438
439 /**
440  * mono_domain_create_appdomain:
441  * @friendly_name: The friendly name of the appdomain to create
442  * @configuration_file: The configuration file to initialize the appdomain with
443  * 
444  * Returns a MonoDomain initialized with the appdomain
445  */
446 MonoDomain *
447 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
448 {
449         HANDLE_FUNCTION_ENTER ();
450         MonoError error;
451         MonoDomain *domain = mono_domain_create_appdomain_checked (friendly_name, configuration_file, &error);
452         mono_error_cleanup (&error);
453         HANDLE_FUNCTION_RETURN_VAL (domain);
454 }
455
456 /**
457  * mono_domain_create_appdomain_checked:
458  * @friendly_name: The friendly name of the appdomain to create
459  * @configuration_file: The configuration file to initialize the appdomain with
460  * @error: Set on error.
461  * 
462  * Returns a MonoDomain initialized with the appdomain.  On failure sets @error and returns NULL.
463  */
464 MonoDomain *
465 mono_domain_create_appdomain_checked (char *friendly_name, char *configuration_file, MonoError *error)
466 {
467         HANDLE_FUNCTION_ENTER ();
468         error_init (error);
469         MonoDomain *result = NULL;
470
471         MonoClass *klass = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
472         MonoAppDomainSetupHandle setup = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (mono_domain_get (), klass, error));
473         if (!is_ok (error))
474                 goto leave;
475         MonoStringHandle config_file;
476         if (configuration_file != NULL) {
477                 config_file = mono_string_new_handle (mono_domain_get (), configuration_file, error);
478                 if (!is_ok (error))
479                         goto leave;
480         } else {
481                 config_file = MONO_HANDLE_NEW (MonoString, NULL);
482         }
483         MONO_HANDLE_SET (setup, configuration_file, config_file);
484
485         MonoAppDomainHandle ad = mono_domain_create_appdomain_internal (friendly_name, setup, error);
486         if (!is_ok (error))
487                 goto leave;
488
489         result = mono_domain_from_appdomain_handle (ad);
490 leave:
491         HANDLE_FUNCTION_RETURN_VAL (result);
492 }
493
494 /**
495  * mono_domain_set_config:
496  * @domain: MonoDomain initialized with the appdomain we want to change
497  * @base_dir: new base directory for the appdomain
498  * @config_file_name: path to the new configuration for the app domain
499  *
500  * Used to set the system configuration for an appdomain
501  *
502  * Without using this, embedded builds will get 'System.Configuration.ConfigurationErrorsException: 
503  * Error Initializing the configuration system. ---> System.ArgumentException: 
504  * The 'ExeConfigFilename' argument cannot be null.' for some managed calls.
505  */
506 void
507 mono_domain_set_config (MonoDomain *domain, const char *base_dir, const char *config_file_name)
508 {
509         MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, base_dir));
510         MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, config_file_name));
511 }
512
513 static MonoAppDomainSetupHandle
514 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetupHandle setup, MonoError *error)
515 {
516         HANDLE_FUNCTION_ENTER ();
517         MonoDomain *caller_domain;
518         MonoClass *ads_class;
519         MonoAppDomainSetupHandle result = MONO_HANDLE_NEW (MonoAppDomainSetup, NULL);
520
521         error_init (error);
522
523         caller_domain = mono_domain_get ();
524         ads_class = mono_class_load_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
525
526         MonoAppDomainSetupHandle copy = MONO_HANDLE_NEW (MonoAppDomainSetup, mono_object_new_checked (domain, ads_class, error));
527         if (!is_ok (error))
528                 goto leave;
529
530         mono_domain_set_internal (domain);
531
532 #define XCOPY_FIELD(dst,field,src,error)                                \
533         do {                                                            \
534                 MonoObjectHandle src_val = MONO_HANDLE_NEW_GET (MonoObject, (src), field); \
535                 MonoObjectHandle copied_val = mono_marshal_xdomain_copy_value_handle (src_val, error); \
536                 if (!is_ok (error))                                     \
537                         goto leave;                                     \
538                 MONO_HANDLE_SET ((dst),field,copied_val);               \
539         } while (0)
540
541 #define COPY_VAL(dst,field,type,src)                                    \
542                 do {                                                    \
543                         MONO_HANDLE_SETVAL ((dst), field, type, MONO_HANDLE_GETVAL ((src),field)); \
544                 } while (0)
545
546         XCOPY_FIELD (copy, application_base, setup, error);
547         XCOPY_FIELD (copy, application_name, setup, error);
548         XCOPY_FIELD (copy, cache_path, setup, error);
549         XCOPY_FIELD (copy, configuration_file, setup, error);
550         XCOPY_FIELD (copy, dynamic_base, setup, error);
551         XCOPY_FIELD (copy, license_file, setup, error);
552         XCOPY_FIELD (copy, private_bin_path, setup, error);
553         XCOPY_FIELD (copy, private_bin_path_probe, setup, error);
554         XCOPY_FIELD (copy, shadow_copy_directories, setup, error);
555         XCOPY_FIELD (copy, shadow_copy_files, setup, error);
556         COPY_VAL (copy, publisher_policy, MonoBoolean, setup);
557         COPY_VAL (copy, path_changed, MonoBoolean, setup);
558         COPY_VAL (copy, loader_optimization, int, setup);
559         COPY_VAL (copy, disallow_binding_redirects, MonoBoolean, setup);
560         COPY_VAL (copy, disallow_code_downloads, MonoBoolean, setup);
561         XCOPY_FIELD (copy, domain_initializer_args, setup, error);
562         COPY_VAL (copy, disallow_appbase_probe, MonoBoolean, setup);
563         XCOPY_FIELD (copy, application_trust, setup, error);
564         XCOPY_FIELD (copy, configuration_bytes, setup, error);
565         XCOPY_FIELD (copy, serialized_non_primitives, setup, error);
566
567 #undef XCOPY_FIELD
568 #undef COPY_VAL
569         
570         mono_domain_set_internal (caller_domain);
571
572         MONO_HANDLE_ASSIGN (result, copy);
573 leave:
574         HANDLE_FUNCTION_RETURN_REF (MonoAppDomainSetup, result);
575 }
576
577 static MonoAppDomainHandle
578 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
579 {
580         HANDLE_FUNCTION_ENTER ();
581         MonoAppDomainHandle result = MONO_HANDLE_NEW (MonoAppDomain, NULL);
582         MonoClass *adclass;
583         MonoDomain *data;
584
585         error_init (error);
586
587         adclass = mono_class_get_appdomain_class ();
588
589         /* FIXME: pin all those objects */
590         data = mono_domain_create();
591
592         MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain,  mono_object_new_checked (data, adclass, error));
593         if (!is_ok (error))
594                 goto leave;
595         MONO_HANDLE_SETVAL (ad, data, MonoDomain*, data);
596         data->domain = MONO_HANDLE_RAW (ad);
597         data->friendly_name = g_strdup (friendly_name);
598
599         mono_profiler_appdomain_name (data, data->friendly_name);
600
601         MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base);
602         if (MONO_HANDLE_IS_NULL (app_base)) {
603                 /* Inherit from the root domain since MS.NET does this */
604                 MonoDomain *root = mono_get_root_domain ();
605                 MonoAppDomainSetupHandle root_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, root->setup);
606                 MonoStringHandle root_app_base = MONO_HANDLE_NEW_GET (MonoString, root_setup, application_base);
607                 if (!MONO_HANDLE_IS_NULL (root_app_base)) {
608                         /* N.B. new string is in the new domain */
609                         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, root_app_base), TRUE);
610                         MonoStringHandle s = mono_string_new_utf16_handle (data, mono_string_chars (MONO_HANDLE_RAW (root_app_base)), mono_string_handle_length (root_app_base), error);
611                         mono_gchandle_free (gchandle);
612                         if (!is_ok (error)) {
613                                 g_free (data->friendly_name);
614                                 goto leave;
615                         }
616                         MONO_HANDLE_SET (setup, application_base, s);
617                 }
618         }
619
620         mono_context_init_checked (data, error);
621         if (!is_ok (error))
622                 goto leave;
623
624         data->setup = MONO_HANDLE_RAW (copy_app_domain_setup (data, setup, error));
625         if (!mono_error_ok (error)) {
626                 g_free (data->friendly_name);
627                 goto leave;
628         }
629
630         mono_domain_set_options_from_config (data);
631         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
632
633 #ifndef DISABLE_SHADOW_COPY
634         /*FIXME, guard this for when the debugger is not running */
635         char *shadow_location = get_shadow_assembly_location_base (data, error);
636         if (!mono_error_ok (error)) {
637                 g_free (data->friendly_name);
638                 goto leave;
639         }
640
641         g_free (shadow_location);
642 #endif
643
644         create_domain_objects (data);
645
646         MONO_HANDLE_ASSIGN (result, ad);
647 leave:
648         HANDLE_FUNCTION_RETURN_REF (MonoAppDomain, result);
649 }
650
651 /**
652  * mono_domain_has_type_resolve:
653  * @domain: application domains being looked up
654  *
655  * Returns: TRUE if the AppDomain.TypeResolve field has been
656  * set.
657  */
658 gboolean
659 mono_domain_has_type_resolve (MonoDomain *domain)
660 {
661         static MonoClassField *field = NULL;
662         MonoObject *o;
663
664         if (field == NULL) {
665                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
666                 g_assert (field);
667         }
668
669         /*pedump doesn't create an appdomin, so the domain object doesn't exist.*/
670         if (!domain->domain)
671                 return FALSE;
672
673         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
674         return o != NULL;
675 }
676
677 /**
678  * mono_domain_try_type_resolve:
679  * @domain: application domainwhere the name where the type is going to be resolved
680  * @name: the name of the type to resolve or NULL.
681  * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
682  *
683  * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
684  * the assembly that matches name.
685  *
686  * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
687  *
688  * Returns: A MonoReflectionAssembly or NULL if not found
689  */
690 MonoReflectionAssembly *
691 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
692 {
693         MonoError error;
694         MonoReflectionAssembly *ret = mono_domain_try_type_resolve_checked (domain, name, tb, &error);
695         mono_error_cleanup (&error);
696
697         return ret;
698 }
699
700 MonoReflectionAssembly *
701 mono_domain_try_type_resolve_checked (MonoDomain *domain, char *name, MonoObject *tb, MonoError *error)
702 {
703         static MonoMethod *method = NULL;
704         MonoReflectionAssembly *ret;
705         void *params [1];
706
707         error_init (error);
708
709         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
710
711         if (method == NULL) {
712                 method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoTypeResolve", -1);
713                 if (method == NULL) {
714                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
715                         return NULL;
716                 }
717         }
718
719         if (name)
720                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
721         else
722                 *params = tb;
723
724         ret = (MonoReflectionAssembly *) mono_runtime_invoke_checked (method, domain->domain, params, error);
725         return_val_if_nok (error, NULL);
726
727         return ret;
728 }
729
730 /**
731  * mono_domain_owns_vtable_slot:
732  *
733  *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
734  */
735 gboolean
736 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
737 {
738         gboolean res;
739
740         mono_domain_lock (domain);
741         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
742         mono_domain_unlock (domain);
743         return res;
744 }
745
746 /**
747  * mono_domain_set:
748  * @domain: domain
749  * @force: force setting.
750  *
751  * Set the current appdomain to @domain. If @force is set, set it even
752  * if it is being unloaded.
753  *
754  * Returns:
755  *   TRUE on success;
756  *   FALSE if the domain is unloaded
757  */
758 gboolean
759 mono_domain_set (MonoDomain *domain, gboolean force)
760 {
761         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
762                 return FALSE;
763
764         mono_domain_set_internal (domain);
765
766         return TRUE;
767 }
768
769 MonoObjectHandle
770 ves_icall_System_AppDomain_GetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoError *error)
771 {
772         error_init (error);
773
774         if (MONO_HANDLE_IS_NULL (name)) {
775                 mono_error_set_argument_null (error, "name", "");
776                 return NULL_HANDLE;
777         }
778
779         g_assert (!MONO_HANDLE_IS_NULL (ad));
780         MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
781         g_assert (add);
782
783         char *str = mono_string_handle_to_utf8 (name, error);
784         return_val_if_nok (error, NULL_HANDLE);
785
786         mono_domain_lock (add);
787
788         MonoAppDomainSetupHandle ad_setup = MONO_HANDLE_NEW (MonoAppDomainSetup, add->setup);
789         MonoStringHandle o;
790         if (!strcmp (str, "APPBASE"))
791                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_base);
792         else if (!strcmp (str, "APP_CONFIG_FILE"))
793                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, configuration_file);
794         else if (!strcmp (str, "DYNAMIC_BASE"))
795                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, dynamic_base);
796         else if (!strcmp (str, "APP_NAME"))
797                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, application_name);
798         else if (!strcmp (str, "CACHE_BASE"))
799                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, cache_path);
800         else if (!strcmp (str, "PRIVATE_BINPATH"))
801                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path);
802         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
803                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, private_bin_path_probe);
804         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
805                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_directories);
806         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
807                 o = MONO_HANDLE_NEW_GET (MonoString, ad_setup, shadow_copy_files);
808         else 
809                 o = MONO_HANDLE_NEW (MonoString, mono_g_hash_table_lookup (add->env, MONO_HANDLE_RAW (name)));
810
811         mono_domain_unlock (add);
812         g_free (str);
813
814         return MONO_HANDLE_CAST (MonoObject, o);
815 }
816
817 void
818 ves_icall_System_AppDomain_SetData (MonoAppDomainHandle ad, MonoStringHandle name, MonoObjectHandle data, MonoError *error)
819 {
820         error_init (error);
821
822         if (MONO_HANDLE_IS_NULL (name)) {
823                 mono_error_set_argument_null (error, "name", "");
824                 return;
825         }
826
827         g_assert (!MONO_HANDLE_IS_NULL (ad));
828         MonoDomain *add = MONO_HANDLE_GETVAL (ad, data);
829         g_assert (add);
830
831         mono_domain_lock (add);
832
833         mono_g_hash_table_insert (add->env, MONO_HANDLE_RAW (name), MONO_HANDLE_RAW (data));
834
835         mono_domain_unlock (add);
836 }
837
838 MonoAppDomainSetupHandle
839 ves_icall_System_AppDomain_getSetup (MonoAppDomainHandle ad, MonoError *error)
840 {
841         error_init (error);
842         g_assert (!MONO_HANDLE_IS_NULL (ad));
843         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
844         g_assert (domain);
845
846         return MONO_HANDLE_NEW (MonoAppDomainSetup, domain->setup);
847 }
848
849 MonoStringHandle
850 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomainHandle ad, MonoError *error)
851 {
852         error_init (error);
853         g_assert (!MONO_HANDLE_IS_NULL (ad));
854         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
855         g_assert (domain);
856
857         return mono_string_new_handle (domain, domain->friendly_name, error);
858 }
859
860 MonoAppDomainHandle
861 ves_icall_System_AppDomain_getCurDomain (MonoError *error)
862 {
863         error_init (error);
864         MonoDomain *add = mono_domain_get ();
865
866         return MONO_HANDLE_NEW (MonoAppDomain, add->domain);
867 }
868
869 MonoAppDomainHandle
870 ves_icall_System_AppDomain_getRootDomain (MonoError *error)
871 {
872         error_init (error);
873         MonoDomain *root = mono_get_root_domain ();
874
875         return MONO_HANDLE_NEW (MonoAppDomain, root->domain);
876 }
877
878 MonoBoolean
879 ves_icall_System_CLRConfig_CheckThrowUnobservedTaskExceptions ()
880 {
881         MonoDomain *domain = mono_domain_get ();
882
883         return domain->throw_unobserved_task_exceptions;
884 }
885
886 static char*
887 get_attribute_value (const gchar **attribute_names, 
888                      const gchar **attribute_values, 
889                      const char *att_name)
890 {
891         int n;
892         for (n = 0; attribute_names [n] != NULL; n++) {
893                 if (strcmp (attribute_names [n], att_name) == 0)
894                         return g_strdup (attribute_values [n]);
895         }
896         return NULL;
897 }
898
899 static void
900 start_element (GMarkupParseContext *context, 
901                const gchar         *element_name,
902                const gchar        **attribute_names,
903                const gchar        **attribute_values,
904                gpointer             user_data,
905                GError             **error)
906 {
907         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
908         
909         if (strcmp (element_name, "runtime") == 0) {
910                 runtime_config->runtime_count++;
911                 return;
912         }
913
914         if (strcmp (element_name, "assemblyBinding") == 0) {
915                 runtime_config->assemblybinding_count++;
916                 return;
917         }
918
919         if (runtime_config->runtime_count != 1)
920                 return;
921
922         if (strcmp (element_name, "ThrowUnobservedTaskExceptions") == 0) {
923                 const char *value = get_attribute_value (attribute_names, attribute_values, "enabled");
924
925                 if (value && g_ascii_strcasecmp (value, "true") == 0)
926                         runtime_config->domain->throw_unobserved_task_exceptions = TRUE;
927         }
928
929         if (runtime_config->assemblybinding_count != 1)
930                 return;
931
932         if (strcmp (element_name, "probing") != 0)
933                 return;
934
935         g_free (runtime_config->domain->private_bin_path);
936         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
937         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
938                 g_free (runtime_config->domain->private_bin_path);
939                 runtime_config->domain->private_bin_path = NULL;
940                 return;
941         }
942 }
943
944 static void
945 end_element (GMarkupParseContext *context,
946              const gchar         *element_name,
947              gpointer             user_data,
948              GError             **error)
949 {
950         RuntimeConfig *runtime_config = (RuntimeConfig *)user_data;
951         if (strcmp (element_name, "runtime") == 0)
952                 runtime_config->runtime_count--;
953         else if (strcmp (element_name, "assemblyBinding") == 0)
954                 runtime_config->assemblybinding_count--;
955 }
956
957 static void
958 parse_error   (GMarkupParseContext *context, GError *error, gpointer user_data)
959 {
960         RuntimeConfig *state = (RuntimeConfig *)user_data;
961         const gchar *msg;
962         const gchar *filename;
963
964         filename = state && state->filename ? (gchar *) state->filename : "<unknown>";
965         msg = error && error->message ? error->message : "";
966         g_warning ("Error parsing %s: %s", filename, msg);
967 }
968
969 static const GMarkupParser
970 mono_parser = {
971         start_element,
972         end_element,
973         NULL,
974         NULL,
975         parse_error
976 };
977
978 void
979 mono_domain_set_options_from_config (MonoDomain *domain)
980 {
981         MonoError error;
982         gchar *config_file_name = NULL, *text = NULL, *config_file_path = NULL;
983         gsize len;
984         GMarkupParseContext *context;
985         RuntimeConfig runtime_config;
986         gint offset;
987         
988         if (!domain || !domain->setup || !domain->setup->configuration_file)
989                 return;
990
991         config_file_name = mono_string_to_utf8_checked (domain->setup->configuration_file, &error);
992         if (!mono_error_ok (&error)) {
993                 mono_error_cleanup (&error);
994                 goto free_and_out;
995         }
996
997         config_file_path = mono_portability_find_file (config_file_name, TRUE);
998         if (!config_file_path)
999                 config_file_path = config_file_name;
1000
1001         if (!g_file_get_contents (config_file_path, &text, &len, NULL))
1002                 goto free_and_out;
1003
1004         runtime_config.runtime_count = 0;
1005         runtime_config.assemblybinding_count = 0;
1006         runtime_config.domain = domain;
1007         runtime_config.filename = config_file_path;
1008         
1009         offset = 0;
1010         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
1011                 offset = 3; /* Skip UTF-8 BOM */
1012
1013         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, &runtime_config, NULL);
1014         if (g_markup_parse_context_parse (context, text + offset, len - offset, NULL))
1015                 g_markup_parse_context_end_parse (context, NULL);
1016         g_markup_parse_context_free (context);
1017
1018   free_and_out:
1019         g_free (text);
1020         if (config_file_name != config_file_path)
1021                 g_free (config_file_name);
1022         g_free (config_file_path);
1023 }
1024
1025 MonoAppDomainHandle
1026 ves_icall_System_AppDomain_createDomain (MonoStringHandle friendly_name, MonoAppDomainSetupHandle setup, MonoError *error)
1027 {
1028         error_init (error);
1029         MonoAppDomainHandle ad = MONO_HANDLE_NEW (MonoAppDomain, NULL);
1030
1031 #ifdef DISABLE_APPDOMAINS
1032         mono_error_set_not_supported (error, "AppDomain creation is not supported on this runtime.");
1033 #else
1034         char *fname;
1035
1036         fname = mono_string_handle_to_utf8 (friendly_name, error);
1037         return_val_if_nok (error, ad);
1038         ad = mono_domain_create_appdomain_internal (fname, setup, error);
1039         g_free (fname);
1040 #endif
1041         return ad;
1042 }
1043
1044 static gboolean
1045 add_assembly_to_array (MonoDomain *domain, MonoArrayHandle dest, int dest_idx, MonoAssembly* assm, MonoError *error)
1046 {
1047         HANDLE_FUNCTION_ENTER ();
1048         error_init (error);
1049         MonoReflectionAssemblyHandle assm_obj = mono_assembly_get_object_handle (domain, assm, error);
1050         if (!is_ok (error))
1051                 goto leave;
1052         MONO_HANDLE_ARRAY_SETREF (dest, dest_idx, assm_obj);
1053 leave:
1054         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
1055 }
1056
1057 MonoArrayHandle
1058 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomainHandle ad, MonoBoolean refonly, MonoError *error)
1059 {
1060         error_init (error);
1061         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
1062         MonoAssembly* ass;
1063         GSList *tmp;
1064         int i;
1065         GPtrArray *assemblies;
1066
1067         /* 
1068          * Make a copy of the list of assemblies because we can't hold the assemblies
1069          * lock while creating objects etc.
1070          */
1071         assemblies = g_ptr_array_new ();
1072         /* Need to skip internal assembly builders created by remoting */
1073         mono_domain_assemblies_lock (domain);
1074         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1075                 ass = (MonoAssembly *)tmp->data;
1076                 if (refonly != ass->ref_only)
1077                         continue;
1078                 if (ass->corlib_internal)
1079                         continue;
1080                 g_ptr_array_add (assemblies, ass);
1081         }
1082         mono_domain_assemblies_unlock (domain);
1083
1084         MonoArrayHandle res = mono_array_new_handle (domain, mono_class_get_assembly_class (), assemblies->len, error);
1085         if (!is_ok (error))
1086                 goto leave;
1087         for (i = 0; i < assemblies->len; ++i) {
1088                 if (!add_assembly_to_array (domain, res, i, (MonoAssembly *)g_ptr_array_index (assemblies, i), error))
1089                         goto leave;
1090         }
1091
1092 leave:
1093         g_ptr_array_free (assemblies, TRUE);
1094         return res;
1095 }
1096
1097 MonoAssembly*
1098 mono_try_assembly_resolve (MonoDomain *domain, const char *fname_raw, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1099 {
1100         HANDLE_FUNCTION_ENTER ();
1101         error_init (error);
1102         MonoAssembly *result = NULL;
1103         MonoStringHandle fname = mono_string_new_handle (domain, fname_raw, error);
1104         if (!is_ok (error))
1105                 goto leave;
1106         result = mono_try_assembly_resolve_handle (domain, fname, requesting, refonly, error);
1107 leave:
1108         HANDLE_FUNCTION_RETURN_VAL (result);
1109 }
1110
1111 MonoAssembly*
1112 mono_try_assembly_resolve_handle (MonoDomain *domain, MonoStringHandle fname, MonoAssembly *requesting, gboolean refonly, MonoError *error)
1113 {
1114         MonoAssembly *ret = NULL;
1115         MonoMethod *method;
1116         MonoBoolean isrefonly;
1117         gpointer params [3];
1118
1119         error_init (error);
1120
1121         if (mono_runtime_get_no_exec ())
1122                 return ret;
1123
1124         g_assert (domain != NULL && !MONO_HANDLE_IS_NULL (fname));
1125
1126         method = mono_class_get_method_from_name (mono_class_get_appdomain_class (), "DoAssemblyResolve", -1);
1127         g_assert (method != NULL);
1128
1129         isrefonly = refonly ? 1 : 0;
1130         MonoReflectionAssemblyHandle requesting_handle;
1131         if (requesting) {
1132                 requesting_handle = mono_assembly_get_object_handle (domain, requesting, error);
1133                 return_val_if_nok (error, ret);
1134         }
1135         params [0] = MONO_HANDLE_RAW (fname);
1136         params[1] = requesting ? MONO_HANDLE_RAW (requesting_handle) : NULL;
1137         params [2] = &isrefonly;
1138         MonoReflectionAssemblyHandle result = MONO_HANDLE_NEW (MonoReflectionAssembly, mono_runtime_invoke_checked (method, domain->domain, params, error));
1139         ret = !MONO_HANDLE_IS_NULL (result) ? MONO_HANDLE_GETVAL (result, assembly) : NULL;
1140         return ret;
1141 }
1142
1143 MonoAssembly *
1144 mono_domain_assembly_postload_search (MonoAssemblyName *aname, MonoAssembly *requesting,
1145                                                                           gboolean refonly)
1146 {
1147         MonoError error;
1148         MonoAssembly *assembly;
1149         MonoDomain *domain = mono_domain_get ();
1150         char *aname_str;
1151
1152         aname_str = mono_stringify_assembly_name (aname);
1153
1154         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
1155
1156         assembly = mono_try_assembly_resolve (domain, aname_str, requesting, refonly, &error);
1157         g_free (aname_str);
1158         mono_error_cleanup (&error);
1159
1160         return assembly;
1161 }
1162         
1163 /*
1164  * LOCKING: assumes assemblies_lock in the domain is already locked.
1165  */
1166 static void
1167 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
1168 {
1169         gint i;
1170         GSList *tmp;
1171         gboolean destroy_ht = FALSE;
1172
1173         if (!ass->aname.name)
1174                 return;
1175
1176         if (!ht) {
1177                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
1178                 destroy_ht = TRUE;
1179                 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1180                         g_hash_table_insert (ht, tmp->data, tmp->data);
1181                 }
1182         }
1183
1184         /* FIXME: handle lazy loaded assemblies */
1185
1186         if (!g_hash_table_lookup (ht, ass)) {
1187                 mono_assembly_addref (ass);
1188                 g_hash_table_insert (ht, ass, ass);
1189                 domain->domain_assemblies = g_slist_append (domain->domain_assemblies, ass);
1190                 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);
1191         }
1192
1193         if (ass->image->references) {
1194                 for (i = 0; i < ass->image->nreferences; i++) {
1195                         if (ass->image->references[i] && ass->image->references [i] != REFERENCE_MISSING) {
1196                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
1197                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
1198                                 }
1199                         }
1200                 }
1201         }
1202         if (destroy_ht)
1203                 g_hash_table_destroy (ht);
1204 }
1205
1206 static void
1207 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
1208 {
1209         static MonoClassField *assembly_load_field;
1210         static MonoMethod *assembly_load_method;
1211         MonoError error;
1212         MonoDomain *domain = mono_domain_get ();
1213         MonoClass *klass;
1214         gpointer load_value;
1215         void *params [1];
1216
1217         if (!domain->domain)
1218                 /* This can happen during startup */
1219                 return;
1220 #ifdef ASSEMBLY_LOAD_DEBUG
1221         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
1222 #endif
1223         klass = domain->domain->mbr.obj.vtable->klass;
1224
1225         mono_domain_assemblies_lock (domain);
1226         add_assemblies_to_domain (domain, assembly, NULL);
1227         mono_domain_assemblies_unlock (domain);
1228
1229         if (assembly_load_field == NULL) {
1230                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
1231                 g_assert (assembly_load_field);
1232         }
1233
1234         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
1235         if (load_value == NULL) {
1236                 /* No events waiting to be triggered */
1237                 return;
1238         }
1239
1240         MonoReflectionAssemblyHandle ref_assembly = mono_assembly_get_object_handle (domain, assembly, &error);
1241         mono_error_assert_ok (&error);
1242
1243         if (assembly_load_method == NULL) {
1244                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
1245                 g_assert (assembly_load_method);
1246         }
1247
1248         *params = MONO_HANDLE_RAW(ref_assembly);
1249
1250         mono_runtime_invoke_checked (assembly_load_method, domain->domain, params, &error);
1251         mono_error_cleanup (&error);
1252 }
1253
1254 /*
1255  * LOCKING: Acquires the domain assemblies lock.
1256  */
1257 static void
1258 set_domain_search_path (MonoDomain *domain)
1259 {
1260         MonoError error;
1261         MonoAppDomainSetup *setup;
1262         gchar **tmp;
1263         gchar *search_path = NULL;
1264         gint i;
1265         gint npaths = 0;
1266         gchar **pvt_split = NULL;
1267         GError *gerror = NULL;
1268         gint appbaselen = -1;
1269
1270         /* 
1271          * We use the low-level domain assemblies lock, since this is called from
1272          * assembly loads hooks, which means this thread might hold the loader lock.
1273          */
1274         mono_domain_assemblies_lock (domain);
1275
1276         if (!domain->setup) {
1277                 mono_domain_assemblies_unlock (domain);
1278                 return;
1279         }
1280
1281         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1282                 mono_domain_assemblies_unlock (domain);
1283                 return;
1284         }
1285         setup = domain->setup;
1286         if (!setup->application_base) {
1287                 mono_domain_assemblies_unlock (domain);
1288                 return; /* Must set application base to get private path working */
1289         }
1290
1291         npaths++;
1292         
1293         if (setup->private_bin_path) {
1294                 search_path = mono_string_to_utf8_checked (setup->private_bin_path, &error);
1295                 if (!mono_error_ok (&error)) { /*FIXME maybe we should bubble up the error.*/
1296                         g_warning ("Could not decode AppDomain search path since it contains invalid characters");
1297                         mono_error_cleanup (&error);
1298                         mono_domain_assemblies_unlock (domain);
1299                         return;
1300                 }
1301         }
1302         
1303         if (domain->private_bin_path) {
1304                 if (search_path == NULL)
1305                         search_path = domain->private_bin_path;
1306                 else {
1307                         gchar *tmp2 = search_path;
1308                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1309                         g_free (tmp2);
1310                 }
1311         }
1312         
1313         if (search_path) {
1314                 /*
1315                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1316                  * directories relative to ApplicationBase separated by semicolons (see
1317                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1318                  * The loop below copes with the fact that some Unix applications may use ':' (or
1319                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1320                  * ';' for the subsequent split.
1321                  *
1322                  * The issue was reported in bug #81446
1323                  */
1324
1325 #ifndef TARGET_WIN32
1326                 gint slen;
1327
1328                 slen = strlen (search_path);
1329                 for (i = 0; i < slen; i++)
1330                         if (search_path [i] == ':')
1331                                 search_path [i] = ';';
1332 #endif
1333                 
1334                 pvt_split = g_strsplit (search_path, ";", 1000);
1335                 g_free (search_path);
1336                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1337         }
1338
1339         if (!npaths) {
1340                 if (pvt_split)
1341                         g_strfreev (pvt_split);
1342                 /*
1343                  * Don't do this because the first time is called, the domain
1344                  * setup is not finished.
1345                  *
1346                  * domain->search_path = g_malloc (sizeof (char *));
1347                  * domain->search_path [0] = NULL;
1348                 */
1349                 mono_domain_assemblies_unlock (domain);
1350                 return;
1351         }
1352
1353         if (domain->search_path)
1354                 g_strfreev (domain->search_path);
1355
1356         tmp = (gchar **)g_malloc ((npaths + 1) * sizeof (gchar *));
1357         tmp [npaths] = NULL;
1358
1359         *tmp = mono_string_to_utf8_checked (setup->application_base, &error);
1360         if (!mono_error_ok (&error)) {
1361                 mono_error_cleanup (&error);
1362                 g_strfreev (pvt_split);
1363                 g_free (tmp);
1364
1365                 mono_domain_assemblies_unlock (domain);
1366                 return;
1367         }
1368
1369         domain->search_path = tmp;
1370
1371         /* FIXME: is this needed? */
1372         if (strncmp (*tmp, "file://", 7) == 0) {
1373                 gchar *file = *tmp;
1374                 gchar *uri = *tmp;
1375                 gchar *tmpuri;
1376
1377                 if (uri [7] != '/')
1378                         uri = g_strdup_printf ("file:///%s", uri + 7);
1379
1380                 tmpuri = uri;
1381                 uri = mono_escape_uri_string (tmpuri);
1382                 *tmp = g_filename_from_uri (uri, NULL, &gerror);
1383                 g_free (uri);
1384
1385                 if (tmpuri != file)
1386                         g_free (tmpuri);
1387
1388                 if (gerror != NULL) {
1389                         g_warning ("%s\n", gerror->message);
1390                         g_error_free (gerror);
1391                         *tmp = file;
1392                 } else {
1393                         g_free (file);
1394                 }
1395         }
1396
1397         for (i = 1; pvt_split && i < npaths; i++) {
1398                 if (g_path_is_absolute (pvt_split [i - 1])) {
1399                         tmp [i] = g_strdup (pvt_split [i - 1]);
1400                 } else {
1401                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1402                 }
1403
1404                 if (strchr (tmp [i], '.')) {
1405                         gchar *reduced;
1406                         gchar *freeme;
1407
1408                         reduced = mono_path_canonicalize (tmp [i]);
1409                         if (appbaselen == -1)
1410                                 appbaselen = strlen (tmp [0]);
1411
1412                         if (strncmp (tmp [0], reduced, appbaselen)) {
1413                                 g_free (reduced);
1414                                 g_free (tmp [i]);
1415                                 tmp [i] = g_strdup ("");
1416                                 continue;
1417                         }
1418
1419                         freeme = tmp [i];
1420                         tmp [i] = reduced;
1421                         g_free (freeme);
1422                 }
1423         }
1424         
1425         if (setup->private_bin_path_probe != NULL) {
1426                 g_free (tmp [0]);
1427                 tmp [0] = g_strdup ("");
1428         }
1429                 
1430         domain->setup->path_changed = FALSE;
1431
1432         g_strfreev (pvt_split);
1433
1434         mono_domain_assemblies_unlock (domain);
1435 }
1436
1437 #ifdef DISABLE_SHADOW_COPY
1438 gboolean
1439 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1440 {
1441         return FALSE;
1442 }
1443
1444 char *
1445 mono_make_shadow_copy (const char *filename, MonoError *error)
1446 {
1447         error_init (error);
1448         return (char *) filename;
1449 }
1450 #else
1451 static gboolean
1452 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1453 {
1454         guint16 *orig, *dest;
1455         gboolean copy_result;
1456         gint32 copy_error;
1457         
1458         strcpy (src + srclen - tail_len, extension);
1459
1460         if (IS_PORTABILITY_CASE) {
1461                 gchar *file = mono_portability_find_file (src, TRUE);
1462
1463                 if (file == NULL)
1464                         return TRUE;
1465
1466                 g_free (file);
1467         } else if (!g_file_test (src, G_FILE_TEST_IS_REGULAR)) {
1468                 return TRUE;
1469         }
1470
1471         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1472
1473         strcpy (target + targetlen - tail_len, extension);
1474         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1475         
1476         mono_w32file_delete (dest);
1477
1478         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1479
1480         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1481          * overwritten when updated in their original locations. */
1482         if (copy_result)
1483                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1484
1485         g_free (orig);
1486         g_free (dest);
1487         
1488         return copy_result;
1489 }
1490
1491 static gint32 
1492 get_cstring_hash (const char *str)
1493 {
1494         int len, i;
1495         const char *p;
1496         gint32 h = 0;
1497         
1498         if (!str || !str [0])
1499                 return 0;
1500                 
1501         len = strlen (str);
1502         p = str;
1503         for (i = 0; i < len; i++) {
1504                 h = (h << 5) - h + *p;
1505                 p++;
1506         }
1507         
1508         return h;
1509 }
1510
1511 /*
1512  * Returned memory is malloc'd. Called must free it 
1513  */
1514 static char *
1515 get_shadow_assembly_location_base (MonoDomain *domain, MonoError *error)
1516 {
1517         MonoAppDomainSetup *setup;
1518         char *cache_path, *appname;
1519         char *userdir;
1520         char *location;
1521
1522         error_init (error);
1523         
1524         setup = domain->setup;
1525         if (setup->cache_path != NULL && setup->application_name != NULL) {
1526                 cache_path = mono_string_to_utf8_checked (setup->cache_path, error);
1527                 return_val_if_nok (error, NULL);
1528
1529 #ifndef TARGET_WIN32
1530                 {
1531                         gint i;
1532                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1533                                 if (cache_path [i] == '\\')
1534                                         cache_path [i] = '/';
1535                 }
1536 #endif
1537
1538                 appname = mono_string_to_utf8_checked (setup->application_name, error);
1539                 if (!mono_error_ok (error)) {
1540                         g_free (cache_path);
1541                         return NULL;
1542                 }
1543
1544                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1545                 g_free (appname);
1546                 g_free (cache_path);
1547         } else {
1548                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1549                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1550                 g_free (userdir);
1551         }
1552         return location;
1553 }
1554
1555 static char *
1556 get_shadow_assembly_location (const char *filename, MonoError *error)
1557 {
1558         gint32 hash = 0, hash2 = 0;
1559         char name_hash [9];
1560         char path_hash [30];
1561         char *bname = g_path_get_basename (filename);
1562         char *dirname = g_path_get_dirname (filename);
1563         char *location, *tmploc;
1564         MonoDomain *domain = mono_domain_get ();
1565
1566         error_init (error);
1567         
1568         hash = get_cstring_hash (bname);
1569         hash2 = get_cstring_hash (dirname);
1570         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1571         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1572         tmploc = get_shadow_assembly_location_base (domain, error);
1573         if (!mono_error_ok (error)) {
1574                 g_free (bname);
1575                 g_free (dirname);
1576                 return NULL;
1577         }
1578
1579         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1580         g_free (tmploc);
1581         g_free (bname);
1582         g_free (dirname);
1583         return location;
1584 }
1585
1586 static gboolean
1587 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1588 {
1589         struct stat sbuf_dest;
1590         gchar *stat_src;
1591         gchar *real_src = mono_portability_find_file (src, TRUE);
1592
1593         if (!real_src)
1594                 stat_src = (gchar*)src;
1595         else
1596                 stat_src = real_src;
1597
1598         if (stat (stat_src, sbuf_src) == -1) {
1599                 time_t tnow = time (NULL);
1600
1601                 if (real_src)
1602                         g_free (real_src);
1603
1604                 memset (sbuf_src, 0, sizeof (*sbuf_src));
1605                 sbuf_src->st_mtime = tnow;
1606                 sbuf_src->st_atime = tnow;
1607                 return TRUE;
1608         }
1609
1610         if (real_src)
1611                 g_free (real_src);
1612
1613         if (stat (dest, &sbuf_dest) == -1)
1614                 return TRUE;
1615         
1616         if (sbuf_src->st_size == sbuf_dest.st_size &&
1617             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1618                 return FALSE;
1619
1620         return TRUE;
1621 }
1622
1623 static gboolean
1624 shadow_copy_create_ini (const char *shadow, const char *filename)
1625 {
1626         char *dir_name;
1627         char *ini_file;
1628         guint16 *u16_ini;
1629         gboolean result;
1630         guint32 n;
1631         HANDLE *handle;
1632         gchar *full_path;
1633
1634         dir_name = g_path_get_dirname (shadow);
1635         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1636         g_free (dir_name);
1637         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1638                 g_free (ini_file);
1639                 return TRUE;
1640         }
1641
1642         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1643         g_free (ini_file);
1644         if (!u16_ini) {
1645                 return FALSE;
1646         }
1647         handle = (void **)mono_w32file_create (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, FileAttributes_Normal);
1648         g_free (u16_ini);
1649         if (handle == INVALID_HANDLE_VALUE) {
1650                 return FALSE;
1651         }
1652
1653         full_path = mono_path_resolve_symlinks (filename);
1654         result = mono_w32file_write (handle, full_path, strlen (full_path), &n);
1655         g_free (full_path);
1656         mono_w32file_close (handle);
1657         return result;
1658 }
1659
1660 gboolean
1661 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1662 {
1663         MonoError error;
1664         MonoAppDomainSetup *setup;
1665         gchar *all_dirs;
1666         gchar **dir_ptr;
1667         gchar **directories;
1668         gchar *shadow_status_string;
1669         gchar *base_dir;
1670         gboolean shadow_enabled;
1671         gboolean found = FALSE;
1672
1673         if (domain == NULL)
1674                 return FALSE;
1675
1676         setup = domain->setup;
1677         if (setup == NULL || setup->shadow_copy_files == NULL)
1678                 return FALSE;
1679
1680         shadow_status_string = mono_string_to_utf8_checked (setup->shadow_copy_files, &error);
1681         if (!mono_error_ok (&error)) {
1682                 mono_error_cleanup (&error);
1683                 return FALSE;
1684         }
1685         shadow_enabled = !g_ascii_strncasecmp (shadow_status_string, "true", 4);
1686         g_free (shadow_status_string);
1687
1688         if (!shadow_enabled)
1689                 return FALSE;
1690
1691         if (setup->shadow_copy_directories == NULL)
1692                 return TRUE;
1693
1694         /* Is dir_name a shadow_copy destination already? */
1695         base_dir = get_shadow_assembly_location_base (domain, &error);
1696         if (!mono_error_ok (&error)) {
1697                 mono_error_cleanup (&error);
1698                 return FALSE;
1699         }
1700
1701         if (strstr (dir_name, base_dir)) {
1702                 g_free (base_dir);
1703                 return TRUE;
1704         }
1705         g_free (base_dir);
1706
1707         all_dirs = mono_string_to_utf8_checked (setup->shadow_copy_directories, &error);
1708         if (!mono_error_ok (&error)) {
1709                 mono_error_cleanup (&error);
1710                 return FALSE;
1711         }
1712
1713         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1714         dir_ptr = directories;
1715         while (*dir_ptr) {
1716                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1717                         found = TRUE;
1718                         break;
1719                 }
1720                 dir_ptr++;
1721         }
1722         g_strfreev (directories);
1723         g_free (all_dirs);
1724         return found;
1725 }
1726
1727 /*
1728 This function raises exceptions so it can cause as sorts of nasty stuff if called
1729 while holding a lock.
1730 Returns old file name if shadow copy is disabled, new shadow copy file name if successful
1731 or NULL if source file not found.
1732 FIXME bubble up the error instead of raising it here
1733 */
1734 char *
1735 mono_make_shadow_copy (const char *filename, MonoError *oerror)
1736 {
1737         MonoError error;
1738         gchar *sibling_source, *sibling_target;
1739         gint sibling_source_len, sibling_target_len;
1740         guint16 *orig, *dest;
1741         guint32 attrs;
1742         char *shadow;
1743         gboolean copy_result;
1744         struct stat src_sbuf;
1745         struct utimbuf utbuf;
1746         char *dir_name = g_path_get_dirname (filename);
1747         MonoDomain *domain = mono_domain_get ();
1748         char *shadow_dir;
1749         gint32 copy_error;
1750
1751         error_init (oerror);
1752
1753         set_domain_search_path (domain);
1754
1755         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1756                 g_free (dir_name);
1757                 return (char *) filename;
1758         }
1759
1760         /* Is dir_name a shadow_copy destination already? */
1761         shadow_dir = get_shadow_assembly_location_base (domain, &error);
1762         if (!mono_error_ok (&error)) {
1763                 mono_error_cleanup (&error);
1764                 g_free (dir_name);
1765                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in shadow directory name).");
1766                 return NULL;
1767         }
1768
1769         if (strstr (dir_name, shadow_dir)) {
1770                 g_free (shadow_dir);
1771                 g_free (dir_name);
1772                 return (char *) filename;
1773         }
1774         g_free (shadow_dir);
1775         g_free (dir_name);
1776
1777         shadow = get_shadow_assembly_location (filename, &error);
1778         if (!mono_error_ok (&error)) {
1779                 mono_error_cleanup (&error);
1780                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (invalid characters in file name).");
1781                 return NULL;
1782         }
1783
1784         if (g_ensure_directory_exists (shadow) == FALSE) {
1785                 g_free (shadow);
1786                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (ensure directory exists).");
1787                 return NULL;
1788         }       
1789
1790         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1791                 return (char*) shadow;
1792
1793         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1794         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1795         mono_w32file_delete (dest);
1796
1797         /* Fix for bug #17066 - make sure we can read the file. if not then don't error but rather 
1798          * let the assembly fail to load. This ensures you can do Type.GetType("NS.T, NonExistantAssembly)
1799          * and not have it runtime error" */
1800         attrs = mono_w32file_get_attributes (orig);
1801         if (attrs == INVALID_FILE_ATTRIBUTES) {
1802                 g_free (shadow);
1803                 return (char *)filename;
1804         }
1805
1806         copy_result = mono_w32file_copy (orig, dest, TRUE, &copy_error);
1807
1808         /* Fix for bug #556884 - make sure the files have the correct mode so that they can be
1809          * overwritten when updated in their original locations. */
1810         if (copy_result)
1811                 copy_result = mono_w32file_set_attributes (dest, FILE_ATTRIBUTE_NORMAL);
1812
1813         g_free (dest);
1814         g_free (orig);
1815
1816         if (copy_result == FALSE) {
1817                 g_free (shadow);
1818
1819                 /* Fix for bug #17251 - if file not found try finding assembly by other means (it is not fatal error) */
1820                 if (mono_w32error_get_last() == ERROR_FILE_NOT_FOUND || mono_w32error_get_last() == ERROR_PATH_NOT_FOUND)
1821                         return NULL; /* file not found, shadow copy failed */
1822
1823                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy (mono_w32file_copy).");
1824                 return NULL;
1825         }
1826
1827         /* attempt to copy .mdb, .config if they exist */
1828         sibling_source = g_strconcat (filename, ".config", NULL);
1829         sibling_source_len = strlen (sibling_source);
1830         sibling_target = g_strconcat (shadow, ".config", NULL);
1831         sibling_target_len = strlen (sibling_target);
1832         
1833         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1834         if (copy_result)
1835                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1836         
1837         g_free (sibling_source);
1838         g_free (sibling_target);
1839         
1840         if (!copy_result)  {
1841                 g_free (shadow);
1842                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy of sibling data (mono_w32file_copy).");
1843                 return NULL;
1844         }
1845
1846         /* Create a .ini file containing the original assembly location */
1847         if (!shadow_copy_create_ini (shadow, filename)) {
1848                 g_free (shadow);
1849                 mono_error_set_execution_engine (oerror, "Failed to create shadow copy .ini file.");
1850                 return NULL;
1851         }
1852
1853         utbuf.actime = src_sbuf.st_atime;
1854         utbuf.modtime = src_sbuf.st_mtime;
1855         utime (shadow, &utbuf);
1856         
1857         return shadow;
1858 }
1859 #endif /* DISABLE_SHADOW_COPY */
1860
1861 MonoDomain *
1862 mono_domain_from_appdomain (MonoAppDomain *appdomain_raw)
1863 {
1864         HANDLE_FUNCTION_ENTER ();
1865         MONO_HANDLE_DCL (MonoAppDomain, appdomain);
1866         MonoDomain *result = mono_domain_from_appdomain_handle (appdomain);
1867         HANDLE_FUNCTION_RETURN_VAL (result);
1868 }
1869
1870 MonoDomain *
1871 mono_domain_from_appdomain_handle (MonoAppDomainHandle appdomain)
1872 {
1873         HANDLE_FUNCTION_ENTER ();
1874         MonoDomain *dom = NULL;
1875         if (MONO_HANDLE_IS_NULL (appdomain))
1876                 goto leave;
1877
1878         if (mono_class_is_transparent_proxy (mono_handle_class (appdomain))) {
1879                 MonoTransparentProxyHandle tp = MONO_HANDLE_CAST (MonoTransparentProxy, appdomain);
1880                 MonoRealProxyHandle rp = MONO_HANDLE_NEW_GET (MonoRealProxy, tp, rp);
1881                 
1882                 dom = mono_domain_get_by_id (MONO_HANDLE_GETVAL (rp, target_domain_id));
1883         } else
1884                 dom = MONO_HANDLE_GETVAL (appdomain, data);
1885
1886 leave:
1887         HANDLE_FUNCTION_RETURN_VAL (dom);
1888 }
1889
1890
1891 static gboolean
1892 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1893                                         const gchar *path3, const gchar *path4,
1894                                         gboolean refonly, gboolean is_private)
1895 {
1896         gchar *fullpath;
1897         gboolean found = FALSE;
1898         
1899         *assembly = NULL;
1900         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1901
1902         if (IS_PORTABILITY_SET) {
1903                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1904                 if (new_fullpath) {
1905                         g_free (fullpath);
1906                         fullpath = new_fullpath;
1907                         found = TRUE;
1908                 }
1909         } else
1910                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1911         
1912         if (found)
1913                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1914
1915         g_free (fullpath);
1916         return (*assembly != NULL);
1917 }
1918
1919 static MonoAssembly *
1920 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1921 {
1922         MonoAssembly *result = NULL;
1923         gchar **path;
1924         gchar *filename;
1925         const gchar *local_culture;
1926         gint len;
1927         gboolean is_private = FALSE;
1928
1929         if (!culture || *culture == '\0') {
1930                 local_culture = "";
1931         } else {
1932                 local_culture = culture;
1933         }
1934
1935         filename =  g_strconcat (name, ".dll", NULL);
1936         len = strlen (filename);
1937
1938         for (path = search_path; *path; path++) {
1939                 if (**path == '\0') {
1940                         is_private = TRUE;
1941                         continue; /* Ignore empty ApplicationBase */
1942                 }
1943
1944                 /* See test cases in bug #58992 and bug #57710 */
1945                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1946                 strcpy (filename + len - 4, ".dll");
1947                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1948                         break;
1949
1950                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1951                 strcpy (filename + len - 4, ".exe");
1952                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1953                         break;
1954
1955                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1956                 strcpy (filename + len - 4, ".dll");
1957                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1958                         break;
1959
1960                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1961                 strcpy (filename + len - 4, ".exe");
1962                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1963                         break;
1964         }
1965
1966         g_free (filename);
1967         return result;
1968 }
1969
1970 /*
1971  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1972  * and then from assemblies_path if any.
1973  * LOCKING: This is called from the assembly loading code, which means the caller
1974  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1975  */
1976 static MonoAssembly *
1977 mono_domain_assembly_preload (MonoAssemblyName *aname,
1978                               gchar **assemblies_path,
1979                               gpointer user_data)
1980 {
1981         MonoDomain *domain = mono_domain_get ();
1982         MonoAssembly *result = NULL;
1983         gboolean refonly = GPOINTER_TO_UINT (user_data);
1984
1985         set_domain_search_path (domain);
1986
1987         if (domain->search_path && domain->search_path [0] != NULL) {
1988                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1989         }
1990
1991         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1992                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1993         }
1994
1995         return result;
1996 }
1997
1998 /*
1999  * Check whenever a given assembly was already loaded in the current appdomain.
2000  */
2001 static MonoAssembly *
2002 mono_domain_assembly_search (MonoAssemblyName *aname,
2003                                                          gpointer user_data)
2004 {
2005         MonoDomain *domain = mono_domain_get ();
2006         GSList *tmp;
2007         MonoAssembly *ass;
2008         gboolean refonly = GPOINTER_TO_UINT (user_data);
2009
2010         mono_domain_assemblies_lock (domain);
2011         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
2012                 ass = (MonoAssembly *)tmp->data;
2013                 /* Dynamic assemblies can't match here in MS.NET */
2014                 if (assembly_is_dynamic (ass) || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
2015                         continue;
2016
2017                 mono_domain_assemblies_unlock (domain);
2018                 return ass;
2019         }
2020         mono_domain_assemblies_unlock (domain);
2021
2022         return NULL;
2023 }
2024
2025 MonoReflectionAssemblyHandle
2026 ves_icall_System_Reflection_Assembly_LoadFrom (MonoStringHandle fname, MonoBoolean refOnly, MonoError *error)
2027 {
2028         error_init (error);
2029         MonoDomain *domain = mono_domain_get ();
2030         char *name, *filename;
2031         MonoImageOpenStatus status = MONO_IMAGE_OK;
2032         MonoReflectionAssemblyHandle result = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2033
2034         name = NULL;
2035         result = NULL;
2036
2037         if (fname == NULL) {
2038                 mono_error_set_argument_null (error, "assemblyFile", "");
2039                 goto leave;
2040         }
2041                 
2042         name = filename = mono_string_handle_to_utf8 (fname, error);
2043         if (!is_ok (error))
2044                 goto leave;
2045         
2046         MonoAssembly *ass = mono_assembly_open_a_lot (filename, &status, refOnly, TRUE);
2047         
2048         if (!ass) {
2049                 if (status == MONO_IMAGE_IMAGE_INVALID)
2050                         mono_error_set_bad_image_name (error, g_strdup (name), "");
2051                 else
2052                         mono_error_set_assembly_load (error, g_strdup (name), "%s", "");
2053                 goto leave;
2054         }
2055
2056         result = mono_assembly_get_object_handle (domain, ass, error);
2057
2058 leave:
2059         g_free (name);
2060         return result;
2061 }
2062
2063 MonoReflectionAssemblyHandle
2064 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomainHandle ad, 
2065                                             MonoArrayHandle raw_assembly,
2066                                             MonoArrayHandle raw_symbol_store, MonoObjectHandle evidence,
2067                                             MonoBoolean refonly,
2068                                             MonoError *error)
2069 {
2070         error_init (error);
2071         MonoAssembly *ass;
2072         MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2073         MonoDomain *domain = MONO_HANDLE_GETVAL(ad, data);
2074         MonoImageOpenStatus status;
2075         guint32 raw_assembly_len = mono_array_handle_length (raw_assembly);
2076
2077         /* Copy the data ourselves to unpin the raw assembly byte array as soon as possible */
2078         char *assembly_data = (char*) g_try_malloc (raw_assembly_len);
2079         if (!assembly_data) {
2080                 mono_error_set_out_of_memory (error, "Could not allocate %ud bytes to copy raw assembly data", raw_assembly_len);
2081                 return refass;
2082         }
2083         uint32_t gchandle;
2084         mono_byte *raw_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_assembly, gchar, 0, &gchandle);
2085         memcpy (assembly_data, raw_data, raw_assembly_len);
2086         mono_gchandle_free (gchandle); /* unpin */
2087         MONO_HANDLE_ASSIGN (raw_assembly, NULL_HANDLE); /* don't reference the data anymore */
2088         
2089         MonoImage *image = mono_image_open_from_data_full (assembly_data, raw_assembly_len, FALSE, NULL, refonly);
2090
2091         if (!image) {
2092                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2093                 return refass;
2094         }
2095
2096         if (!MONO_HANDLE_IS_NULL(raw_symbol_store)) {
2097                 guint32 symbol_len = mono_array_handle_length (raw_symbol_store);
2098                 uint32_t symbol_gchandle;
2099                 mono_byte *raw_symbol_data = (mono_byte*) MONO_ARRAY_HANDLE_PIN (raw_symbol_store, mono_byte, 0, &symbol_gchandle);
2100                 mono_debug_open_image_from_memory (image, raw_symbol_data, symbol_len);
2101                 mono_gchandle_free (symbol_gchandle);
2102         }
2103
2104         ass = mono_assembly_load_from_full (image, "", &status, refonly);
2105
2106
2107         if (!ass) {
2108                 mono_image_close (image);
2109                 mono_error_set_bad_image_name (error, g_strdup (""), "%s", "");
2110                 return refass; 
2111         }
2112
2113         refass = mono_assembly_get_object_handle (domain, ass, error);
2114         if (!MONO_HANDLE_IS_NULL(refass))
2115                 MONO_HANDLE_SET (refass, evidence, evidence);
2116         return refass;
2117 }
2118
2119 MonoReflectionAssemblyHandle
2120 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomainHandle ad, MonoStringHandle assRef, MonoObjectHandle evidence, MonoBoolean refOnly, MonoError *error)
2121 {
2122         error_init (error);
2123         MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2124         MonoImageOpenStatus status = MONO_IMAGE_OK;
2125         MonoAssembly *ass;
2126         MonoAssemblyName aname;
2127         gchar *name = NULL;
2128         gboolean parsed;
2129
2130         g_assert (assRef);
2131
2132         name = mono_string_handle_to_utf8 (assRef, error);
2133         if (!is_ok (error))
2134                 goto fail;
2135         parsed = mono_assembly_name_parse (name, &aname);
2136         g_free (name);
2137
2138         if (!parsed) {
2139                 MonoReflectionAssemblyHandle refass = MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2140                 /* This is a parse error... */
2141                 if (!refOnly) {
2142                         MonoAssembly *assm = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2143                         if (!is_ok (error))
2144                                 goto fail;
2145                         if (assm) {
2146                                 refass = mono_assembly_get_object_handle (domain, assm, error);
2147                                 if (!is_ok (error))
2148                                         goto fail;
2149                         }
2150                 }
2151                 return refass;
2152         }
2153
2154         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
2155         mono_assembly_name_free (&aname);
2156
2157         if (!ass) {
2158                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
2159                 if (!refOnly) {
2160                         ass = mono_try_assembly_resolve_handle (domain, assRef, NULL, refOnly, error);
2161                         if (!is_ok (error))
2162                                 goto fail;
2163                 }
2164                 if (!ass)
2165                         goto fail;
2166         }
2167
2168         g_assert (ass);
2169         MonoReflectionAssemblyHandle refass = mono_assembly_get_object_handle (domain, ass, error);
2170         if (!is_ok (error))
2171                 goto fail;
2172
2173         MONO_HANDLE_SET (refass, evidence, evidence);
2174
2175         return refass;
2176 fail:
2177         return MONO_HANDLE_CAST (MonoReflectionAssembly, NULL_HANDLE);
2178 }
2179
2180 void
2181 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id, MonoError *error)
2182 {
2183         error_init (error);
2184         MonoDomain * domain = mono_domain_get_by_id (domain_id);
2185
2186         if (NULL == domain) {
2187                 mono_error_set_execution_engine (error, "Failed to unload domain, domain id not found");
2188                 return;
2189         }
2190         
2191         if (domain == mono_get_root_domain ()) {
2192                 mono_error_set_generic_error (error, "System", "CannotUnloadAppDomainException", "The default appdomain can not be unloaded.");
2193                 return;
2194         }
2195
2196         /* 
2197          * Unloading seems to cause problems when running NUnit/NAnt, hence
2198          * this workaround.
2199          */
2200         if (g_getenv ("MONO_NO_UNLOAD"))
2201                 return;
2202 #ifdef __native_client__
2203         return;
2204 #endif
2205
2206         MonoException *exc = NULL;
2207         mono_domain_try_unload (domain, (MonoObject**)&exc);
2208         if (exc)
2209                 mono_error_set_exception_instance (error, exc);
2210 }
2211
2212 gboolean
2213 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id, MonoError *error)
2214 {
2215         error_init (error);
2216         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2217
2218         if (!domain)
2219                 return TRUE;
2220
2221         return mono_domain_is_unloading (domain);
2222 }
2223
2224 void
2225 ves_icall_System_AppDomain_DoUnhandledException (MonoException *exc)
2226 {
2227         mono_unhandled_exception ((MonoObject*) exc);
2228 }
2229
2230 gint32
2231 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomainHandle ad,
2232                                             MonoReflectionAssemblyHandle refass, MonoArrayHandle args,
2233                                             MonoError *error)
2234 {
2235         error_init (error);
2236         MonoImage *image;
2237         MonoMethod *method;
2238
2239         g_assert (!MONO_HANDLE_IS_NULL (refass));
2240         MonoAssembly *assembly = MONO_HANDLE_GETVAL (refass, assembly);
2241         image = assembly->image;
2242         g_assert (image);
2243
2244         method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, error);
2245
2246         if (!method)
2247                 g_error ("No entry point method found in %s due to %s", image->name, mono_error_get_message (error));
2248
2249         if (MONO_HANDLE_IS_NULL (args)) {
2250                 MonoDomain *domain = MONO_HANDLE_GETVAL (ad, data);
2251                 MONO_HANDLE_ASSIGN (args , mono_array_new_handle (domain, mono_defaults.string_class, 0, error));
2252                 mono_error_assert_ok (error);
2253         }
2254
2255         int res = mono_runtime_exec_main_checked (method, MONO_HANDLE_RAW (args), error);
2256         return res;
2257 }
2258
2259 gint32 
2260 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
2261 {
2262         return ad->data->domain_id;
2263 }
2264
2265 MonoAppDomainHandle
2266 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomainHandle ad, MonoError* error)
2267 {
2268         error_init (error);
2269         MonoDomain *old_domain = mono_domain_get ();
2270
2271         if (!mono_domain_set (MONO_HANDLE_GETVAL (ad, data), FALSE)) {
2272                 mono_error_set_appdomain_unloaded (error);
2273                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2274         }
2275
2276         return MONO_HANDLE_NEW (MonoAppDomain, old_domain->domain);
2277 }
2278
2279 MonoAppDomainHandle
2280 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid, MonoError *error)
2281 {
2282         MonoDomain *current_domain = mono_domain_get ();
2283         MonoDomain *domain = mono_domain_get_by_id (domainid);
2284
2285         if (!domain || !mono_domain_set (domain, FALSE)) {
2286                 mono_error_set_appdomain_unloaded (error);
2287                 return MONO_HANDLE_CAST (MonoAppDomain, NULL_HANDLE);
2288         }
2289
2290         return MONO_HANDLE_NEW (MonoAppDomain, current_domain->domain);
2291 }
2292
2293 void
2294 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomainHandle ad, MonoError *error)
2295 {
2296         error_init (error);
2297         mono_thread_push_appdomain_ref (MONO_HANDLE_GETVAL (ad, data));
2298 }
2299
2300 void
2301 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id, MonoError *error)
2302 {
2303         error_init (error);
2304         MonoDomain *domain = mono_domain_get_by_id (domain_id);
2305
2306         if (!domain) {
2307                 /* 
2308                  * Raise an exception to prevent the managed code from executing a pop
2309                  * later.
2310                  */
2311                 mono_error_set_appdomain_unloaded (error);
2312                 return;
2313         }
2314
2315         mono_thread_push_appdomain_ref (domain);
2316 }
2317
2318 void
2319 ves_icall_System_AppDomain_InternalPopDomainRef (MonoError *error)
2320 {
2321         error_init (error);
2322         mono_thread_pop_appdomain_ref ();
2323 }
2324
2325 MonoAppContext * 
2326 ves_icall_System_AppDomain_InternalGetContext ()
2327 {
2328         return mono_context_get ();
2329 }
2330
2331 MonoAppContext * 
2332 ves_icall_System_AppDomain_InternalGetDefaultContext ()
2333 {
2334         return mono_domain_get ()->default_context;
2335 }
2336
2337 MonoAppContext * 
2338 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
2339 {
2340         MonoAppContext *old_context = mono_context_get ();
2341
2342         mono_context_set (mc);
2343
2344         return old_context;
2345 }
2346
2347 MonoStringHandle
2348 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoStringHandle newguid, MonoError *error)
2349 {
2350         error_init (error);
2351         MonoDomain* mono_root_domain = mono_get_root_domain ();
2352         mono_domain_lock (mono_root_domain);
2353         if (process_guid_set) {
2354                 mono_domain_unlock (mono_root_domain);
2355                 return mono_string_new_utf16_handle (mono_domain_get (), process_guid, sizeof(process_guid)/2, error);
2356         }
2357         uint32_t gchandle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, newguid), TRUE);
2358         memcpy (process_guid, mono_string_chars(MONO_HANDLE_RAW (newguid)), sizeof(process_guid));
2359         mono_gchandle_free (gchandle);
2360         process_guid_set = TRUE;
2361         mono_domain_unlock (mono_root_domain);
2362         return newguid;
2363 }
2364
2365 gboolean
2366 mono_domain_is_unloading (MonoDomain *domain)
2367 {
2368         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
2369                 return TRUE;
2370         else
2371                 return FALSE;
2372 }
2373
2374 static void
2375 clear_cached_vtable (MonoVTable *vtable)
2376 {
2377         MonoClass *klass = vtable->klass;
2378         MonoDomain *domain = vtable->domain;
2379         MonoClassRuntimeInfo *runtime_info;
2380         void *data;
2381
2382         runtime_info = klass->runtime_info;
2383         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2384                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2385         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2386                 mono_gc_free_fixed (data);
2387 }
2388
2389 static G_GNUC_UNUSED void
2390 zero_static_data (MonoVTable *vtable)
2391 {
2392         MonoClass *klass = vtable->klass;
2393         void *data;
2394
2395         if (klass->has_static_refs && (data = mono_vtable_get_static_field_data (vtable)))
2396                 mono_gc_bzero_aligned (data, mono_class_data_size (klass));
2397 }
2398
2399 typedef struct unload_data {
2400         gboolean done;
2401         MonoDomain *domain;
2402         char *failure_reason;
2403         gint32 refcount;
2404 } unload_data;
2405
2406 static void
2407 unload_data_unref (unload_data *data)
2408 {
2409         gint32 count;
2410         do {
2411                 mono_atomic_load_acquire (count, gint32, &data->refcount);
2412                 g_assert (count >= 1 && count <= 2);
2413                 if (count == 1) {
2414                         g_free (data);
2415                         return;
2416                 }
2417         } while (InterlockedCompareExchange (&data->refcount, count - 1, count) != count);
2418 }
2419
2420 static void
2421 deregister_reflection_info_roots_from_list (MonoImage *image)
2422 {
2423         GSList *list = image->reflection_info_unregister_classes;
2424
2425         while (list) {
2426                 MonoClass *klass = (MonoClass *)list->data;
2427
2428                 mono_class_free_ref_info (klass);
2429
2430                 list = list->next;
2431         }
2432
2433         image->reflection_info_unregister_classes = NULL;
2434 }
2435
2436 static void
2437 deregister_reflection_info_roots (MonoDomain *domain)
2438 {
2439         GSList *list;
2440
2441         mono_domain_assemblies_lock (domain);
2442         for (list = domain->domain_assemblies; list; list = list->next) {
2443                 MonoAssembly *assembly = (MonoAssembly *)list->data;
2444                 MonoImage *image = assembly->image;
2445                 int i;
2446
2447                 /*
2448                  * No need to take the image lock here since dynamic images are appdomain bound and
2449                  * at this point the mutator is gone.  Taking the image lock here would mean
2450                  * promoting it from a simple lock to a complex lock, which we better avoid if
2451                  * possible.
2452                  */
2453                 if (image_is_dynamic (image))
2454                         deregister_reflection_info_roots_from_list (image);
2455
2456                 for (i = 0; i < image->module_count; ++i) {
2457                         MonoImage *module = image->modules [i];
2458                         if (module && image_is_dynamic (module))
2459                                 deregister_reflection_info_roots_from_list (module);
2460                 }
2461         }
2462         mono_domain_assemblies_unlock (domain);
2463 }
2464
2465 static gsize WINAPI
2466 unload_thread_main (void *arg)
2467 {
2468         MonoError error;
2469         unload_data *data = (unload_data*)arg;
2470         MonoDomain *domain = data->domain;
2471         MonoInternalThread *internal;
2472         int i;
2473
2474         internal = mono_thread_internal_current ();
2475
2476         mono_thread_set_name_internal (internal, mono_string_new (mono_domain_get (), "Domain unloader"), TRUE, FALSE, &error);
2477         if (!is_ok (&error)) {
2478                 data->failure_reason = g_strdup (mono_error_get_message (&error));
2479                 mono_error_cleanup (&error);
2480                 goto failure;
2481         }
2482
2483         /* 
2484          * FIXME: Abort our parent thread last, so we can return a failure 
2485          * indication if aborting times out.
2486          */
2487         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2488                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2489                 goto failure;
2490         }
2491
2492         if (!mono_threadpool_remove_domain_jobs (domain, -1)) {
2493                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2494                 goto failure;
2495         }
2496
2497         /* Finalize all finalizable objects in the doomed appdomain */
2498         if (!mono_domain_finalize (domain, -1)) {
2499                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2500                 goto failure;
2501         }
2502
2503         /* Clear references to our vtables in class->runtime_info.
2504          * We also hold the loader lock because we're going to change
2505          * class->runtime_info.
2506          */
2507
2508         mono_loader_lock (); //FIXME why do we need the loader lock here?
2509         mono_domain_lock (domain);
2510 #ifdef HAVE_SGEN_GC
2511         /*
2512          * We need to make sure that we don't have any remsets
2513          * pointing into static data of the to-be-freed domain because
2514          * at the next collections they would be invalid.  So what we
2515          * do is we first zero all static data and then do a minor
2516          * collection.  Because all references in the static data will
2517          * now be null we won't do any unnecessary copies and after
2518          * the collection there won't be any more remsets.
2519          */
2520         for (i = 0; i < domain->class_vtable_array->len; ++i)
2521                 zero_static_data ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2522         mono_gc_collect (0);
2523 #endif
2524         for (i = 0; i < domain->class_vtable_array->len; ++i)
2525                 clear_cached_vtable ((MonoVTable *)g_ptr_array_index (domain->class_vtable_array, i));
2526         deregister_reflection_info_roots (domain);
2527
2528         mono_assembly_cleanup_domain_bindings (domain->domain_id);
2529
2530         mono_domain_unlock (domain);
2531         mono_loader_unlock ();
2532
2533         domain->state = MONO_APPDOMAIN_UNLOADED;
2534
2535         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2536
2537         /* remove from the handle table the items related to this domain */
2538         mono_gchandle_free_domain (domain);
2539
2540         mono_domain_free (domain, FALSE);
2541
2542         mono_gc_collect (mono_gc_max_generation ());
2543
2544         mono_atomic_store_release (&data->done, TRUE);
2545         unload_data_unref (data);
2546         return 0;
2547
2548 failure:
2549         mono_atomic_store_release (&data->done, TRUE);
2550         unload_data_unref (data);
2551         return 1;
2552 }
2553
2554 /*
2555  * mono_domain_unload:
2556  * @domain: The domain to unload
2557  *
2558  *  Unloads an appdomain. Follows the process outlined in the comment
2559  *  for mono_domain_try_unload.
2560  */
2561 void
2562 mono_domain_unload (MonoDomain *domain)
2563 {
2564         MonoObject *exc = NULL;
2565         mono_domain_try_unload (domain, &exc);
2566 }
2567
2568 static MonoThreadInfoWaitRet
2569 guarded_wait (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
2570 {
2571         MonoThreadInfoWaitRet result;
2572
2573         MONO_ENTER_GC_SAFE;
2574         result = mono_thread_info_wait_one_handle (thread_handle, timeout, alertable);
2575         MONO_EXIT_GC_SAFE;
2576
2577         return result;
2578 }
2579
2580 /*
2581  * mono_domain_unload:
2582  * @domain: The domain to unload
2583  * @exc: Exception information
2584  *
2585  *  Unloads an appdomain. Follows the process outlined in:
2586  *  http://blogs.gotdotnet.com/cbrumme
2587  *
2588  *  If doing things the 'right' way is too hard or complex, we do it the 
2589  *  'simple' way, which means do everything needed to avoid crashes and
2590  *  memory leaks, but not much else.
2591  *
2592  *  It is required to pass a valid reference to the exc argument, upon return
2593  *  from this function *exc will be set to the exception thrown, if any.
2594  *
2595  *  If this method is not called from an icall (embedded scenario for instance),
2596  *  it must not be called with any managed frames on the stack, since the unload
2597  *  process could end up trying to abort the current thread.
2598  */
2599 void
2600 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2601 {
2602         MonoError error;
2603         MonoThreadHandle *thread_handle;
2604         MonoAppDomainState prev_state;
2605         MonoMethod *method;
2606         unload_data *thread_data;
2607         MonoInternalThread *internal;
2608         MonoDomain *caller_domain = mono_domain_get ();
2609
2610         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, mono_native_thread_id_get ()); */
2611
2612         /* Atomically change our state to UNLOADING */
2613         prev_state = (MonoAppDomainState)InterlockedCompareExchange ((gint32*)&domain->state,
2614                 MONO_APPDOMAIN_UNLOADING_START,
2615                 MONO_APPDOMAIN_CREATED);
2616         if (prev_state != MONO_APPDOMAIN_CREATED) {
2617                 switch (prev_state) {
2618                 case MONO_APPDOMAIN_UNLOADING_START:
2619                 case MONO_APPDOMAIN_UNLOADING:
2620                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2621                         return;
2622                 case MONO_APPDOMAIN_UNLOADED:
2623                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2624                         return;
2625                 default:
2626                         g_warning ("Invalid appdomain state %d", prev_state);
2627                         g_assert_not_reached ();
2628                 }
2629         }
2630
2631         mono_domain_set (domain, FALSE);
2632         /* Notify OnDomainUnload listeners */
2633         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2634         g_assert (method);
2635
2636         mono_runtime_try_invoke (method, domain->domain, NULL, exc, &error);
2637
2638         if (!mono_error_ok (&error)) {
2639                 if (*exc)
2640                         mono_error_cleanup (&error);
2641                 else
2642                         *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2643         }
2644
2645         if (*exc) {
2646                 /* Roll back the state change */
2647                 domain->state = MONO_APPDOMAIN_CREATED;
2648                 mono_domain_set (caller_domain, FALSE);
2649                 return;
2650         }
2651         mono_domain_set (caller_domain, FALSE);
2652
2653         thread_data = g_new0 (unload_data, 1);
2654         thread_data->domain = domain;
2655         thread_data->failure_reason = NULL;
2656         thread_data->done = FALSE;
2657         thread_data->refcount = 2; /*Must be 2: unload thread + initiator */
2658
2659         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2660         domain->state = MONO_APPDOMAIN_UNLOADING;
2661         /* 
2662          * First we create a separate thread for unloading, since
2663          * we might have to abort some threads, including the current one.
2664          *
2665          * Have to attach to the runtime so shutdown can wait for this thread.
2666          *
2667          * Force it to be attached to avoid racing during shutdown.
2668          */
2669         internal = mono_thread_create_internal (mono_get_root_domain (), unload_thread_main, thread_data, MONO_THREAD_CREATE_FLAGS_FORCE_CREATE, &error);
2670         mono_error_assert_ok (&error);
2671
2672         thread_handle = mono_threads_open_thread_handle (internal->handle);
2673
2674         /* Wait for the thread */       
2675         while (!thread_data->done && guarded_wait (thread_handle, MONO_INFINITE_WAIT, TRUE) == MONO_THREAD_INFO_WAIT_RET_ALERTED) {
2676                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ())) {
2677                         /* The unload thread tries to abort us */
2678                         /* The icall wrapper will execute the abort */
2679                         mono_threads_close_thread_handle (thread_handle);
2680                         unload_data_unref (thread_data);
2681                         return;
2682                 }
2683         }
2684
2685         mono_threads_close_thread_handle (thread_handle);
2686
2687         if (thread_data->failure_reason) {
2688                 /* Roll back the state change */
2689                 domain->state = MONO_APPDOMAIN_CREATED;
2690
2691                 g_warning ("%s", thread_data->failure_reason);
2692
2693                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data->failure_reason);
2694
2695                 g_free (thread_data->failure_reason);
2696                 thread_data->failure_reason = NULL;
2697         }
2698
2699         unload_data_unref (thread_data);
2700 }