Merge pull request #2998 from lateralusX/jlorenss/win-x64-full-aot-support
[mono.git] / mono / metadata / gc.c
1 /*
2  * metadata/gc.c: GC icalls.
3  *
4  * Author: Paolo Molaro <lupus@ximian.com>
5  *
6  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
7  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
8  * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #include <config.h>
13 #include <glib.h>
14 #include <string.h>
15
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/mono-gc.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/metadata-internals.h>
25 #include <mono/metadata/mono-mlist.h>
26 #include <mono/metadata/threads-types.h>
27 #include <mono/metadata/threadpool-ms.h>
28 #include <mono/sgen/sgen-conf.h>
29 #include <mono/sgen/sgen-gc.h>
30 #include <mono/utils/mono-logger-internals.h>
31 #include <mono/metadata/gc-internals.h>
32 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
33 #include <mono/metadata/attach.h>
34 #include <mono/metadata/console-io.h>
35 #include <mono/utils/mono-os-semaphore.h>
36 #include <mono/utils/mono-memory-model.h>
37 #include <mono/utils/mono-counters.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/dtrace.h>
40 #include <mono/utils/mono-threads.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-coop-semaphore.h>
43 #include <mono/utils/hazard-pointer.h>
44
45 #ifndef HOST_WIN32
46 #include <pthread.h>
47 #endif
48
49 typedef struct DomainFinalizationReq {
50         MonoDomain *domain;
51         HANDLE done_event;
52 } DomainFinalizationReq;
53
54 static gboolean gc_disabled = FALSE;
55
56 static gboolean finalizing_root_domain = FALSE;
57
58 gboolean log_finalizers = FALSE;
59 gboolean mono_do_not_finalize = FALSE;
60 gchar **mono_do_not_finalize_class_names = NULL;
61
62 #define mono_finalizer_lock() mono_coop_mutex_lock (&finalizer_mutex)
63 #define mono_finalizer_unlock() mono_coop_mutex_unlock (&finalizer_mutex)
64 static MonoCoopMutex finalizer_mutex;
65 static MonoCoopMutex reference_queue_mutex;
66
67 static GSList *domains_to_finalize= NULL;
68 static MonoMList *threads_to_finalize = NULL;
69
70 static gboolean finalizer_thread_exited;
71 /* Uses finalizer_mutex */
72 static MonoCoopCond exited_cond;
73
74 static MonoInternalThread *gc_thread;
75
76 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*), MonoError *error);
77
78 static void reference_queue_proccess_all (void);
79 static void mono_reference_queue_cleanup (void);
80 static void reference_queue_clear_for_domain (MonoDomain *domain);
81 static HANDLE pending_done_event;
82
83 static guint32
84 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
85 {
86         guint32 result;
87
88         MONO_ENTER_GC_SAFE;
89         result = WaitForSingleObjectEx (handle, timeout, alertable);
90         MONO_EXIT_GC_SAFE;
91
92         return result;
93 }
94
95 static void
96 add_thread_to_finalize (MonoInternalThread *thread)
97 {
98         MonoError error;
99         mono_finalizer_lock ();
100         if (!threads_to_finalize)
101                 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize, MONO_ROOT_SOURCE_FINALIZER_QUEUE, "finalizable threads list");
102         threads_to_finalize = mono_mlist_append_checked (threads_to_finalize, (MonoObject*)thread, &error);
103         mono_finalizer_unlock ();
104         mono_error_raise_exception (&error); /* FIXME don't raise here */
105 }
106
107 static gboolean suspend_finalizers = FALSE;
108 /* 
109  * actually, we might want to queue the finalize requests in a separate thread,
110  * but we need to be careful about the execution domain of the thread...
111  */
112 void
113 mono_gc_run_finalize (void *obj, void *data)
114 {
115         MonoError error;
116         MonoObject *exc = NULL;
117         MonoObject *o;
118 #ifndef HAVE_SGEN_GC
119         MonoObject *o2;
120 #endif
121         MonoMethod* finalizer = NULL;
122         MonoDomain *caller_domain = mono_domain_get ();
123         MonoDomain *domain;
124         RuntimeInvokeFunction runtime_invoke;
125
126         // This function is called from the innards of the GC, so our best alternative for now is to do polling here
127         mono_threads_safepoint ();
128
129         o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
130
131         if (mono_do_not_finalize) {
132                 if (!mono_do_not_finalize_class_names)
133                         return;
134
135                 size_t namespace_len = strlen (o->vtable->klass->name_space);
136                 for (int i = 0; mono_do_not_finalize_class_names [i]; ++i) {
137                         const char *name = mono_do_not_finalize_class_names [i];
138                         if (strncmp (name, o->vtable->klass->name_space, namespace_len))
139                                 break;
140                         if (name [namespace_len] != '.')
141                                 break;
142                         if (strcmp (name + namespace_len + 1, o->vtable->klass->name))
143                                 break;
144                         return;
145                 }
146         }
147
148         if (log_finalizers)
149                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_DEBUG, "<%s at %p> Starting finalizer checks.", o->vtable->klass->name, o);
150
151         if (suspend_finalizers)
152                 return;
153
154         domain = o->vtable->domain;
155
156 #ifndef HAVE_SGEN_GC
157         mono_domain_finalizers_lock (domain);
158
159         o2 = (MonoObject *)g_hash_table_lookup (domain->finalizable_objects_hash, o);
160
161         mono_domain_finalizers_unlock (domain);
162
163         if (!o2)
164                 /* Already finalized somehow */
165                 return;
166 #endif
167
168         /* make sure the finalizer is not called again if the object is resurrected */
169         object_register_finalizer ((MonoObject *)obj, NULL, &error);
170         mono_error_assert_ok (&error); /* FIXME don't swallow the error */
171
172         if (log_finalizers)
173                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Registered finalizer as processed.", o->vtable->klass->name, o);
174
175         if (o->vtable->klass == mono_defaults.internal_thread_class) {
176                 MonoInternalThread *t = (MonoInternalThread*)o;
177
178                 if (mono_gc_is_finalizer_internal_thread (t))
179                         /* Avoid finalizing ourselves */
180                         return;
181
182                 if (t->threadpool_thread && finalizing_root_domain) {
183                         /* Don't finalize threadpool threads when
184                            shutting down - they're finalized when the
185                            threadpool shuts down. */
186                         add_thread_to_finalize (t);
187                         return;
188                 }
189         }
190
191         if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
192                 /*
193                  * These can't be finalized during unloading/shutdown, since that would
194                  * free the native code which can still be referenced by other
195                  * finalizers.
196                  * FIXME: This is not perfect, objects dying at the same time as 
197                  * dynamic methods can still reference them even when !shutdown.
198                  */
199                 return;
200         }
201
202         if (mono_runtime_get_no_exec ())
203                 return;
204
205         /* speedup later... and use a timeout */
206         /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
207
208         /* Use _internal here, since this thread can enter a doomed appdomain */
209         mono_domain_set_internal (mono_object_domain (o));
210
211         /* delegates that have a native function pointer allocated are
212          * registered for finalization, but they don't have a Finalize
213          * method, because in most cases it's not needed and it's just a waste.
214          */
215         if (o->vtable->klass->delegate) {
216                 MonoDelegate* del = (MonoDelegate*)o;
217                 if (del->delegate_trampoline)
218                         mono_delegate_free_ftnptr ((MonoDelegate*)o);
219                 mono_domain_set_internal (caller_domain);
220                 return;
221         }
222
223         finalizer = mono_class_get_finalizer (o->vtable->klass);
224
225         /* If object has a CCW but has no finalizer, it was only
226          * registered for finalization in order to free the CCW.
227          * Else it needs the regular finalizer run.
228          * FIXME: what to do about ressurection and suppression
229          * of finalizer on object with CCW.
230          */
231         if (mono_marshal_free_ccw (o) && !finalizer) {
232                 mono_domain_set_internal (caller_domain);
233                 return;
234         }
235
236         /* 
237          * To avoid the locking plus the other overhead of mono_runtime_invoke_checked (),
238          * create and precompile a wrapper which calls the finalize method using
239          * a CALLVIRT.
240          */
241         if (log_finalizers)
242                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o->vtable->klass->name, o);
243
244         if (!domain->finalize_runtime_invoke) {
245                 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
246
247                 domain->finalize_runtime_invoke = mono_compile_method_checked (invoke, &error);
248                 mono_error_assert_ok (&error); /* expect this not to fail */
249         }
250
251         runtime_invoke = (RuntimeInvokeFunction)domain->finalize_runtime_invoke;
252
253         mono_runtime_class_init_full (o->vtable, &error);
254         mono_error_raise_exception (&error); /* FIXME don't raise here */
255
256         if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
257                 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
258                                 o->vtable->klass->name_space, o->vtable->klass->name);
259         }
260
261         if (log_finalizers)
262                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o->vtable->klass->name, o);
263
264         runtime_invoke (o, NULL, &exc, NULL);
265
266         if (log_finalizers)
267                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o);
268
269         if (exc)
270                 mono_thread_internal_unhandled_exception (exc);
271
272         mono_domain_set_internal (caller_domain);
273 }
274
275 void
276 mono_gc_finalize_threadpool_threads (void)
277 {
278         MonoError error;
279         while (threads_to_finalize) {
280                 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
281
282                 /* Force finalization of the thread. */
283                 thread->threadpool_thread = FALSE;
284                 mono_object_register_finalizer ((MonoObject*)thread, &error);
285                 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
286
287                 mono_gc_run_finalize (thread, NULL);
288
289                 threads_to_finalize = mono_mlist_next (threads_to_finalize);
290         }
291 }
292
293 gpointer
294 mono_gc_out_of_memory (size_t size)
295 {
296         /* 
297          * we could allocate at program startup some memory that we could release 
298          * back to the system at this point if we're really low on memory (ie, size is
299          * lower than the memory we set apart)
300          */
301         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
302
303         return NULL;
304 }
305
306 /*
307  * Some of our objects may point to a different address than the address returned by GC_malloc()
308  * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
309  * This also means that in the callback we need to adjust the pointer to get back the real
310  * MonoObject*.
311  * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
312  * since that, too, can cause the underlying pointer to be offset.
313  */
314 static void
315 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*), MonoError *error)
316 {
317         MonoDomain *domain;
318
319         mono_error_init (error);
320
321         if (obj == NULL) {
322                 mono_error_set_argument_null (error, "obj", "");
323                 return;
324         }
325
326         domain = obj->vtable->domain;
327
328 #if HAVE_BOEHM_GC
329         if (mono_domain_is_unloading (domain) && (callback != NULL))
330                 /*
331                  * Can't register finalizers in a dying appdomain, since they
332                  * could be invoked after the appdomain has been unloaded.
333                  */
334                 return;
335
336         mono_domain_finalizers_lock (domain);
337
338         if (callback)
339                 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
340         else
341                 g_hash_table_remove (domain->finalizable_objects_hash, obj);
342
343         mono_domain_finalizers_unlock (domain);
344
345         mono_gc_register_for_finalization (obj, callback);
346 #elif defined(HAVE_SGEN_GC)
347         /*
348          * If we register finalizers for domains that are unloading we might
349          * end up running them while or after the domain is being cleared, so
350          * the objects will not be valid anymore.
351          */
352         if (!mono_domain_is_unloading (domain))
353                 mono_gc_register_for_finalization (obj, callback);
354 #endif
355 }
356
357 /**
358  * mono_object_register_finalizer:
359  * @obj: object to register
360  *
361  * Records that object @obj has a finalizer, this will call the
362  * Finalize method when the garbage collector disposes the object.
363  * 
364  */
365 void
366 mono_object_register_finalizer (MonoObject *obj, MonoError *error)
367 {
368         /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
369         object_register_finalizer (obj, mono_gc_run_finalize, error);
370 }
371
372 /**
373  * mono_domain_finalize:
374  * @domain: the domain to finalize
375  * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
376  *
377  *  Request finalization of all finalizable objects inside @domain. Wait
378  * @timeout msecs for the finalization to complete.
379  *
380  * Returns: TRUE if succeeded, FALSE if there was a timeout
381  */
382
383 gboolean
384 mono_domain_finalize (MonoDomain *domain, guint32 timeout) 
385 {
386         DomainFinalizationReq *req;
387         guint32 res;
388         HANDLE done_event;
389         MonoInternalThread *thread = mono_thread_internal_current ();
390
391 #if defined(__native_client__)
392         return FALSE;
393 #endif
394
395         if (mono_thread_internal_current () == gc_thread)
396                 /* We are called from inside a finalizer, not much we can do here */
397                 return FALSE;
398
399         /* 
400          * No need to create another thread 'cause the finalizer thread
401          * is still working and will take care of running the finalizers
402          */ 
403         
404         if (gc_disabled)
405                 return TRUE;
406
407         /* We don't support domain finalization without a GC */
408         if (mono_gc_is_null ())
409                 return FALSE;
410
411         mono_gc_collect (mono_gc_max_generation ());
412
413         done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
414         if (done_event == NULL) {
415                 return FALSE;
416         }
417
418         req = g_new0 (DomainFinalizationReq, 1);
419         req->domain = domain;
420         req->done_event = done_event;
421
422         if (domain == mono_get_root_domain ())
423                 finalizing_root_domain = TRUE;
424         
425         mono_finalizer_lock ();
426
427         domains_to_finalize = g_slist_append (domains_to_finalize, req);
428
429         mono_finalizer_unlock ();
430
431         /* Tell the finalizer thread to finalize this appdomain */
432         mono_gc_finalize_notify ();
433
434         if (timeout == -1)
435                 timeout = INFINITE;
436
437         while (TRUE) {
438                 res = guarded_wait (done_event, timeout, TRUE);
439                 /* printf ("WAIT RES: %d.\n", res); */
440
441                 if (res == WAIT_IO_COMPLETION) {
442                         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
443                                 return FALSE;
444                 } else if (res == WAIT_TIMEOUT) {
445                         /* We leak the handle here */
446                         return FALSE;
447                 } else {
448                         break;
449                 }
450         }
451
452         CloseHandle (done_event);
453
454         if (domain == mono_get_root_domain ()) {
455                 mono_threadpool_ms_cleanup ();
456                 mono_gc_finalize_threadpool_threads ();
457         }
458
459         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
460
461         return TRUE;
462 }
463
464 void
465 ves_icall_System_GC_InternalCollect (int generation)
466 {
467         mono_gc_collect (generation);
468 }
469
470 gint64
471 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
472 {
473         if (forceCollection)
474                 mono_gc_collect (mono_gc_max_generation ());
475         return mono_gc_get_used_size ();
476 }
477
478 void
479 ves_icall_System_GC_KeepAlive (MonoObject *obj)
480 {
481         /*
482          * Does nothing.
483          */
484 }
485
486 void
487 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
488 {
489         MonoError error;
490
491         MONO_CHECK_ARG_NULL (obj,);
492
493         object_register_finalizer (obj, mono_gc_run_finalize, &error);
494         mono_error_set_pending_exception (&error);
495 }
496
497 void
498 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
499 {
500         MonoError error;
501
502         MONO_CHECK_ARG_NULL (obj,);
503
504         /* delegates have no finalizers, but we register them to deal with the
505          * unmanaged->managed trampoline. We don't let the user suppress it
506          * otherwise we'd leak it.
507          */
508         if (obj->vtable->klass->delegate)
509                 return;
510
511         /* FIXME: Need to handle case where obj has COM Callable Wrapper
512          * generated for it that needs cleaned up, but user wants to suppress
513          * their derived object finalizer. */
514
515         object_register_finalizer (obj, NULL, &error);
516         mono_error_set_pending_exception (&error);
517 }
518
519 void
520 ves_icall_System_GC_WaitForPendingFinalizers (void)
521 {
522         if (mono_gc_is_null ())
523                 return;
524
525         if (!mono_gc_pending_finalizers ())
526                 return;
527
528         if (mono_thread_internal_current () == gc_thread)
529                 /* Avoid deadlocks */
530                 return;
531
532         /*
533         If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
534         be the one responsible for starting it up.
535         */
536         if (gc_thread == NULL)
537                 return;
538
539         ResetEvent (pending_done_event);
540         mono_gc_finalize_notify ();
541         /* g_print ("Waiting for pending finalizers....\n"); */
542         guarded_wait (pending_done_event, INFINITE, TRUE);
543         /* g_print ("Done pending....\n"); */
544 }
545
546 void
547 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
548 {
549 #ifdef HAVE_SGEN_GC
550         if (!mono_gc_ephemeron_array_add (array)) {
551                 mono_set_pending_exception (mono_object_domain (array)->out_of_memory_ex);
552                 return;
553         }
554 #endif
555 }
556
557 MonoObject*
558 ves_icall_System_GC_get_ephemeron_tombstone (void)
559 {
560         return mono_domain_get ()->ephemeron_tombstone;
561 }
562
563 MonoObject *
564 ves_icall_System_GCHandle_GetTarget (guint32 handle)
565 {
566         return mono_gchandle_get_target (handle);
567 }
568
569 /*
570  * if type == -1, change the target of the handle, otherwise allocate a new handle.
571  */
572 guint32
573 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
574 {
575         if (type == -1) {
576                 mono_gchandle_set_target (handle, obj);
577                 /* the handle doesn't change */
578                 return handle;
579         }
580         switch (type) {
581         case HANDLE_WEAK:
582                 return mono_gchandle_new_weakref (obj, FALSE);
583         case HANDLE_WEAK_TRACK:
584                 return mono_gchandle_new_weakref (obj, TRUE);
585         case HANDLE_NORMAL:
586                 return mono_gchandle_new (obj, FALSE);
587         case HANDLE_PINNED:
588                 return mono_gchandle_new (obj, TRUE);
589         default:
590                 g_assert_not_reached ();
591         }
592         return 0;
593 }
594
595 void
596 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
597 {
598         mono_gchandle_free (handle);
599 }
600
601 gpointer
602 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
603 {
604         MonoObject *obj;
605
606         if (MONO_GC_HANDLE_TYPE (handle) != HANDLE_PINNED)
607                 return (gpointer)-2;
608         obj = mono_gchandle_get_target (handle);
609         if (obj) {
610                 MonoClass *klass = mono_object_class (obj);
611                 if (klass == mono_defaults.string_class) {
612                         return mono_string_chars ((MonoString*)obj);
613                 } else if (klass->rank) {
614                         return mono_array_addr ((MonoArray*)obj, char, 0);
615                 } else {
616                         /* the C# code will check and throw the exception */
617                         /* FIXME: missing !klass->blittable test, see bug #61134 */
618                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
619                                 return (gpointer)-1;
620                         return (char*)obj + sizeof (MonoObject);
621                 }
622         }
623         return NULL;
624 }
625
626 MonoBoolean
627 mono_gc_GCHandle_CheckCurrentDomain (guint32 gchandle)
628 {
629         return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
630 }
631
632 static MonoCoopSem finalizer_sem;
633 static volatile gboolean finished=FALSE;
634
635 void
636 mono_gc_finalize_notify (void)
637 {
638 #ifdef DEBUG
639         g_message ( "%s: prodding finalizer", __func__);
640 #endif
641
642         if (mono_gc_is_null ())
643                 return;
644
645         mono_coop_sem_post (&finalizer_sem);
646 }
647
648 /*
649 This is the number of entries allowed in the hazard free queue before
650 we explicitly cycle the finalizer thread to trigger pumping the queue.
651
652 It was picked empirically by running the corlib test suite in a stress
653 scenario where all hazard entries are queued.
654
655 In this extreme scenario we double the number of times we cycle the finalizer
656 thread compared to just GC calls.
657
658 Entries are usually in the order of 100's of bytes each, so we're limiting
659 floating garbage to be in the order of a dozen kb.
660 */
661 static gboolean finalizer_thread_pulsed;
662 #define HAZARD_QUEUE_OVERFLOW_SIZE 20
663
664 static void
665 hazard_free_queue_is_too_big (size_t size)
666 {
667         if (size < HAZARD_QUEUE_OVERFLOW_SIZE)
668                 return;
669
670         if (finalizer_thread_pulsed || InterlockedCompareExchange (&finalizer_thread_pulsed, TRUE, FALSE))
671                 return;
672
673         mono_gc_finalize_notify ();
674 }
675
676 static void
677 hazard_free_queue_pump (void)
678 {
679         mono_thread_hazardous_try_free_all ();
680         finalizer_thread_pulsed = FALSE;
681 }
682
683 #ifdef HAVE_BOEHM_GC
684
685 static void
686 collect_objects (gpointer key, gpointer value, gpointer user_data)
687 {
688         GPtrArray *arr = (GPtrArray*)user_data;
689         g_ptr_array_add (arr, key);
690 }
691
692 #endif
693
694 /*
695  * finalize_domain_objects:
696  *
697  *  Run the finalizers of all finalizable objects in req->domain.
698  */
699 static void
700 finalize_domain_objects (DomainFinalizationReq *req)
701 {
702         MonoDomain *domain = req->domain;
703
704 #if HAVE_SGEN_GC
705 #define NUM_FOBJECTS 64
706         MonoObject *to_finalize [NUM_FOBJECTS];
707         int count;
708 #endif
709
710         /* Process finalizers which are already in the queue */
711         mono_gc_invoke_finalizers ();
712
713 #ifdef HAVE_BOEHM_GC
714         while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
715                 int i;
716                 GPtrArray *objs;
717                 /* 
718                  * Since the domain is unloading, nobody is allowed to put
719                  * new entries into the hash table. But finalize_object might
720                  * remove entries from the hash table, so we make a copy.
721                  */
722                 objs = g_ptr_array_new ();
723                 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
724                 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
725
726                 for (i = 0; i < objs->len; ++i) {
727                         MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
728                         /* FIXME: Avoid finalizing threads, etc */
729                         mono_gc_run_finalize (o, 0);
730                 }
731
732                 g_ptr_array_free (objs, TRUE);
733         }
734 #elif defined(HAVE_SGEN_GC)
735         while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
736                 int i;
737                 for (i = 0; i < count; ++i) {
738                         mono_gc_run_finalize (to_finalize [i], 0);
739                 }
740         }
741 #endif
742
743         /* cleanup the reference queue */
744         reference_queue_clear_for_domain (domain);
745         
746         /* printf ("DONE.\n"); */
747         SetEvent (req->done_event);
748
749         /* The event is closed in mono_domain_finalize if we get here */
750         g_free (req);
751 }
752
753 static guint32
754 finalizer_thread (gpointer unused)
755 {
756         MonoError error;
757         mono_thread_set_name_internal (mono_thread_internal_current (), mono_string_new (mono_get_root_domain (), "Finalizer"), FALSE, &error);
758         mono_error_assert_ok (&error);
759
760         gboolean wait = TRUE;
761
762         /* Register a hazard free queue pump callback */
763         mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);
764
765         while (!finished) {
766                 /* Wait to be notified that there's at least one
767                  * finaliser to run
768                  */
769
770                 g_assert (mono_domain_get () == mono_get_root_domain ());
771                 mono_gc_set_skip_thread (TRUE);
772
773                 if (wait) {
774                         /* An alertable wait is required so this thread can be suspended on windows */
775                         mono_coop_sem_wait (&finalizer_sem, MONO_SEM_FLAGS_ALERTABLE);
776                 }
777                 wait = TRUE;
778
779                 mono_gc_set_skip_thread (FALSE);
780
781                 mono_threads_perform_thread_dump ();
782
783                 mono_console_handle_async_ops ();
784
785                 mono_attach_maybe_start ();
786
787                 if (domains_to_finalize) {
788                         mono_finalizer_lock ();
789                         if (domains_to_finalize) {
790                                 DomainFinalizationReq *req = (DomainFinalizationReq *)domains_to_finalize->data;
791                                 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
792                                 mono_finalizer_unlock ();
793
794                                 finalize_domain_objects (req);
795                         } else {
796                                 mono_finalizer_unlock ();
797                         }
798                 }                               
799
800                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
801                  * before the domain is unloaded.
802                  */
803                 mono_gc_invoke_finalizers ();
804
805                 mono_threads_join_threads ();
806
807                 reference_queue_proccess_all ();
808
809                 hazard_free_queue_pump ();
810
811                 /* Avoid posting the pending done event until there are pending finalizers */
812                 if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == 0) {
813                         /* Don't wait again at the start of the loop */
814                         wait = FALSE;
815                 } else {
816                         SetEvent (pending_done_event);
817                 }
818         }
819
820         mono_finalizer_lock ();
821         finalizer_thread_exited = TRUE;
822         mono_coop_cond_signal (&exited_cond);
823         mono_finalizer_unlock ();
824
825         return 0;
826 }
827
828 #ifndef LAZY_GC_THREAD_CREATION
829 static
830 #endif
831 void
832 mono_gc_init_finalizer_thread (void)
833 {
834         MonoError error;
835         gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0, &error);
836         mono_error_assert_ok (&error);
837 }
838
839 void
840 mono_gc_init (void)
841 {
842         mono_coop_mutex_init_recursive (&finalizer_mutex);
843         mono_coop_mutex_init_recursive (&reference_queue_mutex);
844
845         mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.minor_gc_count);
846         mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.major_gc_count);
847         mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time);
848         mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time);
849         mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent);
850
851         mono_gc_base_init ();
852
853         if (mono_gc_is_disabled ()) {
854                 gc_disabled = TRUE;
855                 return;
856         }
857
858         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
859         g_assert (pending_done_event);
860         mono_coop_cond_init (&exited_cond);
861         mono_coop_sem_init (&finalizer_sem, 0);
862
863 #ifndef LAZY_GC_THREAD_CREATION
864         mono_gc_init_finalizer_thread ();
865 #endif
866 }
867
868 void
869 mono_gc_cleanup (void)
870 {
871 #ifdef DEBUG
872         g_message ("%s: cleaning up finalizer", __func__);
873 #endif
874
875         if (mono_gc_is_null ())
876                 return;
877
878         if (!gc_disabled) {
879                 finished = TRUE;
880                 if (mono_thread_internal_current () != gc_thread) {
881                         gboolean timed_out = FALSE;
882                         gint64 start_ticks = mono_msec_ticks ();
883                         gint64 end_ticks = start_ticks + 2000;
884
885                         mono_gc_finalize_notify ();
886                         /* Finishing the finalizer thread, so wait a little bit... */
887                         /* MS seems to wait for about 2 seconds */
888                         while (!finalizer_thread_exited) {
889                                 gint64 current_ticks = mono_msec_ticks ();
890                                 guint32 timeout;
891
892                                 if (current_ticks >= end_ticks)
893                                         break;
894                                 else
895                                         timeout = end_ticks - current_ticks;
896                                 mono_finalizer_lock ();
897                                 if (!finalizer_thread_exited)
898                                         mono_coop_cond_timedwait (&exited_cond, &finalizer_mutex, timeout);
899                                 mono_finalizer_unlock ();
900                         }
901
902                         if (!finalizer_thread_exited) {
903                                 int ret;
904
905                                 /* Set a flag which the finalizer thread can check */
906                                 suspend_finalizers = TRUE;
907
908                                 /* Try to abort the thread, in the hope that it is running managed code */
909                                 mono_thread_internal_stop (gc_thread);
910
911                                 /* Wait for it to stop */
912                                 ret = guarded_wait (gc_thread->handle, 100, TRUE);
913
914                                 if (ret == WAIT_TIMEOUT) {
915                                         /* 
916                                          * The finalizer thread refused to die. There is not much we 
917                                          * can do here, since the runtime is shutting down so the 
918                                          * state the finalizer thread depends on will vanish.
919                                          */
920                                         g_warning ("Shutting down finalizer thread timed out.");
921                                         timed_out = TRUE;
922                                 }
923                         }
924
925                         if (!timed_out) {
926                                 int ret;
927
928                                 /* Wait for the thread to actually exit */
929                                 ret = guarded_wait (gc_thread->handle, INFINITE, TRUE);
930                                 g_assert (ret == WAIT_OBJECT_0);
931
932                                 mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
933                         }
934                         g_assert (finalizer_thread_exited);
935                 }
936                 gc_thread = NULL;
937                 mono_gc_base_cleanup ();
938         }
939
940         mono_reference_queue_cleanup ();
941
942         mono_coop_mutex_destroy (&finalizer_mutex);
943         mono_coop_mutex_destroy (&reference_queue_mutex);
944 }
945
946 gboolean
947 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
948 {
949         return thread == gc_thread;
950 }
951
952 /**
953  * mono_gc_is_finalizer_thread:
954  * @thread: the thread to test.
955  *
956  * In Mono objects are finalized asynchronously on a separate thread.
957  * This routine tests whether the @thread argument represents the
958  * finalization thread.
959  * 
960  * Returns: TRUE if @thread is the finalization thread.
961  */
962 gboolean
963 mono_gc_is_finalizer_thread (MonoThread *thread)
964 {
965         return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
966 }
967
968 #if defined(__MACH__)
969 static pthread_t mach_exception_thread;
970
971 void
972 mono_gc_register_mach_exception_thread (pthread_t thread)
973 {
974         mach_exception_thread = thread;
975 }
976
977 pthread_t
978 mono_gc_get_mach_exception_thread (void)
979 {
980         return mach_exception_thread;
981 }
982 #endif
983
984 static MonoReferenceQueue *ref_queues;
985
986 static void
987 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
988 {
989         do {
990                 /* Guard if head is changed concurrently. */
991                 while (*prev != element)
992                         prev = &(*prev)->next;
993         } while (prev && InterlockedCompareExchangePointer ((volatile gpointer *)prev, element->next, element) != element);
994 }
995
996 static void
997 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
998 {
999         RefQueueEntry *current;
1000         do {
1001                 current = *head;
1002                 value->next = current;
1003                 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1004         } while (InterlockedCompareExchangePointer ((volatile gpointer *)head, value, current) != current);
1005 }
1006
1007 static void
1008 reference_queue_proccess (MonoReferenceQueue *queue)
1009 {
1010         RefQueueEntry **iter = &queue->queue;
1011         RefQueueEntry *entry;
1012         while ((entry = *iter)) {
1013                 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1014                         mono_gchandle_free ((guint32)entry->gchandle);
1015                         ref_list_remove_element (iter, entry);
1016                         queue->callback (entry->user_data);
1017                         g_free (entry);
1018                 } else {
1019                         iter = &entry->next;
1020                 }
1021         }
1022 }
1023
1024 static void
1025 reference_queue_proccess_all (void)
1026 {
1027         MonoReferenceQueue **iter;
1028         MonoReferenceQueue *queue = ref_queues;
1029         for (; queue; queue = queue->next)
1030                 reference_queue_proccess (queue);
1031
1032 restart:
1033         mono_coop_mutex_lock (&reference_queue_mutex);
1034         for (iter = &ref_queues; *iter;) {
1035                 queue = *iter;
1036                 if (!queue->should_be_deleted) {
1037                         iter = &queue->next;
1038                         continue;
1039                 }
1040                 if (queue->queue) {
1041                         mono_coop_mutex_unlock (&reference_queue_mutex);
1042                         reference_queue_proccess (queue);
1043                         goto restart;
1044                 }
1045                 *iter = queue->next;
1046                 g_free (queue);
1047         }
1048         mono_coop_mutex_unlock (&reference_queue_mutex);
1049 }
1050
1051 static void
1052 mono_reference_queue_cleanup (void)
1053 {
1054         MonoReferenceQueue *queue = ref_queues;
1055         for (; queue; queue = queue->next)
1056                 queue->should_be_deleted = TRUE;
1057         reference_queue_proccess_all ();
1058 }
1059
1060 static void
1061 reference_queue_clear_for_domain (MonoDomain *domain)
1062 {
1063         MonoReferenceQueue *queue = ref_queues;
1064         for (; queue; queue = queue->next) {
1065                 RefQueueEntry **iter = &queue->queue;
1066                 RefQueueEntry *entry;
1067                 while ((entry = *iter)) {
1068                         if (entry->domain == domain) {
1069                                 mono_gchandle_free ((guint32)entry->gchandle);
1070                                 ref_list_remove_element (iter, entry);
1071                                 queue->callback (entry->user_data);
1072                                 g_free (entry);
1073                         } else {
1074                                 iter = &entry->next;
1075                         }
1076                 }
1077         }
1078 }
1079 /**
1080  * mono_gc_reference_queue_new:
1081  * @callback callback used when processing collected entries.
1082  *
1083  * Create a new reference queue used to process collected objects.
1084  * A reference queue let you add a pair of (managed object, user data)
1085  * using the mono_gc_reference_queue_add method.
1086  *
1087  * Once the managed object is collected @callback will be called
1088  * in the finalizer thread with 'user data' as argument.
1089  *
1090  * The callback is called from the finalizer thread without any locks held.
1091  * When a AppDomain is unloaded, all callbacks for objects belonging to it
1092  * will be invoked.
1093  *
1094  * @returns the new queue.
1095  */
1096 MonoReferenceQueue*
1097 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1098 {
1099         MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1100         res->callback = callback;
1101
1102         mono_coop_mutex_lock (&reference_queue_mutex);
1103         res->next = ref_queues;
1104         ref_queues = res;
1105         mono_coop_mutex_unlock (&reference_queue_mutex);
1106
1107         return res;
1108 }
1109
1110 /**
1111  * mono_gc_reference_queue_add:
1112  * @queue the queue to add the reference to.
1113  * @obj the object to be watched for collection
1114  * @user_data parameter to be passed to the queue callback
1115  *
1116  * Queue an object to be watched for collection, when the @obj is
1117  * collected, the callback that was registered for the @queue will
1118  * be invoked with @user_data as argument.
1119  *
1120  * @returns false if the queue is scheduled to be freed.
1121  */
1122 gboolean
1123 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1124 {
1125         MonoError error;
1126         RefQueueEntry *entry;
1127         if (queue->should_be_deleted)
1128                 return FALSE;
1129
1130         entry = g_new0 (RefQueueEntry, 1);
1131         entry->user_data = user_data;
1132         entry->domain = mono_object_domain (obj);
1133
1134         entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1135         mono_object_register_finalizer (obj, &error);
1136         mono_error_assert_ok (&error);
1137
1138         ref_list_push (&queue->queue, entry);
1139         return TRUE;
1140 }
1141
1142 /**
1143  * mono_gc_reference_queue_free:
1144  * @queue the queue that should be freed.
1145  *
1146  * This operation signals that @queue should be freed. This operation is deferred
1147  * as it happens on the finalizer thread.
1148  *
1149  * After this call, no further objects can be queued. It's the responsibility of the
1150  * caller to make sure that no further attempt to access queue will be made.
1151  */
1152 void
1153 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1154 {
1155         queue->should_be_deleted = TRUE;
1156 }