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