Add a new 'MONO_DEBUGGER_EVENT_TRAMPOLINE' notification for the debugger which also...
[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  */
12 #undef ASSEMBLY_LOAD_DEBUG
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25 #ifdef HAVE_UTIME_H
26 #include <utime.h>
27 #else
28 #ifdef HAVE_SYS_UTIME_H
29 #include <sys/utime.h>
30 #endif
31 #endif
32
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/object.h>
35 #include <mono/metadata/domain-internals.h>
36 #include "mono/metadata/metadata-internals.h"
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/threads.h>
40 #include <mono/metadata/socket-io.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/gc-internal.h>
43 #include <mono/metadata/mono-gc.h>
44 #include <mono/metadata/marshal.h>
45 #include <mono/metadata/monitor.h>
46 #include <mono/metadata/threadpool.h>
47 #include <mono/metadata/mono-debug.h>
48 #include <mono/metadata/mono-debug-debugger.h>
49 #include <mono/metadata/attach.h>
50 #include <mono/metadata/file-io.h>
51 #include <mono/metadata/lock-tracer.h>
52 #include <mono/metadata/console-io.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/tokentype.h>
55 #include <mono/utils/mono-uri.h>
56 #include <mono/utils/mono-logger.h>
57 #include <mono/utils/mono-path.h>
58 #include <mono/utils/mono-stdlib.h>
59 #include <mono/utils/mono-io-portability.h>
60 #ifdef PLATFORM_WIN32
61 #include <direct.h>
62 #endif
63
64 /*
65  * This is the version number of the corlib-runtime interface. When
66  * making changes to this interface (by changing the layout
67  * of classes the runtime knows about, changing icall signature or
68  * semantics etc), increment this variable. Also increment the
69  * pair of this variable in mscorlib in:
70  *       mcs/class/mscorlib/System/Environment.cs
71  *
72  * Changes which are already detected at runtime, like the addition
73  * of icalls, do not require an increment.
74  */
75 #define MONO_CORLIB_VERSION 86
76
77 typedef struct
78 {
79         int runtime_count;
80         int assemblybinding_count;
81         MonoDomain *domain;
82 } RuntimeConfig;
83
84 CRITICAL_SECTION mono_delegate_section;
85
86 #ifdef _EGLIB_MAJOR
87 /* Need to lock here because EGLIB has locking defined as no-ops, we can not depend on mono_strtod do the right locking */
88 /* Ideally this will be fixed in eglib */
89 CRITICAL_SECTION mono_strtod_mutex;
90 #endif
91
92
93 static gunichar2 process_guid [36];
94 static gboolean process_guid_set = FALSE;
95
96 static gboolean shutting_down = FALSE;
97
98 static gboolean no_exec = FALSE;
99
100 static MonoAssembly *
101 mono_domain_assembly_preload (MonoAssemblyName *aname,
102                               gchar **assemblies_path,
103                               gpointer user_data);
104
105 static MonoAssembly *
106 mono_domain_assembly_search (MonoAssemblyName *aname,
107                                                          gpointer user_data);
108
109 static MonoAssembly *
110 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
111                                                                           gpointer user_data);
112
113 static void
114 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data);
115
116 static void
117 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *hash);
118
119 static MonoAppDomain *
120 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup);
121
122 static char *
123 get_shadow_assembly_location_base (MonoDomain *domain);
124
125 static MonoLoadFunc load_function = NULL;
126
127 void
128 mono_install_runtime_load (MonoLoadFunc func)
129 {
130         load_function = func;
131 }
132
133 MonoDomain*
134 mono_runtime_load (const char *filename, const char *runtime_version)
135 {
136         g_assert (load_function);
137         return load_function (filename, runtime_version);
138 }
139
140 /*
141  * mono_runtime_set_no_exec:
142  *
143  *   Instructs the runtime to operate in static mode, i.e. avoid/do not allow managed
144  * code execution. This is useful for running the AOT compiler on platforms which
145  * allow full-aot execution only.
146  * This should be called before mono_runtime_init ().
147  */
148 void
149 mono_runtime_set_no_exec (gboolean val)
150 {
151         no_exec = val;
152 }
153
154 gboolean
155 mono_runtime_get_no_exec (void)
156 {
157         return no_exec;
158 }
159
160 /**
161  * mono_runtime_init:
162  * @domain: domain returned by mono_init ()
163  *
164  * Initialize the core AppDomain: this function will run also some
165  * IL initialization code, so it needs the execution engine to be fully 
166  * operational.
167  *
168  * AppDomain.SetupInformation is set up in mono_runtime_exec_main, where
169  * we know the entry_assembly.
170  *
171  */
172 void
173 mono_runtime_init (MonoDomain *domain, MonoThreadStartCB start_cb,
174                    MonoThreadAttachCB attach_cb)
175 {
176         MonoAppDomainSetup *setup;
177         MonoAppDomain *ad;
178         MonoClass *class;
179         MonoString *arg;
180
181         mono_portability_helpers_init ();
182         
183         mono_gc_base_init ();
184         mono_monitor_init ();
185         mono_thread_pool_init ();
186         mono_marshal_init ();
187
188         mono_install_assembly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (FALSE));
189         mono_install_assembly_refonly_preload_hook (mono_domain_assembly_preload, GUINT_TO_POINTER (TRUE));
190         mono_install_assembly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (FALSE));
191         mono_install_assembly_refonly_search_hook (mono_domain_assembly_search, GUINT_TO_POINTER (TRUE));
192         mono_install_assembly_postload_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (FALSE));
193         mono_install_assembly_postload_refonly_search_hook (mono_domain_assembly_postload_search, GUINT_TO_POINTER (TRUE));
194         mono_install_assembly_load_hook (mono_domain_fire_assembly_load, NULL);
195         mono_install_lookup_dynamic_token (mono_reflection_lookup_dynamic_token);
196
197         mono_thread_init (start_cb, attach_cb);
198
199         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
200         setup = (MonoAppDomainSetup *) mono_object_new (domain, class);
201
202         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
203         ad = (MonoAppDomain *) mono_object_new (domain, class);
204         ad->data = domain;
205         domain->domain = ad;
206         domain->setup = setup;
207
208         InitializeCriticalSection (&mono_delegate_section);
209
210 #ifdef _EGLIB_MAJOR
211         /* Needed until EGLIB is fixed #464316 */
212         InitializeCriticalSection (&mono_strtod_mutex);
213 #endif
214         
215         mono_thread_attach (domain);
216         mono_context_init (domain);
217         mono_context_set (domain->default_context);
218
219         mono_type_initialization_init ();
220
221         if (!mono_runtime_get_no_exec ()) {
222                 /*
223                  * Create an instance early since we can't do it when there is no memory.
224                  */
225                 arg = mono_string_new (domain, "Out of memory");
226                 domain->out_of_memory_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "OutOfMemoryException", arg, NULL);
227         
228                 /* 
229                  * These two are needed because the signal handlers might be executing on
230                  * an alternate stack, and Boehm GC can't handle that.
231                  */
232                 arg = mono_string_new (domain, "A null value was found where an object instance was required");
233                 domain->null_reference_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "NullReferenceException", arg, NULL);
234                 arg = mono_string_new (domain, "The requested operation caused a stack overflow.");
235                 domain->stack_overflow_ex = mono_exception_from_name_two_strings (mono_defaults.corlib, "System", "StackOverflowException", arg, NULL);
236         }
237
238         /* GC init has to happen after thread init */
239         mono_gc_init ();
240
241 #ifndef DISABLE_SOCKETS
242         mono_network_init ();
243 #endif
244         
245         mono_console_init ();
246         mono_attach_init ();
247
248         mono_locks_tracer_init ();
249
250         /* mscorlib is loaded before we install the load hook */
251         mono_domain_fire_assembly_load (mono_defaults.corlib->assembly, NULL);
252         
253         return;
254 }
255
256 static int
257 mono_get_corlib_version (void)
258 {
259         MonoClass *klass;
260         MonoClassField *field;
261         MonoObject *value;
262
263         klass = mono_class_from_name (mono_defaults.corlib, "System", "Environment");
264         mono_class_init (klass);
265         field = mono_class_get_field_from_name (klass, "mono_corlib_version");
266         if (!field)
267                 return -1;
268         if (! (field->type->attrs & FIELD_ATTRIBUTE_STATIC))
269                 return -1;
270         value = mono_field_get_value_object (mono_domain_get (), field, NULL);
271         return *(gint32*)((gchar*)value + sizeof (MonoObject));
272 }
273
274 const char*
275 mono_check_corlib_version (void)
276 {
277         int version = mono_get_corlib_version ();
278         if (version != MONO_CORLIB_VERSION)
279                 return g_strdup_printf ("expected corlib version %d, found %d.", MONO_CORLIB_VERSION, version);
280         else
281                 return NULL;
282 }
283
284 void
285 mono_context_init (MonoDomain *domain)
286 {
287         MonoClass *class;
288         MonoAppContext *context;
289
290         class = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Contexts", "Context");
291         context = (MonoAppContext *) mono_object_new (domain, class);
292         context->domain_id = domain->domain_id;
293         context->context_id = 0;
294         domain->default_context = context;
295 }
296
297 /**
298  * mono_runtime_cleanup:
299  * @domain: unused.
300  *
301  * Internal routine.
302  *
303  * This must not be called while there are still running threads executing
304  * managed code.
305  */
306 void
307 mono_runtime_cleanup (MonoDomain *domain)
308 {
309         shutting_down = TRUE;
310
311         mono_attach_cleanup ();
312
313         /* This ends up calling any pending pending (for at most 2 seconds) */
314         mono_gc_cleanup ();
315
316         mono_thread_cleanup ();
317
318 #ifndef DISABLE_SOCKETS
319         mono_network_cleanup ();
320 #endif
321         mono_marshal_cleanup ();
322
323         mono_type_initialization_cleanup ();
324
325         mono_monitor_cleanup ();
326
327 #ifndef PLATFORM_WIN32
328         _wapi_cleanup ();
329 #endif
330 }
331
332 static MonoDomainFunc quit_function = NULL;
333
334 void
335 mono_install_runtime_cleanup (MonoDomainFunc func)
336 {
337         quit_function = func;
338 }
339
340 void
341 mono_runtime_quit ()
342 {
343         if (quit_function != NULL)
344                 quit_function (mono_get_root_domain (), NULL);
345 }
346
347 /** 
348  * mono_runtime_set_shutting_down:
349  *
350  * Invoked by System.Environment.Exit to flag that the runtime
351  * is shutting down.
352  */
353 void
354 mono_runtime_set_shutting_down (void)
355 {
356         shutting_down = TRUE;
357 }
358
359 /**
360  * mono_runtime_is_shutting_down:
361  *
362  * Returns whether the runtime has been flagged for shutdown.
363  *
364  * This is consumed by the P:System.Environment.HasShutdownStarted
365  * property.
366  *
367  */
368 gboolean
369 mono_runtime_is_shutting_down (void)
370 {
371         return shutting_down;
372 }
373
374 /**
375  * mono_domain_create_appdomain:
376  * @friendly_name: The friendly name of the appdomain to create
377  * @configuration_file: The configuration file to initialize the appdomain with
378  * 
379  * Returns a MonoDomain initialized with the appdomain
380  */
381 MonoDomain *
382 mono_domain_create_appdomain (char *friendly_name, char *configuration_file)
383 {
384         MonoAppDomain *ad;
385         MonoAppDomainSetup *setup;
386         MonoClass *class;
387
388         class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
389         setup = (MonoAppDomainSetup *) mono_object_new (mono_domain_get (), class);
390         setup->configuration_file = configuration_file != NULL ? mono_string_new (mono_domain_get (), configuration_file) : NULL;
391
392         ad = mono_domain_create_appdomain_internal (friendly_name, setup);
393
394         return mono_domain_from_appdomain (ad);
395 }
396
397 static MonoAppDomainSetup*
398 copy_app_domain_setup (MonoDomain *domain, MonoAppDomainSetup *setup)
399 {
400         MonoDomain *caller_domain = mono_domain_get ();
401         MonoClass *ads_class = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainSetup");
402         MonoAppDomainSetup *copy = (MonoAppDomainSetup*)mono_object_new (domain, ads_class);
403
404         mono_domain_set_internal (domain);
405
406         MONO_OBJECT_SETREF (copy, application_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_base));
407         MONO_OBJECT_SETREF (copy, application_name, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_name));
408         MONO_OBJECT_SETREF (copy, cache_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->cache_path));
409         MONO_OBJECT_SETREF (copy, configuration_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_file));
410         MONO_OBJECT_SETREF (copy, dynamic_base, mono_marshal_xdomain_copy_value ((MonoObject*)setup->dynamic_base));
411         MONO_OBJECT_SETREF (copy, license_file, mono_marshal_xdomain_copy_value ((MonoObject*)setup->license_file));
412         MONO_OBJECT_SETREF (copy, private_bin_path, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path));
413         MONO_OBJECT_SETREF (copy, private_bin_path_probe, mono_marshal_xdomain_copy_value ((MonoObject*)setup->private_bin_path_probe));
414         MONO_OBJECT_SETREF (copy, shadow_copy_directories, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_directories));
415         MONO_OBJECT_SETREF (copy, shadow_copy_files, mono_marshal_xdomain_copy_value ((MonoObject*)setup->shadow_copy_files));
416         copy->publisher_policy = setup->publisher_policy;
417         copy->path_changed = setup->path_changed;
418         copy->loader_optimization = setup->loader_optimization;
419         copy->disallow_binding_redirects = setup->disallow_binding_redirects;
420         copy->disallow_code_downloads = setup->disallow_code_downloads;
421         MONO_OBJECT_SETREF (copy, domain_initializer_args, mono_marshal_xdomain_copy_value ((MonoObject*)setup->domain_initializer_args));
422         copy->disallow_appbase_probe = setup->disallow_appbase_probe;
423         MONO_OBJECT_SETREF (copy, application_trust, mono_marshal_xdomain_copy_value ((MonoObject*)setup->application_trust));
424         MONO_OBJECT_SETREF (copy, configuration_bytes, mono_marshal_xdomain_copy_value ((MonoObject*)setup->configuration_bytes));
425         MONO_OBJECT_SETREF (copy, serialized_non_primitives, mono_marshal_xdomain_copy_value ((MonoObject*)setup->serialized_non_primitives));
426
427         mono_domain_set_internal (caller_domain);
428
429         return copy;
430 }
431
432 static MonoAppDomain *
433 mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetup *setup)
434 {
435         MonoClass *adclass;
436         MonoAppDomain *ad;
437         MonoDomain *data;
438         char *shadow_location;
439         
440         MONO_ARCH_SAVE_REGS;
441
442         adclass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomain");
443
444         /* FIXME: pin all those objects */
445         data = mono_domain_create();
446
447         ad = (MonoAppDomain *) mono_object_new (data, adclass);
448         ad->data = data;
449         data->domain = ad;
450         data->friendly_name = g_strdup (friendly_name);
451
452         if (!setup->application_base) {
453                 /* Inherit from the root domain since MS.NET does this */
454                 MonoDomain *root = mono_get_root_domain ();
455                 if (root->setup->application_base)
456                         MONO_OBJECT_SETREF (setup, application_base, mono_string_new_utf16 (data, mono_string_chars (root->setup->application_base), mono_string_length (root->setup->application_base)));
457         }
458
459         mono_context_init (data);
460
461         mono_set_private_bin_path_from_config (data);
462         
463         add_assemblies_to_domain (data, mono_defaults.corlib->assembly, NULL);
464
465         data->setup = copy_app_domain_setup (data, setup);
466
467 #ifndef DISABLE_SHADOW_COPY
468         shadow_location = get_shadow_assembly_location_base (data);
469         mono_debugger_event_create_appdomain (data, shadow_location);
470         g_free (shadow_location);
471 #endif
472
473         // FIXME: Initialize null_reference_ex and stack_overflow_ex
474         data->out_of_memory_ex = mono_exception_from_name_domain (data, mono_defaults.corlib, "System", "OutOfMemoryException");
475
476         return ad;
477 }
478
479 /**
480  * mono_domain_has_type_resolve:
481  * @domain: application domains being looked up
482  *
483  * Returns true if the AppDomain.TypeResolve field has been
484  * set.
485  */
486 gboolean
487 mono_domain_has_type_resolve (MonoDomain *domain)
488 {
489         static MonoClassField *field = NULL;
490         MonoObject *o;
491
492         if (field == NULL) {
493                 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "TypeResolve");
494                 g_assert (field);
495         }
496
497         mono_field_get_value ((MonoObject*)(domain->domain), field, &o);
498         return o != NULL;
499 }
500
501 /**
502  * mono_domain_try_type_resolve:
503  * @domain: application domainwhere the name where the type is going to be resolved
504  * @name: the name of the type to resolve or NULL.
505  * @tb: A System.Reflection.Emit.TypeBuilder, used if name is NULL.
506  *
507  * This routine invokes the internal System.AppDomain.DoTypeResolve and returns
508  * the assembly that matches name.
509  *
510  * If @name is null, the value of ((TypeBuilder)tb).FullName is used instead
511  *
512  * Returns: A MonoReflectionAssembly or NULL if not found
513  */
514 MonoReflectionAssembly *
515 mono_domain_try_type_resolve (MonoDomain *domain, char *name, MonoObject *tb)
516 {
517         MonoClass *klass;
518         void *params [1];
519         static MonoMethod *method = NULL;
520
521         g_assert (domain != NULL && ((name != NULL) || (tb != NULL)));
522
523         if (method == NULL) {
524                 klass = domain->domain->mbr.obj.vtable->klass;
525                 g_assert (klass);
526
527                 method = mono_class_get_method_from_name (klass, "DoTypeResolve", -1);
528                 if (method == NULL) {
529                         g_warning ("Method AppDomain.DoTypeResolve not found.\n");
530                         return NULL;
531                 }
532         }
533
534         if (name)
535                 *params = (MonoObject*)mono_string_new (mono_domain_get (), name);
536         else
537                 *params = tb;
538         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
539 }
540
541 /**
542  * mono_domain_owns_vtable_slot:
543  *
544  *  Returns whenever VTABLE_SLOT is inside a vtable which belongs to DOMAIN.
545  */
546 gboolean
547 mono_domain_owns_vtable_slot (MonoDomain *domain, gpointer vtable_slot)
548 {
549         gboolean res;
550
551         mono_domain_lock (domain);
552         res = mono_mempool_contains_addr (domain->mp, vtable_slot);
553         mono_domain_unlock (domain);
554         return res;
555 }
556
557 /**
558  * mono_domain_set:
559  * @domain: domain
560  * @force: force setting.
561  *
562  * Set the current appdomain to @domain. If @force is set, set it even
563  * if it is being unloaded.
564  *
565  * Returns:
566  *   TRUE on success;
567  *   FALSE if the domain is unloaded
568  */
569 gboolean
570 mono_domain_set (MonoDomain *domain, gboolean force)
571 {
572         if (!force && domain->state == MONO_APPDOMAIN_UNLOADED)
573                 return FALSE;
574
575         mono_domain_set_internal (domain);
576
577         return TRUE;
578 }
579
580 MonoObject *
581 ves_icall_System_AppDomain_GetData (MonoAppDomain *ad, MonoString *name)
582 {
583         MonoDomain *add;
584         MonoObject *o;
585         char *str;
586
587         MONO_ARCH_SAVE_REGS;
588
589         g_assert (ad != NULL);
590         add = ad->data;
591         g_assert (add != NULL);
592
593         if (name == NULL)
594                 mono_raise_exception (mono_get_exception_argument_null ("name"));
595
596         str = mono_string_to_utf8 (name);
597
598         mono_domain_lock (add);
599
600         if (!strcmp (str, "APPBASE"))
601                 o = (MonoObject *)add->setup->application_base;
602         else if (!strcmp (str, "APP_CONFIG_FILE"))
603                 o = (MonoObject *)add->setup->configuration_file;
604         else if (!strcmp (str, "DYNAMIC_BASE"))
605                 o = (MonoObject *)add->setup->dynamic_base;
606         else if (!strcmp (str, "APP_NAME"))
607                 o = (MonoObject *)add->setup->application_name;
608         else if (!strcmp (str, "CACHE_BASE"))
609                 o = (MonoObject *)add->setup->cache_path;
610         else if (!strcmp (str, "PRIVATE_BINPATH"))
611                 o = (MonoObject *)add->setup->private_bin_path;
612         else if (!strcmp (str, "BINPATH_PROBE_ONLY"))
613                 o = (MonoObject *)add->setup->private_bin_path_probe;
614         else if (!strcmp (str, "SHADOW_COPY_DIRS"))
615                 o = (MonoObject *)add->setup->shadow_copy_directories;
616         else if (!strcmp (str, "FORCE_CACHE_INSTALL"))
617                 o = (MonoObject *)add->setup->shadow_copy_files;
618         else 
619                 o = mono_g_hash_table_lookup (add->env, name);
620
621         mono_domain_unlock (add);
622         g_free (str);
623
624         if (!o)
625                 return NULL;
626
627         return o;
628 }
629
630 void
631 ves_icall_System_AppDomain_SetData (MonoAppDomain *ad, MonoString *name, MonoObject *data)
632 {
633         MonoDomain *add;
634
635         MONO_ARCH_SAVE_REGS;
636
637         g_assert (ad != NULL);
638         add = ad->data;
639         g_assert (add != NULL);
640
641         if (name == NULL)
642                 mono_raise_exception (mono_get_exception_argument_null ("name"));
643
644         mono_domain_lock (add);
645
646         mono_g_hash_table_insert (add->env, name, data);
647
648         mono_domain_unlock (add);
649 }
650
651 MonoAppDomainSetup *
652 ves_icall_System_AppDomain_getSetup (MonoAppDomain *ad)
653 {
654         MONO_ARCH_SAVE_REGS;
655
656         g_assert (ad != NULL);
657         g_assert (ad->data != NULL);
658
659         return ad->data->setup;
660 }
661
662 MonoString *
663 ves_icall_System_AppDomain_getFriendlyName (MonoAppDomain *ad)
664 {
665         MONO_ARCH_SAVE_REGS;
666
667         g_assert (ad != NULL);
668         g_assert (ad->data != NULL);
669
670         return mono_string_new (ad->data, ad->data->friendly_name);
671 }
672
673 MonoAppDomain *
674 ves_icall_System_AppDomain_getCurDomain ()
675 {
676         MonoDomain *add = mono_domain_get ();
677
678         MONO_ARCH_SAVE_REGS;
679
680         return add->domain;
681 }
682
683 MonoAppDomain *
684 ves_icall_System_AppDomain_getRootDomain ()
685 {
686         MonoDomain *root = mono_get_root_domain ();
687
688         MONO_ARCH_SAVE_REGS;
689
690         return root->domain;
691 }
692
693 static char*
694 get_attribute_value (const gchar **attribute_names, 
695                      const gchar **attribute_values, 
696                      const char *att_name)
697 {
698         int n;
699         for (n = 0; attribute_names [n] != NULL; n++) {
700                 if (strcmp (attribute_names [n], att_name) == 0)
701                         return g_strdup (attribute_values [n]);
702         }
703         return NULL;
704 }
705
706 static void
707 start_element (GMarkupParseContext *context, 
708                const gchar         *element_name,
709                const gchar        **attribute_names,
710                const gchar        **attribute_values,
711                gpointer             user_data,
712                GError             **error)
713 {
714         RuntimeConfig *runtime_config = user_data;
715         
716         if (strcmp (element_name, "runtime") == 0) {
717                 runtime_config->runtime_count++;
718                 return;
719         }
720
721         if (strcmp (element_name, "assemblyBinding") == 0) {
722                 runtime_config->assemblybinding_count++;
723                 return;
724         }
725         
726         if (runtime_config->runtime_count != 1 || runtime_config->assemblybinding_count != 1)
727                 return;
728
729         if (strcmp (element_name, "probing") != 0)
730                 return;
731
732         g_free (runtime_config->domain->private_bin_path);
733         runtime_config->domain->private_bin_path = get_attribute_value (attribute_names, attribute_values, "privatePath");
734         if (runtime_config->domain->private_bin_path && !runtime_config->domain->private_bin_path [0]) {
735                 g_free (runtime_config->domain->private_bin_path);
736                 runtime_config->domain->private_bin_path = NULL;
737                 return;
738         }
739 }
740
741 static void
742 end_element (GMarkupParseContext *context,
743              const gchar         *element_name,
744              gpointer             user_data,
745              GError             **error)
746 {
747         RuntimeConfig *runtime_config = user_data;
748         if (strcmp (element_name, "runtime") == 0)
749                 runtime_config->runtime_count--;
750         else if (strcmp (element_name, "assemblyBinding") == 0)
751                 runtime_config->assemblybinding_count--;
752 }
753
754 static const GMarkupParser
755 mono_parser = {
756         start_element,
757         end_element,
758         NULL,
759         NULL,
760         NULL
761 };
762
763 void
764 mono_set_private_bin_path_from_config (MonoDomain *domain)
765 {
766         gchar *config_file, *text;
767         gsize len;
768         GMarkupParseContext *context;
769         RuntimeConfig runtime_config;
770         
771         if (!domain || !domain->setup || !domain->setup->configuration_file)
772                 return;
773
774         config_file = mono_string_to_utf8 (domain->setup->configuration_file);
775
776         if (!g_file_get_contents (config_file, &text, &len, NULL)) {
777                 g_free (config_file);
778                 return;
779         }
780         g_free (config_file);
781
782         runtime_config.runtime_count = 0;
783         runtime_config.assemblybinding_count = 0;
784         runtime_config.domain = domain;
785         
786         context = g_markup_parse_context_new (&mono_parser, 0, &runtime_config, NULL);
787         if (g_markup_parse_context_parse (context, text, len, NULL))
788                 g_markup_parse_context_end_parse (context, NULL);
789         g_markup_parse_context_free (context);
790         g_free (text);
791 }
792
793 MonoAppDomain *
794 ves_icall_System_AppDomain_createDomain (MonoString *friendly_name, MonoAppDomainSetup *setup)
795 {
796         char *fname = mono_string_to_utf8 (friendly_name);
797         MonoAppDomain *ad = mono_domain_create_appdomain_internal (fname, setup);
798         
799         g_free (fname);
800
801         return ad;
802 }
803
804 MonoArray *
805 ves_icall_System_AppDomain_GetAssemblies (MonoAppDomain *ad, MonoBoolean refonly)
806 {
807         MonoDomain *domain = ad->data; 
808         MonoAssembly* ass;
809         static MonoClass *System_Reflection_Assembly;
810         MonoArray *res;
811         GSList *tmp;
812         int i;
813         GPtrArray *assemblies;
814
815         MONO_ARCH_SAVE_REGS;
816
817         if (!System_Reflection_Assembly)
818                 System_Reflection_Assembly = mono_class_from_name (
819                         mono_defaults.corlib, "System.Reflection", "Assembly");
820
821         /* 
822          * Make a copy of the list of assemblies because we can't hold the assemblies
823          * lock while creating objects etc.
824          */
825         assemblies = g_ptr_array_new ();
826         /* Need to skip internal assembly builders created by remoting */
827         mono_domain_assemblies_lock (domain);
828         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
829                 ass = tmp->data;
830                 if (refonly != ass->ref_only)
831                         continue;
832                 if (ass->corlib_internal)
833                         continue;
834                 g_ptr_array_add (assemblies, ass);
835         }
836         mono_domain_assemblies_unlock (domain);
837
838         res = mono_array_new (domain, System_Reflection_Assembly, assemblies->len);
839         for (i = 0; i < assemblies->len; ++i) {
840                 ass = g_ptr_array_index (assemblies, i);
841                 mono_array_setref (res, i, mono_assembly_get_object (domain, ass));
842         }
843
844         g_ptr_array_free (assemblies, TRUE);
845
846         return res;
847 }
848
849 MonoReflectionAssembly *
850 mono_try_assembly_resolve (MonoDomain *domain, MonoString *fname, gboolean refonly)
851 {
852         MonoClass *klass;
853         MonoMethod *method;
854         MonoBoolean isrefonly;
855         gpointer params [2];
856
857         if (mono_runtime_get_no_exec ())
858                 return NULL;
859
860         g_assert (domain != NULL && fname != NULL);
861
862         klass = domain->domain->mbr.obj.vtable->klass;
863         g_assert (klass);
864         
865         method = mono_class_get_method_from_name (klass, "DoAssemblyResolve", -1);
866         if (method == NULL) {
867                 g_warning ("Method AppDomain.DoAssemblyResolve not found.\n");
868                 return NULL;
869         }
870
871         isrefonly = refonly ? 1 : 0;
872         params [0] = fname;
873         params [1] = &isrefonly;
874         return (MonoReflectionAssembly *) mono_runtime_invoke (method, domain->domain, params, NULL);
875 }
876
877 static MonoAssembly *
878 mono_domain_assembly_postload_search (MonoAssemblyName *aname,
879                                                                           gpointer user_data)
880 {
881         gboolean refonly = GPOINTER_TO_UINT (user_data);
882         MonoReflectionAssembly *assembly;
883         MonoDomain *domain = mono_domain_get ();
884         char *aname_str;
885
886         aname_str = mono_stringify_assembly_name (aname);
887
888         /* FIXME: We invoke managed code here, so there is a potential for deadlocks */
889         assembly = mono_try_assembly_resolve (domain, mono_string_new (domain, aname_str), refonly);
890
891         g_free (aname_str);
892
893         if (assembly)
894                 return assembly->assembly;
895         else
896                 return NULL;
897 }
898         
899 /*
900  * LOCKING: assumes assemblies_lock in the domain is already locked.
901  */
902 static void
903 add_assemblies_to_domain (MonoDomain *domain, MonoAssembly *ass, GHashTable *ht)
904 {
905         gint i;
906         GSList *tmp;
907         gboolean destroy_ht = FALSE;
908
909         if (!ass->aname.name)
910                 return;
911
912         if (!ht) {
913                 ht = g_hash_table_new (mono_aligned_addr_hash, NULL);
914                 destroy_ht = TRUE;
915         }
916
917         /* FIXME: handle lazy loaded assemblies */
918         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
919                 g_hash_table_insert (ht, tmp->data, tmp->data);
920         }
921         if (!g_hash_table_lookup (ht, ass)) {
922                 mono_assembly_addref (ass);
923                 g_hash_table_insert (ht, ass, ass);
924                 domain->domain_assemblies = g_slist_prepend (domain->domain_assemblies, ass);
925                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly %s %p added to domain %s, ref_count=%d\n", ass->aname.name, ass, domain->friendly_name, ass->ref_count);
926         }
927
928         if (ass->image->references) {
929                 for (i = 0; ass->image->references [i] != NULL; i++) {
930                         if (ass->image->references [i] != REFERENCE_MISSING)
931                                 if (!g_hash_table_lookup (ht, ass->image->references [i])) {
932                                         add_assemblies_to_domain (domain, ass->image->references [i], ht);
933                                 }
934                 }
935         }
936         if (destroy_ht)
937                 g_hash_table_destroy (ht);
938 }
939
940 static void
941 mono_domain_fire_assembly_load (MonoAssembly *assembly, gpointer user_data)
942 {
943         static MonoClassField *assembly_load_field;
944         static MonoMethod *assembly_load_method;
945         MonoDomain *domain = mono_domain_get ();
946         MonoReflectionAssembly *ref_assembly;
947         MonoClass *klass;
948         gpointer load_value;
949         void *params [1];
950
951         if (!domain->domain)
952                 /* This can happen during startup */
953                 return;
954 #ifdef ASSEMBLY_LOAD_DEBUG
955         fprintf (stderr, "Loading %s into domain %s\n", assembly->aname.name, domain->friendly_name);
956 #endif
957         klass = domain->domain->mbr.obj.vtable->klass;
958
959         mono_domain_assemblies_lock (domain);
960         add_assemblies_to_domain (domain, assembly, NULL);
961         mono_domain_assemblies_unlock (domain);
962
963         if (assembly_load_field == NULL) {
964                 assembly_load_field = mono_class_get_field_from_name (klass, "AssemblyLoad");
965                 g_assert (assembly_load_field);
966         }
967
968         mono_field_get_value ((MonoObject*) domain->domain, assembly_load_field, &load_value);
969         if (load_value == NULL) {
970                 /* No events waiting to be triggered */
971                 return;
972         }
973
974         ref_assembly = mono_assembly_get_object (domain, assembly);
975         g_assert (ref_assembly);
976
977         if (assembly_load_method == NULL) {
978                 assembly_load_method = mono_class_get_method_from_name (klass, "DoAssemblyLoad", -1);
979                 g_assert (assembly_load_method);
980         }
981
982         *params = ref_assembly;
983         mono_runtime_invoke (assembly_load_method, domain->domain, params, NULL);
984 }
985
986 /*
987  * LOCKING: Acquires the domain assemblies lock.
988  */
989 static void
990 set_domain_search_path (MonoDomain *domain)
991 {
992         MonoAppDomainSetup *setup;
993         gchar **tmp;
994         gchar *search_path = NULL;
995         gint i;
996         gint npaths = 0;
997         gchar **pvt_split = NULL;
998         GError *error = NULL;
999         gint appbaselen = -1;
1000
1001         /* 
1002          * We use the low-level domain assemblies lock, since this is called from
1003          * assembly loads hooks, which means this thread might hold the loader lock.
1004          */
1005         mono_domain_assemblies_lock (domain);
1006
1007         if (!domain->setup) {
1008                 mono_domain_assemblies_unlock (domain);
1009                 return;
1010         }
1011
1012         if ((domain->search_path != NULL) && !domain->setup->path_changed) {
1013                 mono_domain_assemblies_unlock (domain);
1014                 return;
1015         }
1016         setup = domain->setup;
1017         if (!setup->application_base) {
1018                 mono_domain_assemblies_unlock (domain);
1019                 return; /* Must set application base to get private path working */
1020         }
1021
1022         npaths++;
1023         
1024         if (setup->private_bin_path)
1025                 search_path = mono_string_to_utf8 (setup->private_bin_path);
1026         
1027         if (domain->private_bin_path) {
1028                 if (search_path == NULL)
1029                         search_path = domain->private_bin_path;
1030                 else {
1031                         gchar *tmp2 = search_path;
1032                         search_path = g_strjoin (";", search_path, domain->private_bin_path, NULL);
1033                         g_free (tmp2);
1034                 }
1035         }
1036         
1037         if (search_path) {
1038                 /*
1039                  * As per MSDN documentation, AppDomainSetup.PrivateBinPath contains a list of
1040                  * directories relative to ApplicationBase separated by semicolons (see
1041                  * http://msdn2.microsoft.com/en-us/library/system.appdomainsetup.privatebinpath.aspx)
1042                  * The loop below copes with the fact that some Unix applications may use ':' (or
1043                  * System.IO.Path.PathSeparator) as the path search separator. We replace it with
1044                  * ';' for the subsequent split.
1045                  *
1046                  * The issue was reported in bug #81446
1047                  */
1048
1049 #ifndef PLATFORM_WIN32
1050                 gint slen;
1051
1052                 slen = strlen (search_path);
1053                 for (i = 0; i < slen; i++)
1054                         if (search_path [i] == ':')
1055                                 search_path [i] = ';';
1056 #endif
1057                 
1058                 pvt_split = g_strsplit (search_path, ";", 1000);
1059                 g_free (search_path);
1060                 for (tmp = pvt_split; *tmp; tmp++, npaths++);
1061         }
1062
1063         if (!npaths) {
1064                 if (pvt_split)
1065                         g_strfreev (pvt_split);
1066                 /*
1067                  * Don't do this because the first time is called, the domain
1068                  * setup is not finished.
1069                  *
1070                  * domain->search_path = g_malloc (sizeof (char *));
1071                  * domain->search_path [0] = NULL;
1072                 */
1073                 mono_domain_assemblies_unlock (domain);
1074                 return;
1075         }
1076
1077         if (domain->search_path)
1078                 g_strfreev (domain->search_path);
1079
1080         domain->search_path = tmp = g_malloc ((npaths + 1) * sizeof (gchar *));
1081         tmp [npaths] = NULL;
1082
1083         *tmp = mono_string_to_utf8 (setup->application_base);
1084
1085         /* FIXME: is this needed? */
1086         if (strncmp (*tmp, "file://", 7) == 0) {
1087                 gchar *file = *tmp;
1088                 gchar *uri = *tmp;
1089                 gchar *tmpuri;
1090
1091                 if (uri [7] != '/')
1092                         uri = g_strdup_printf ("file:///%s", uri + 7);
1093
1094                 tmpuri = uri;
1095                 uri = mono_escape_uri_string (tmpuri);
1096                 *tmp = g_filename_from_uri (uri, NULL, &error);
1097                 g_free (uri);
1098
1099                 if (tmpuri != file)
1100                         g_free (tmpuri);
1101
1102                 if (error != NULL) {
1103                         g_warning ("%s\n", error->message);
1104                         g_error_free (error);
1105                         *tmp = file;
1106                 } else {
1107                         g_free (file);
1108                 }
1109         }
1110
1111         for (i = 1; pvt_split && i < npaths; i++) {
1112                 if (g_path_is_absolute (pvt_split [i - 1])) {
1113                         tmp [i] = g_strdup (pvt_split [i - 1]);
1114                 } else {
1115                         tmp [i] = g_build_filename (tmp [0], pvt_split [i - 1], NULL);
1116                 }
1117
1118                 if (strchr (tmp [i], '.')) {
1119                         gchar *reduced;
1120                         gchar *freeme;
1121
1122                         reduced = mono_path_canonicalize (tmp [i]);
1123                         if (appbaselen == -1)
1124                                 appbaselen = strlen (tmp [0]);
1125
1126                         if (strncmp (tmp [0], reduced, appbaselen)) {
1127                                 g_free (reduced);
1128                                 g_free (tmp [i]);
1129                                 tmp [i] = g_strdup ("");
1130                                 continue;
1131                         }
1132
1133                         freeme = tmp [i];
1134                         tmp [i] = reduced;
1135                         g_free (freeme);
1136                 }
1137         }
1138         
1139         if (setup->private_bin_path_probe != NULL) {
1140                 g_free (tmp [0]);
1141                 tmp [0] = g_strdup ("");
1142         }
1143                 
1144         domain->setup->path_changed = FALSE;
1145
1146         g_strfreev (pvt_split);
1147
1148         mono_domain_assemblies_unlock (domain);
1149 }
1150
1151 #ifdef DISABLE_SHADOW_COPY
1152 gboolean
1153 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1154 {
1155         return FALSE;
1156 }
1157
1158 char *
1159 mono_make_shadow_copy (const char *filename)
1160 {
1161         return (char *) filename;
1162 }
1163 #else
1164 static gboolean
1165 shadow_copy_sibling (gchar *src, gint srclen, const char *extension, gchar *target, gint targetlen, gint tail_len)
1166 {
1167         guint16 *orig, *dest;
1168         gboolean copy_result;
1169         
1170         strcpy (src + srclen - tail_len, extension);
1171         if (!g_file_test (src, G_FILE_TEST_IS_REGULAR))
1172                 return TRUE;
1173         orig = g_utf8_to_utf16 (src, strlen (src), NULL, NULL, NULL);
1174
1175         strcpy (target + targetlen - tail_len, extension);
1176         dest = g_utf8_to_utf16 (target, strlen (target), NULL, NULL, NULL);
1177         
1178         DeleteFile (dest);
1179         copy_result = CopyFile (orig, dest, FALSE);
1180         g_free (orig);
1181         g_free (dest);
1182         
1183         return copy_result;
1184 }
1185
1186 static gint32 
1187 get_cstring_hash (const char *str)
1188 {
1189         int len, i;
1190         const char *p;
1191         gint32 h = 0;
1192         
1193         if (!str || !str [0])
1194                 return 0;
1195                 
1196         len = strlen (str);
1197         p = str;
1198         for (i = 0; i < len; i++) {
1199                 h = (h << 5) - h + *p;
1200                 p++;
1201         }
1202         
1203         return h;
1204 }
1205
1206 /*
1207  * Returned memory is malloc'd. Called must free it 
1208  */
1209 static char *
1210 get_shadow_assembly_location_base (MonoDomain *domain)
1211 {
1212         MonoAppDomainSetup *setup;
1213         char *cache_path, *appname;
1214         char *userdir;
1215         char *location;
1216         
1217         setup = domain->setup;
1218         if (setup->cache_path != NULL && setup->application_name != NULL) {
1219                 cache_path = mono_string_to_utf8 (setup->cache_path);
1220 #ifndef PLATFORM_WIN32
1221                 {
1222                         gint i;
1223                         for (i = strlen (cache_path) - 1; i >= 0; i--)
1224                                 if (cache_path [i] == '\\')
1225                                         cache_path [i] = '/';
1226                 }
1227 #endif
1228
1229                 appname = mono_string_to_utf8 (setup->application_name);
1230                 location = g_build_filename (cache_path, appname, "assembly", "shadow", NULL);
1231                 g_free (appname);
1232                 g_free (cache_path);
1233         } else {
1234                 userdir = g_strdup_printf ("%s-mono-cachepath", g_get_user_name ());
1235                 location = g_build_filename (g_get_tmp_dir (), userdir, "assembly", "shadow", NULL);
1236                 g_free (userdir);
1237         }
1238         return location;
1239 }
1240
1241 static char *
1242 get_shadow_assembly_location (const char *filename)
1243 {
1244         gint32 hash = 0, hash2 = 0;
1245         char name_hash [9];
1246         char path_hash [30];
1247         char *bname = g_path_get_basename (filename);
1248         char *dirname = g_path_get_dirname (filename);
1249         char *location, *tmploc;
1250         MonoDomain *domain = mono_domain_get ();
1251         
1252         hash = get_cstring_hash (bname);
1253         hash2 = get_cstring_hash (dirname);
1254         g_snprintf (name_hash, sizeof (name_hash), "%08x", hash);
1255         g_snprintf (path_hash, sizeof (path_hash), "%08x_%08x_%08x", hash ^ hash2, hash2, domain->shadow_serial);
1256         tmploc = get_shadow_assembly_location_base (domain);
1257         location = g_build_filename (tmploc, name_hash, path_hash, bname, NULL);
1258         g_free (tmploc);
1259         g_free (bname);
1260         g_free (dirname);
1261         return location;
1262 }
1263
1264 static gboolean
1265 ensure_directory_exists (const char *filename)
1266 {
1267 #ifdef PLATFORM_WIN32
1268         gchar *dir_utf8 = g_path_get_dirname (filename);
1269         gunichar2 *p;
1270         gunichar2 *dir_utf16 = NULL;
1271         int retval;
1272         
1273         if (!dir_utf8 || !dir_utf8 [0])
1274                 return FALSE;
1275
1276         dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
1277         g_free (dir_utf8);
1278
1279         if (!dir_utf16)
1280                 return FALSE;
1281
1282         p = dir_utf16;
1283
1284         /* make life easy and only use one directory seperator */
1285         while (*p != '\0')
1286         {
1287                 if (*p == '/')
1288                         *p = '\\';
1289                 p++;
1290         }
1291
1292         p = dir_utf16;
1293
1294         /* get past C:\ )*/
1295         while (*p++ != '\\')    
1296         {
1297         }
1298
1299         while (1) {
1300                 BOOL bRet = FALSE;
1301                 p = wcschr (p, '\\');
1302                 if (p)
1303                         *p = '\0';
1304                 retval = _wmkdir (dir_utf16);
1305                 if (retval != 0 && errno != EEXIST) {
1306                         g_free (dir_utf16);
1307                         return FALSE;
1308                 }
1309                 if (!p)
1310                         break;
1311                 *p++ = '\\';
1312         }
1313         
1314         g_free (dir_utf16);
1315         return TRUE;
1316 #else
1317         char *p;
1318         gchar *dir = g_path_get_dirname (filename);
1319         int retval;
1320         struct stat sbuf;
1321         
1322         if (!dir || !dir [0]) {
1323                 g_free (dir);
1324                 return FALSE;
1325         }
1326         
1327         if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
1328                 g_free (dir);
1329                 return TRUE;
1330         }
1331         
1332         p = dir;
1333         while (*p == '/')
1334                 p++;
1335
1336         while (1) {
1337                 p = strchr (p, '/');
1338                 if (p)
1339                         *p = '\0';
1340                 retval = mkdir (dir, 0777);
1341                 if (retval != 0 && errno != EEXIST) {
1342                         g_free (dir);
1343                         return FALSE;
1344                 }
1345                 if (!p)
1346                         break;
1347                 *p++ = '/';
1348         }
1349         
1350         g_free (dir);
1351         return TRUE;
1352 #endif
1353 }
1354
1355 static gboolean
1356 private_file_needs_copying (const char *src, struct stat *sbuf_src, char *dest)
1357 {
1358         struct stat sbuf_dest;
1359         
1360         if (stat (src, sbuf_src) == -1 || stat (dest, &sbuf_dest) == -1)
1361                 return TRUE;
1362
1363         if (sbuf_src->st_mode == sbuf_dest.st_mode &&
1364             sbuf_src->st_size == sbuf_dest.st_size &&
1365             sbuf_src->st_mtime == sbuf_dest.st_mtime)
1366                 return FALSE;
1367
1368         return TRUE;
1369 }
1370
1371 static gboolean
1372 shadow_copy_create_ini (const char *shadow, const char *filename)
1373 {
1374         char *dir_name;
1375         char *ini_file;
1376         guint16 *u16_ini;
1377         gboolean result;
1378         guint32 n;
1379         HANDLE *handle;
1380         gchar *full_path;
1381
1382         dir_name = g_path_get_dirname (shadow);
1383         ini_file = g_build_filename (dir_name, "__AssemblyInfo__.ini", NULL);
1384         g_free (dir_name);
1385         if (g_file_test (ini_file, G_FILE_TEST_IS_REGULAR)) {
1386                 g_free (ini_file);
1387                 return TRUE;
1388         }
1389
1390         u16_ini = g_utf8_to_utf16 (ini_file, strlen (ini_file), NULL, NULL, NULL);
1391         g_free (ini_file);
1392         if (!u16_ini) {
1393                 return FALSE;
1394         }
1395         handle = CreateFile (u16_ini, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
1396                                 NULL, CREATE_NEW, FileAttributes_Normal, NULL);
1397         g_free (u16_ini);
1398         if (handle == INVALID_HANDLE_VALUE) {
1399                 return FALSE;
1400         }
1401
1402         full_path = mono_path_resolve_symlinks (filename);
1403         result = WriteFile (handle, full_path, strlen (full_path), &n, NULL);
1404         g_free (full_path);
1405         CloseHandle (handle);
1406         return result;
1407 }
1408
1409 gboolean
1410 mono_is_shadow_copy_enabled (MonoDomain *domain, const gchar *dir_name)
1411 {
1412         const char *version;
1413         MonoAppDomainSetup *setup;
1414         gchar *all_dirs;
1415         gchar **dir_ptr;
1416         gchar **directories;
1417         gchar *shadow_status_string;
1418         gchar *base_dir;
1419         gboolean shadow_enabled;
1420         gboolean found = FALSE;
1421
1422         if (domain == NULL)
1423                 return FALSE;
1424
1425         setup = domain->setup;
1426         if (setup == NULL || setup->shadow_copy_files == NULL)
1427                 return FALSE;
1428
1429         version = mono_get_runtime_info ()->framework_version;
1430         shadow_status_string = mono_string_to_utf8 (setup->shadow_copy_files);
1431         /* For 1.x, not NULL is enough. In 2.0 it has to be "true" */
1432         shadow_enabled = (*version <= '1' || !g_ascii_strncasecmp (shadow_status_string, "true", 4));
1433         g_free (shadow_status_string);
1434         if (!shadow_enabled)
1435                 return FALSE;
1436
1437         if (setup->shadow_copy_directories == NULL)
1438                 return TRUE;
1439
1440         /* Is dir_name a shadow_copy destination already? */
1441         base_dir = get_shadow_assembly_location_base (domain);
1442         if (strstr (dir_name, base_dir)) {
1443                 g_free (base_dir);
1444                 return TRUE;
1445         }
1446         g_free (base_dir);
1447
1448         all_dirs = mono_string_to_utf8 (setup->shadow_copy_directories);
1449         directories = g_strsplit (all_dirs, G_SEARCHPATH_SEPARATOR_S, 1000);
1450         dir_ptr = directories;
1451         while (*dir_ptr) {
1452                 if (**dir_ptr != '\0' && !strcmp (*dir_ptr, dir_name)) {
1453                         found = TRUE;
1454                         break;
1455                 }
1456                 dir_ptr++;
1457         }
1458         g_strfreev (directories);
1459         g_free (all_dirs);
1460         return found;
1461 }
1462
1463 char *
1464 mono_make_shadow_copy (const char *filename)
1465 {
1466         gchar *sibling_source, *sibling_target;
1467         gint sibling_source_len, sibling_target_len;
1468         guint16 *orig, *dest;
1469         char *shadow;
1470         gboolean copy_result;
1471         MonoException *exc;
1472         struct stat src_sbuf;
1473         struct utimbuf utbuf;
1474         char *dir_name = g_path_get_dirname (filename);
1475         MonoDomain *domain = mono_domain_get ();
1476         char *shadow_dir;
1477
1478         set_domain_search_path (domain);
1479
1480         if (!mono_is_shadow_copy_enabled (domain, dir_name)) {
1481                 g_free (dir_name);
1482                 return (char *) filename;
1483         }
1484         /* Is dir_name a shadow_copy destination already? */
1485         shadow_dir = get_shadow_assembly_location_base (domain);
1486         if (strstr (dir_name, shadow_dir)) {
1487                 g_free (shadow_dir);
1488                 g_free (dir_name);
1489                 return (char *) filename;
1490         }
1491         g_free (shadow_dir);
1492         g_free (dir_name);
1493
1494         shadow = get_shadow_assembly_location (filename);
1495         if (ensure_directory_exists (shadow) == FALSE) {
1496                 g_free (shadow);
1497                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (ensure directory exists).");
1498                 mono_raise_exception (exc);
1499         }       
1500
1501         if (!private_file_needs_copying (filename, &src_sbuf, shadow))
1502                 return (char*) shadow;
1503
1504         orig = g_utf8_to_utf16 (filename, strlen (filename), NULL, NULL, NULL);
1505         dest = g_utf8_to_utf16 (shadow, strlen (shadow), NULL, NULL, NULL);
1506         DeleteFile (dest);
1507         copy_result = CopyFile (orig, dest, FALSE);
1508         g_free (dest);
1509         g_free (orig);
1510
1511         if (copy_result == FALSE) {
1512                 g_free (shadow);
1513                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy (CopyFile).");
1514                 mono_raise_exception (exc);
1515         }
1516
1517         /* attempt to copy .mdb, .config if they exist */
1518         sibling_source = g_strconcat (filename, ".config", NULL);
1519         sibling_source_len = strlen (sibling_source);
1520         sibling_target = g_strconcat (shadow, ".config", NULL);
1521         sibling_target_len = strlen (sibling_target);
1522         
1523         copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".mdb", sibling_target, sibling_target_len, 7);
1524         if (copy_result == TRUE)
1525                 copy_result = shadow_copy_sibling (sibling_source, sibling_source_len, ".config", sibling_target, sibling_target_len, 7);
1526         
1527         g_free (sibling_source);
1528         g_free (sibling_target);
1529         
1530         if (copy_result == FALSE)  {
1531                 g_free (shadow);
1532                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy of sibling data (CopyFile).");
1533                 mono_raise_exception (exc);
1534         }
1535
1536         /* Create a .ini file containing the original assembly location */
1537         if (!shadow_copy_create_ini (shadow, filename)) {
1538                 g_free (shadow);
1539                 exc = mono_get_exception_execution_engine ("Failed to create shadow copy .ini file.");
1540                 mono_raise_exception (exc);
1541         }
1542
1543         utbuf.actime = src_sbuf.st_atime;
1544         utbuf.modtime = src_sbuf.st_mtime;
1545         utime (shadow, &utbuf);
1546         
1547         return shadow;
1548 }
1549 #endif /* DISABLE_SHADOW_COPY */
1550
1551 MonoDomain *
1552 mono_domain_from_appdomain (MonoAppDomain *appdomain)
1553 {
1554         if (appdomain == NULL)
1555                 return NULL;
1556         
1557         return appdomain->data;
1558 }
1559
1560 static gboolean
1561 try_load_from (MonoAssembly **assembly, const gchar *path1, const gchar *path2,
1562                                         const gchar *path3, const gchar *path4,
1563                                         gboolean refonly, gboolean is_private)
1564 {
1565         gchar *fullpath;
1566         gboolean found = FALSE;
1567         
1568         *assembly = NULL;
1569         fullpath = g_build_filename (path1, path2, path3, path4, NULL);
1570
1571         if (IS_PORTABILITY_SET) {
1572                 gchar *new_fullpath = mono_portability_find_file (fullpath, TRUE);
1573                 if (new_fullpath) {
1574                         g_free (fullpath);
1575                         fullpath = new_fullpath;
1576                         found = TRUE;
1577                 }
1578         } else
1579                 found = g_file_test (fullpath, G_FILE_TEST_IS_REGULAR);
1580         
1581         if (found)
1582                 *assembly = mono_assembly_open_full (fullpath, NULL, refonly);
1583
1584         g_free (fullpath);
1585         return (*assembly != NULL);
1586 }
1587
1588 static MonoAssembly *
1589 real_load (gchar **search_path, const gchar *culture, const gchar *name, gboolean refonly)
1590 {
1591         MonoAssembly *result = NULL;
1592         gchar **path;
1593         gchar *filename;
1594         const gchar *local_culture;
1595         gint len;
1596         gboolean is_private = FALSE;
1597
1598         if (!culture || *culture == '\0') {
1599                 local_culture = "";
1600         } else {
1601                 local_culture = culture;
1602         }
1603
1604         filename =  g_strconcat (name, ".dll", NULL);
1605         len = strlen (filename);
1606
1607         for (path = search_path; *path; path++) {
1608                 if (**path == '\0') {
1609                         is_private = TRUE;
1610                         continue; /* Ignore empty ApplicationBase */
1611                 }
1612
1613                 /* See test cases in bug #58992 and bug #57710 */
1614                 /* 1st try: [culture]/[name].dll (culture may be empty) */
1615                 strcpy (filename + len - 4, ".dll");
1616                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1617                         break;
1618
1619                 /* 2nd try: [culture]/[name].exe (culture may be empty) */
1620                 strcpy (filename + len - 4, ".exe");
1621                 if (try_load_from (&result, *path, local_culture, "", filename, refonly, is_private))
1622                         break;
1623
1624                 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
1625                 strcpy (filename + len - 4, ".dll");
1626                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1627                         break;
1628
1629                 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
1630                 strcpy (filename + len - 4, ".exe");
1631                 if (try_load_from (&result, *path, local_culture, name, filename, refonly, is_private))
1632                         break;
1633         }
1634
1635         g_free (filename);
1636         return result;
1637 }
1638
1639 /*
1640  * Try loading the assembly from ApplicationBase and PrivateBinPath 
1641  * and then from assemblies_path if any.
1642  * LOCKING: This is called from the assembly loading code, which means the caller
1643  * might hold the loader lock. Thus, this function must not acquire the domain lock.
1644  */
1645 static MonoAssembly *
1646 mono_domain_assembly_preload (MonoAssemblyName *aname,
1647                               gchar **assemblies_path,
1648                               gpointer user_data)
1649 {
1650         MonoDomain *domain = mono_domain_get ();
1651         MonoAssembly *result = NULL;
1652         gboolean refonly = GPOINTER_TO_UINT (user_data);
1653
1654         set_domain_search_path (domain);
1655
1656         if (domain->search_path && domain->search_path [0] != NULL) {
1657                 result = real_load (domain->search_path, aname->culture, aname->name, refonly);
1658         }
1659
1660         if (result == NULL && assemblies_path && assemblies_path [0] != NULL) {
1661                 result = real_load (assemblies_path, aname->culture, aname->name, refonly);
1662         }
1663
1664         return result;
1665 }
1666
1667 /*
1668  * Check whenever a given assembly was already loaded in the current appdomain.
1669  */
1670 static MonoAssembly *
1671 mono_domain_assembly_search (MonoAssemblyName *aname,
1672                                                          gpointer user_data)
1673 {
1674         MonoDomain *domain = mono_domain_get ();
1675         GSList *tmp;
1676         MonoAssembly *ass;
1677         gboolean refonly = GPOINTER_TO_UINT (user_data);
1678
1679         mono_domain_assemblies_lock (domain);
1680         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
1681                 ass = tmp->data;
1682                 /* Dynamic assemblies can't match here in MS.NET */
1683                 if (ass->dynamic || refonly != ass->ref_only || !mono_assembly_names_equal (aname, &ass->aname))
1684                         continue;
1685
1686                 mono_domain_assemblies_unlock (domain);
1687                 return ass;
1688         }
1689         mono_domain_assemblies_unlock (domain);
1690
1691         return NULL;
1692 }
1693
1694 MonoReflectionAssembly *
1695 ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean refOnly)
1696 {
1697         MonoDomain *domain = mono_domain_get ();
1698         char *name, *filename;
1699         MonoImageOpenStatus status = MONO_IMAGE_OK;
1700         MonoAssembly *ass;
1701
1702         MONO_ARCH_SAVE_REGS;
1703
1704         if (fname == NULL) {
1705                 MonoException *exc = mono_get_exception_argument_null ("assemblyFile");
1706                 mono_raise_exception (exc);
1707         }
1708                 
1709         name = filename = mono_string_to_utf8 (fname);
1710         
1711         ass = mono_assembly_open_full (filename, &status, refOnly);
1712         
1713         if (!ass){
1714                 MonoException *exc;
1715
1716                 if (status == MONO_IMAGE_IMAGE_INVALID)
1717                         exc = mono_get_exception_bad_image_format2 (NULL, fname);
1718                 else
1719                         exc = mono_get_exception_file_not_found2 (NULL, fname);
1720                 g_free (name);
1721                 mono_raise_exception (exc);
1722         }
1723
1724         g_free (name);
1725
1726         return mono_assembly_get_object (domain, ass);
1727 }
1728
1729 MonoReflectionAssembly *
1730 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
1731                                             MonoArray *raw_assembly,
1732                                             MonoArray *raw_symbol_store, MonoObject *evidence,
1733                                             MonoBoolean refonly)
1734 {
1735         MonoAssembly *ass;
1736         MonoReflectionAssembly *refass = NULL;
1737         MonoDomain *domain = ad->data;
1738         MonoImageOpenStatus status;
1739         guint32 raw_assembly_len = mono_array_length (raw_assembly);
1740         MonoImage *image = mono_image_open_from_data_full (mono_array_addr (raw_assembly, gchar, 0), raw_assembly_len, TRUE, NULL, refonly);
1741
1742         if (!image) {
1743                 mono_raise_exception (mono_get_exception_bad_image_format (""));
1744                 return NULL;
1745         }
1746
1747         if (raw_symbol_store != NULL)
1748                 mono_debug_open_image_from_memory (image, mono_array_addr (raw_symbol_store, guint8, 0), mono_array_length (raw_symbol_store));
1749
1750         ass = mono_assembly_load_from_full (image, "", &status, refonly);
1751
1752
1753         if (!ass) {
1754                 mono_image_close (image);
1755                 mono_raise_exception (mono_get_exception_bad_image_format (""));
1756                 return NULL; 
1757         }
1758
1759         refass = mono_assembly_get_object (domain, ass);
1760         MONO_OBJECT_SETREF (refass, evidence, evidence);
1761         return refass;
1762 }
1763
1764 MonoReflectionAssembly *
1765 ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef, MonoObject *evidence, MonoBoolean refOnly)
1766 {
1767         MonoDomain *domain = ad->data; 
1768         MonoImageOpenStatus status = MONO_IMAGE_OK;
1769         MonoAssembly *ass;
1770         MonoAssemblyName aname;
1771         MonoReflectionAssembly *refass = NULL;
1772         gchar *name;
1773         gboolean parsed;
1774
1775         MONO_ARCH_SAVE_REGS;
1776
1777         g_assert (assRef != NULL);
1778
1779         name = mono_string_to_utf8 (assRef);
1780         parsed = mono_assembly_name_parse (name, &aname);
1781         g_free (name);
1782
1783         if (!parsed) {
1784                 /* This is a parse error... */
1785                 return NULL;
1786         }
1787
1788         ass = mono_assembly_load_full_nosearch (&aname, NULL, &status, refOnly);
1789         mono_assembly_name_free (&aname);
1790
1791         if (!ass) {
1792                 /* MS.NET doesn't seem to call the assembly resolve handler for refonly assemblies */
1793                 if (!refOnly)
1794                         refass = mono_try_assembly_resolve (domain, assRef, refOnly);
1795                 else
1796                         refass = NULL;
1797                 if (!refass) {
1798                         return NULL;
1799                 }
1800         }
1801
1802         if (refass == NULL)
1803                 refass = mono_assembly_get_object (domain, ass);
1804
1805         MONO_OBJECT_SETREF (refass, evidence, evidence);
1806         return refass;
1807 }
1808
1809 void
1810 ves_icall_System_AppDomain_InternalUnload (gint32 domain_id)
1811 {
1812         MonoDomain * domain = mono_domain_get_by_id (domain_id);
1813
1814         MONO_ARCH_SAVE_REGS;
1815
1816         if (NULL == domain) {
1817                 MonoException *exc = mono_get_exception_execution_engine ("Failed to unload domain, domain id not found");
1818                 mono_raise_exception (exc);
1819         }
1820         
1821         if (domain == mono_get_root_domain ()) {
1822                 mono_raise_exception (mono_get_exception_cannot_unload_appdomain ("The default appdomain can not be unloaded."));
1823                 return;
1824         }
1825
1826         /* 
1827          * Unloading seems to cause problems when running NUnit/NAnt, hence
1828          * this workaround.
1829          */
1830         if (g_getenv ("MONO_NO_UNLOAD"))
1831                 return;
1832
1833         mono_domain_unload (domain);
1834 }
1835
1836 gboolean
1837 ves_icall_System_AppDomain_InternalIsFinalizingForUnload (gint32 domain_id)
1838 {
1839         MonoDomain *domain = mono_domain_get_by_id (domain_id);
1840
1841         if (!domain)
1842                 return TRUE;
1843
1844         return mono_domain_is_unloading (domain);
1845 }
1846
1847 gint32
1848 ves_icall_System_AppDomain_ExecuteAssembly (MonoAppDomain *ad, 
1849                                                                                         MonoReflectionAssembly *refass, MonoArray *args)
1850 {
1851         MonoImage *image;
1852         MonoMethod *method;
1853
1854         MONO_ARCH_SAVE_REGS;
1855
1856         g_assert (refass);
1857         image = refass->assembly->image;
1858         g_assert (image);
1859
1860         method = mono_get_method (image, mono_image_get_entry_point (image), NULL);
1861
1862         if (!method)
1863                 g_error ("No entry point method found in %s", image->name);
1864
1865         if (!args)
1866                 args = (MonoArray *) mono_array_new (ad->data, mono_defaults.string_class, 0);
1867
1868         return mono_runtime_exec_main (method, (MonoArray *)args, NULL);
1869 }
1870
1871 gint32 
1872 ves_icall_System_AppDomain_GetIDFromDomain (MonoAppDomain * ad) 
1873 {
1874         MONO_ARCH_SAVE_REGS;
1875
1876         return ad->data->domain_id;
1877 }
1878
1879 MonoAppDomain * 
1880 ves_icall_System_AppDomain_InternalSetDomain (MonoAppDomain *ad)
1881 {
1882         MonoDomain *old_domain = mono_domain_get();
1883
1884         MONO_ARCH_SAVE_REGS;
1885
1886         if (!mono_domain_set (ad->data, FALSE))
1887                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
1888
1889         return old_domain->domain;
1890 }
1891
1892 MonoAppDomain * 
1893 ves_icall_System_AppDomain_InternalSetDomainByID (gint32 domainid)
1894 {
1895         MonoDomain *current_domain = mono_domain_get ();
1896         MonoDomain *domain = mono_domain_get_by_id (domainid);
1897
1898         MONO_ARCH_SAVE_REGS;
1899
1900         if (!domain || !mono_domain_set (domain, FALSE))        
1901                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
1902
1903         return current_domain->domain;
1904 }
1905
1906 void
1907 ves_icall_System_AppDomain_InternalPushDomainRef (MonoAppDomain *ad)
1908 {
1909         MONO_ARCH_SAVE_REGS;
1910
1911         mono_thread_push_appdomain_ref (ad->data);
1912 }
1913
1914 void
1915 ves_icall_System_AppDomain_InternalPushDomainRefByID (gint32 domain_id)
1916 {
1917         MonoDomain *domain = mono_domain_get_by_id (domain_id);
1918
1919         MONO_ARCH_SAVE_REGS;
1920
1921         if (!domain)
1922                 /* 
1923                  * Raise an exception to prevent the managed code from executing a pop
1924                  * later.
1925                  */
1926                 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
1927
1928         mono_thread_push_appdomain_ref (domain);
1929 }
1930
1931 void
1932 ves_icall_System_AppDomain_InternalPopDomainRef (void)
1933 {
1934         MONO_ARCH_SAVE_REGS;
1935
1936         mono_thread_pop_appdomain_ref ();
1937 }
1938
1939 MonoAppContext * 
1940 ves_icall_System_AppDomain_InternalGetContext ()
1941 {
1942         MONO_ARCH_SAVE_REGS;
1943
1944         return mono_context_get ();
1945 }
1946
1947 MonoAppContext * 
1948 ves_icall_System_AppDomain_InternalGetDefaultContext ()
1949 {
1950         MONO_ARCH_SAVE_REGS;
1951
1952         return mono_domain_get ()->default_context;
1953 }
1954
1955 MonoAppContext * 
1956 ves_icall_System_AppDomain_InternalSetContext (MonoAppContext *mc)
1957 {
1958         MonoAppContext *old_context = mono_context_get ();
1959
1960         MONO_ARCH_SAVE_REGS;
1961
1962         mono_context_set (mc);
1963
1964         return old_context;
1965 }
1966
1967 MonoString *
1968 ves_icall_System_AppDomain_InternalGetProcessGuid (MonoString* newguid)
1969 {
1970         MonoDomain* mono_root_domain = mono_get_root_domain ();
1971         mono_domain_lock (mono_root_domain);
1972         if (process_guid_set) {
1973                 mono_domain_unlock (mono_root_domain);
1974                 return mono_string_new_utf16 (mono_domain_get (), process_guid, sizeof(process_guid)/2);
1975         }
1976         memcpy (process_guid, mono_string_chars(newguid), sizeof(process_guid));
1977         process_guid_set = TRUE;
1978         mono_domain_unlock (mono_root_domain);
1979         return newguid;
1980 }
1981
1982 gboolean
1983 mono_domain_is_unloading (MonoDomain *domain)
1984 {
1985         if (domain->state == MONO_APPDOMAIN_UNLOADING || domain->state == MONO_APPDOMAIN_UNLOADED)
1986                 return TRUE;
1987         else
1988                 return FALSE;
1989 }
1990
1991 static void
1992 clear_cached_vtable (gpointer key, gpointer value, gpointer user_data)
1993 {
1994         MonoClass *klass = (MonoClass*)key;
1995         MonoVTable *vtable = value;
1996         MonoDomain *domain = (MonoDomain*)user_data;
1997         MonoClassRuntimeInfo *runtime_info;
1998
1999         runtime_info = klass->runtime_info;
2000         if (runtime_info && runtime_info->max_domain >= domain->domain_id)
2001                 runtime_info->domain_vtables [domain->domain_id] = NULL;
2002         if (vtable->data && klass->has_static_refs)
2003                 mono_gc_free_fixed (vtable->data);
2004 }
2005
2006 typedef struct unload_data {
2007         MonoDomain *domain;
2008         char *failure_reason;
2009 } unload_data;
2010
2011 #ifdef HAVE_SGEN_GC
2012 static void
2013 deregister_reflection_info_roots_nspace_table (gpointer key, gpointer value, gpointer image)
2014 {
2015         guint32 index = GPOINTER_TO_UINT (value);
2016         MonoClass *class = mono_class_get (image, MONO_TOKEN_TYPE_DEF | index);
2017
2018         g_assert (class);
2019
2020         if (class->reflection_info)
2021                 mono_gc_deregister_root ((char*) &class->reflection_info);
2022 }
2023
2024 static void
2025 deregister_reflection_info_roots_name_space (gpointer key, gpointer value, gpointer user_data)
2026 {
2027         g_hash_table_foreach (value, deregister_reflection_info_roots_nspace_table, user_data);
2028 }
2029
2030 static void
2031 deregister_reflection_info_roots_from_list (MonoImage *image)
2032 {
2033         GSList *list = image->reflection_info_unregister_classes;
2034
2035         while (list) {
2036                 MonoClass *class = list->data;
2037
2038                 g_assert (class->reflection_info);
2039                 mono_gc_deregister_root ((char*) &class->reflection_info);
2040
2041                 list = list->next;
2042         }
2043
2044         g_slist_free (image->reflection_info_unregister_classes);
2045         image->reflection_info_unregister_classes = NULL;
2046 }
2047
2048 static void
2049 deregister_reflection_info_roots (MonoDomain *domain)
2050 {
2051         GSList *list;
2052
2053         mono_loader_lock ();
2054         mono_domain_assemblies_lock (domain);
2055         for (list = domain->domain_assemblies; list; list = list->next) {
2056                 MonoAssembly *assembly = list->data;
2057                 MonoImage *image = assembly->image;
2058                 int i;
2059                 /*No need to take the image lock here since dynamic images are appdomain bound and at this point the mutator is gone.*/
2060                 if (image->dynamic && image->name_cache)
2061                         g_hash_table_foreach (image->name_cache, deregister_reflection_info_roots_name_space, image);
2062                 deregister_reflection_info_roots_from_list (image);
2063                 for (i = 0; i < image->module_count; ++i) {
2064                         MonoImage *module = image->modules [i];
2065                         if (module) {
2066                                 if (module->dynamic && module->name_cache) {
2067                                         g_hash_table_foreach (module->name_cache,
2068                                                         deregister_reflection_info_roots_name_space, module);
2069                                 }
2070                                 deregister_reflection_info_roots_from_list (module);
2071                         }
2072                 }
2073         }
2074         mono_domain_assemblies_unlock (domain);
2075         mono_loader_unlock ();
2076 }
2077 #endif
2078
2079 static guint32 WINAPI
2080 unload_thread_main (void *arg)
2081 {
2082         unload_data *data = (unload_data*)arg;
2083         MonoDomain *domain = data->domain;
2084
2085         /* Have to attach to the runtime so shutdown can wait for this thread */
2086         mono_thread_attach (mono_get_root_domain ());
2087
2088         /* 
2089          * FIXME: Abort our parent thread last, so we can return a failure 
2090          * indication if aborting times out.
2091          */
2092         if (!mono_threads_abort_appdomain_threads (domain, -1)) {
2093                 data->failure_reason = g_strdup_printf ("Aborting of threads in domain %s timed out.", domain->friendly_name);
2094                 return 1;
2095         }
2096
2097         if (!mono_thread_pool_remove_domain_jobs (domain, -1)) {
2098                 data->failure_reason = g_strdup_printf ("Cleanup of threadpool jobs of domain %s timed out.", domain->friendly_name);
2099                 return 1;
2100         }
2101
2102         /* Finalize all finalizable objects in the doomed appdomain */
2103         if (!mono_domain_finalize (domain, -1)) {
2104                 data->failure_reason = g_strdup_printf ("Finalization of domain %s timed out.", domain->friendly_name);
2105                 return 1;
2106         }
2107
2108         /* Clear references to our vtables in class->runtime_info.
2109          * We also hold the loader lock because we're going to change
2110          * class->runtime_info.
2111          */
2112
2113         mono_loader_lock ();
2114         mono_domain_lock (domain);
2115         g_hash_table_foreach (domain->class_vtable_hash, clear_cached_vtable, domain);
2116 #ifdef HAVE_SGEN_GC
2117         deregister_reflection_info_roots (domain);
2118 #endif
2119         mono_domain_unlock (domain);
2120         mono_loader_unlock ();
2121
2122         mono_threads_clear_cached_culture (domain);
2123
2124         domain->state = MONO_APPDOMAIN_UNLOADED;
2125
2126         /* printf ("UNLOADED %s.\n", domain->friendly_name); */
2127
2128         /* remove from the handle table the items related to this domain */
2129         mono_gchandle_free_domain (domain);
2130
2131         mono_domain_free (domain, FALSE);
2132
2133         mono_gc_collect (mono_gc_max_generation ());
2134
2135         return 0;
2136 }
2137
2138 /*
2139  * mono_domain_unload:
2140  * @domain: The domain to unload
2141  *
2142  *  Unloads an appdomain. Follows the process outlined in the comment
2143  *  for mono_domain_try_unload.
2144  */
2145 void
2146 mono_domain_unload (MonoDomain *domain)
2147 {
2148         MonoObject *exc = NULL;
2149         mono_domain_try_unload (domain, &exc);
2150         if (exc)
2151                 mono_raise_exception ((MonoException*)exc);
2152 }
2153
2154 /*
2155  * mono_domain_unload:
2156  * @domain: The domain to unload
2157  * @exc: Exception information
2158  *
2159  *  Unloads an appdomain. Follows the process outlined in:
2160  *  http://blogs.gotdotnet.com/cbrumme
2161  *
2162  *  If doing things the 'right' way is too hard or complex, we do it the 
2163  *  'simple' way, which means do everything needed to avoid crashes and
2164  *  memory leaks, but not much else.
2165  *
2166  *  It is required to pass a valid reference to the exc argument, upon return
2167  *  from this function *exc will be set to the exception thrown, if any.
2168  *
2169  *  If this method is not called from an icall (embedded scenario for instance),
2170  *  it must not be called with any managed frames on the stack, since the unload
2171  *  process could end up trying to abort the current thread.
2172  */
2173 void
2174 mono_domain_try_unload (MonoDomain *domain, MonoObject **exc)
2175 {
2176         HANDLE thread_handle;
2177         gsize tid;
2178         guint32 res;
2179         MonoAppDomainState prev_state;
2180         MonoMethod *method;
2181         unload_data thread_data;
2182         MonoDomain *caller_domain = mono_domain_get ();
2183
2184         /* printf ("UNLOAD STARTING FOR %s (%p) IN THREAD 0x%x.\n", domain->friendly_name, domain, GetCurrentThreadId ()); */
2185
2186         /* Atomically change our state to UNLOADING */
2187         prev_state = InterlockedCompareExchange ((gint32*)&domain->state,
2188                                                                                          MONO_APPDOMAIN_UNLOADING_START,
2189                                                                                          MONO_APPDOMAIN_CREATED);
2190         if (prev_state != MONO_APPDOMAIN_CREATED) {
2191                 switch (prev_state) {
2192                 case MONO_APPDOMAIN_UNLOADING_START:
2193                 case MONO_APPDOMAIN_UNLOADING:
2194                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already being unloaded.");
2195                         return;
2196                 case MONO_APPDOMAIN_UNLOADED:
2197                         *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain ("Appdomain is already unloaded.");
2198                         return;
2199                 default:
2200                         g_warning ("Incalid appdomain state %d", prev_state);
2201                         g_assert_not_reached ();
2202                 }
2203         }
2204
2205         mono_debugger_event_unload_appdomain (domain);
2206
2207         mono_domain_set (domain, FALSE);
2208         /* Notify OnDomainUnload listeners */
2209         method = mono_class_get_method_from_name (domain->domain->mbr.obj.vtable->klass, "DoDomainUnload", -1); 
2210         g_assert (method);
2211
2212         mono_runtime_invoke (method, domain->domain, NULL, exc);
2213         if (*exc) {
2214                 /* Roll back the state change */
2215                 domain->state = MONO_APPDOMAIN_CREATED;
2216                 mono_domain_set (caller_domain, FALSE);
2217                 return;
2218         }
2219         mono_domain_set (caller_domain, FALSE);
2220
2221         thread_data.domain = domain;
2222         thread_data.failure_reason = NULL;
2223
2224         /*The managed callback finished successfully, now we start tearing down the appdomain*/
2225         domain->state = MONO_APPDOMAIN_UNLOADING;
2226         /* 
2227          * First we create a separate thread for unloading, since
2228          * we might have to abort some threads, including the current one.
2229          */
2230         /*
2231          * If we create a non-suspended thread, the runtime will hang.
2232          * See:
2233          * http://bugzilla.ximian.com/show_bug.cgi?id=27663
2234          */ 
2235 #if 0
2236         thread_handle = mono_create_thread (NULL, 0, unload_thread_main, &thread_data, 0, &tid);
2237 #else
2238         thread_handle = mono_create_thread (NULL, 0, (LPTHREAD_START_ROUTINE)unload_thread_main, &thread_data, CREATE_SUSPENDED, &tid);
2239         if (thread_handle == NULL) {
2240                 return;
2241         }
2242         ResumeThread (thread_handle);
2243 #endif
2244
2245         /* Wait for the thread */       
2246         while ((res = WaitForSingleObjectEx (thread_handle, INFINITE, TRUE) == WAIT_IO_COMPLETION)) {
2247                 if (mono_thread_internal_has_appdomain_ref (mono_thread_internal_current (), domain) && (mono_thread_interruption_requested ()))
2248                         /* The unload thread tries to abort us */
2249                         /* The icall wrapper will execute the abort */
2250                         CloseHandle (thread_handle);
2251                         return;
2252         }
2253         CloseHandle (thread_handle);
2254
2255         if (thread_data.failure_reason) {
2256                 /* Roll back the state change */
2257                 domain->state = MONO_APPDOMAIN_CREATED;
2258
2259                 g_warning ("%s", thread_data.failure_reason);
2260
2261                 *exc = (MonoObject *) mono_get_exception_cannot_unload_appdomain (thread_data.failure_reason);
2262
2263                 g_free (thread_data.failure_reason);
2264                 thread_data.failure_reason = NULL;
2265         }
2266 }