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