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