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