Merge pull request #2802 from BrzVlad/feature-evacuation-opt2
[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         return TRUE;
457 }
458
459 void
460 ves_icall_System_GC_InternalCollect (int generation)
461 {
462         mono_gc_collect (generation);
463 }
464
465 gint64
466 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
467 {
468         if (forceCollection)
469                 mono_gc_collect (mono_gc_max_generation ());
470         return mono_gc_get_used_size ();
471 }
472
473 void
474 ves_icall_System_GC_KeepAlive (MonoObject *obj)
475 {
476         /*
477          * Does nothing.
478          */
479 }
480
481 void
482 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
483 {
484         MonoError error;
485
486         MONO_CHECK_ARG_NULL (obj,);
487
488         object_register_finalizer (obj, mono_gc_run_finalize, &error);
489         mono_error_set_pending_exception (&error);
490 }
491
492 void
493 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
494 {
495         MonoError error;
496
497         MONO_CHECK_ARG_NULL (obj,);
498
499         /* delegates have no finalizers, but we register them to deal with the
500          * unmanaged->managed trampoline. We don't let the user suppress it
501          * otherwise we'd leak it.
502          */
503         if (obj->vtable->klass->delegate)
504                 return;
505
506         /* FIXME: Need to handle case where obj has COM Callable Wrapper
507          * generated for it that needs cleaned up, but user wants to suppress
508          * their derived object finalizer. */
509
510         object_register_finalizer (obj, NULL, &error);
511         mono_error_set_pending_exception (&error);
512 }
513
514 void
515 ves_icall_System_GC_WaitForPendingFinalizers (void)
516 {
517         if (mono_gc_is_null ())
518                 return;
519
520         if (!mono_gc_pending_finalizers ())
521                 return;
522
523         if (mono_thread_internal_current () == gc_thread)
524                 /* Avoid deadlocks */
525                 return;
526
527         /*
528         If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
529         be the one responsible for starting it up.
530         */
531         if (gc_thread == NULL)
532                 return;
533
534         ResetEvent (pending_done_event);
535         mono_gc_finalize_notify ();
536         /* g_print ("Waiting for pending finalizers....\n"); */
537         guarded_wait (pending_done_event, INFINITE, TRUE);
538         /* g_print ("Done pending....\n"); */
539 }
540
541 void
542 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
543 {
544 #ifdef HAVE_SGEN_GC
545         if (!mono_gc_ephemeron_array_add (array)) {
546                 mono_set_pending_exception (mono_object_domain (array)->out_of_memory_ex);
547                 return;
548         }
549 #endif
550 }
551
552 MonoObject*
553 ves_icall_System_GC_get_ephemeron_tombstone (void)
554 {
555         return mono_domain_get ()->ephemeron_tombstone;
556 }
557
558 MonoObject *
559 ves_icall_System_GCHandle_GetTarget (guint32 handle)
560 {
561         return mono_gchandle_get_target (handle);
562 }
563
564 /*
565  * if type == -1, change the target of the handle, otherwise allocate a new handle.
566  */
567 guint32
568 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
569 {
570         if (type == -1) {
571                 mono_gchandle_set_target (handle, obj);
572                 /* the handle doesn't change */
573                 return handle;
574         }
575         switch (type) {
576         case HANDLE_WEAK:
577                 return mono_gchandle_new_weakref (obj, FALSE);
578         case HANDLE_WEAK_TRACK:
579                 return mono_gchandle_new_weakref (obj, TRUE);
580         case HANDLE_NORMAL:
581                 return mono_gchandle_new (obj, FALSE);
582         case HANDLE_PINNED:
583                 return mono_gchandle_new (obj, TRUE);
584         default:
585                 g_assert_not_reached ();
586         }
587         return 0;
588 }
589
590 void
591 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
592 {
593         mono_gchandle_free (handle);
594 }
595
596 gpointer
597 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
598 {
599         MonoObject *obj;
600
601         if (MONO_GC_HANDLE_TYPE (handle) != HANDLE_PINNED)
602                 return (gpointer)-2;
603         obj = mono_gchandle_get_target (handle);
604         if (obj) {
605                 MonoClass *klass = mono_object_class (obj);
606                 if (klass == mono_defaults.string_class) {
607                         return mono_string_chars ((MonoString*)obj);
608                 } else if (klass->rank) {
609                         return mono_array_addr ((MonoArray*)obj, char, 0);
610                 } else {
611                         /* the C# code will check and throw the exception */
612                         /* FIXME: missing !klass->blittable test, see bug #61134 */
613                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
614                                 return (gpointer)-1;
615                         return (char*)obj + sizeof (MonoObject);
616                 }
617         }
618         return NULL;
619 }
620
621 MonoBoolean
622 mono_gc_GCHandle_CheckCurrentDomain (guint32 gchandle)
623 {
624         return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
625 }
626
627 static MonoCoopSem finalizer_sem;
628 static volatile gboolean finished=FALSE;
629
630 void
631 mono_gc_finalize_notify (void)
632 {
633 #ifdef DEBUG
634         g_message ( "%s: prodding finalizer", __func__);
635 #endif
636
637         if (mono_gc_is_null ())
638                 return;
639
640         mono_coop_sem_post (&finalizer_sem);
641 }
642
643 /*
644 This is the number of entries allowed in the hazard free queue before
645 we explicitly cycle the finalizer thread to trigger pumping the queue.
646
647 It was picked empirically by running the corlib test suite in a stress
648 scenario where all hazard entries are queued.
649
650 In this extreme scenario we double the number of times we cycle the finalizer
651 thread compared to just GC calls.
652
653 Entries are usually in the order of 100's of bytes each, so we're limiting
654 floating garbage to be in the order of a dozen kb.
655 */
656 static gboolean finalizer_thread_pulsed;
657 #define HAZARD_QUEUE_OVERFLOW_SIZE 20
658
659 static void
660 hazard_free_queue_is_too_big (size_t size)
661 {
662         if (size < HAZARD_QUEUE_OVERFLOW_SIZE)
663                 return;
664
665         if (finalizer_thread_pulsed || InterlockedCompareExchange (&finalizer_thread_pulsed, TRUE, FALSE))
666                 return;
667
668         mono_gc_finalize_notify ();
669 }
670
671 static void
672 hazard_free_queue_pump (void)
673 {
674         mono_thread_hazardous_try_free_all ();
675         finalizer_thread_pulsed = FALSE;
676 }
677
678 #ifdef HAVE_BOEHM_GC
679
680 static void
681 collect_objects (gpointer key, gpointer value, gpointer user_data)
682 {
683         GPtrArray *arr = (GPtrArray*)user_data;
684         g_ptr_array_add (arr, key);
685 }
686
687 #endif
688
689 /*
690  * finalize_domain_objects:
691  *
692  *  Run the finalizers of all finalizable objects in req->domain.
693  */
694 static void
695 finalize_domain_objects (DomainFinalizationReq *req)
696 {
697         MonoDomain *domain = req->domain;
698
699 #if HAVE_SGEN_GC
700 #define NUM_FOBJECTS 64
701         MonoObject *to_finalize [NUM_FOBJECTS];
702         int count;
703 #endif
704
705         /* Process finalizers which are already in the queue */
706         mono_gc_invoke_finalizers ();
707
708 #ifdef HAVE_BOEHM_GC
709         while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
710                 int i;
711                 GPtrArray *objs;
712                 /* 
713                  * Since the domain is unloading, nobody is allowed to put
714                  * new entries into the hash table. But finalize_object might
715                  * remove entries from the hash table, so we make a copy.
716                  */
717                 objs = g_ptr_array_new ();
718                 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
719                 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
720
721                 for (i = 0; i < objs->len; ++i) {
722                         MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
723                         /* FIXME: Avoid finalizing threads, etc */
724                         mono_gc_run_finalize (o, 0);
725                 }
726
727                 g_ptr_array_free (objs, TRUE);
728         }
729 #elif defined(HAVE_SGEN_GC)
730         while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
731                 int i;
732                 for (i = 0; i < count; ++i) {
733                         mono_gc_run_finalize (to_finalize [i], 0);
734                 }
735         }
736 #endif
737
738         /* cleanup the reference queue */
739         reference_queue_clear_for_domain (domain);
740         
741         /* printf ("DONE.\n"); */
742         SetEvent (req->done_event);
743
744         /* The event is closed in mono_domain_finalize if we get here */
745         g_free (req);
746 }
747
748 static guint32
749 finalizer_thread (gpointer unused)
750 {
751         MonoError error;
752         mono_thread_set_name_internal (mono_thread_internal_current (), mono_string_new (mono_get_root_domain (), "Finalizer"), FALSE, &error);
753         mono_error_assert_ok (&error);
754
755         gboolean wait = TRUE;
756
757         /* Register a hazard free queue pump callback */
758         mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);
759
760         while (!finished) {
761                 /* Wait to be notified that there's at least one
762                  * finaliser to run
763                  */
764
765                 g_assert (mono_domain_get () == mono_get_root_domain ());
766                 mono_gc_set_skip_thread (TRUE);
767
768                 if (wait) {
769                         /* An alertable wait is required so this thread can be suspended on windows */
770                         mono_coop_sem_wait (&finalizer_sem, MONO_SEM_FLAGS_ALERTABLE);
771                 }
772                 wait = TRUE;
773
774                 mono_gc_set_skip_thread (FALSE);
775
776                 mono_threads_perform_thread_dump ();
777
778                 mono_console_handle_async_ops ();
779
780                 mono_attach_maybe_start ();
781
782                 if (domains_to_finalize) {
783                         mono_finalizer_lock ();
784                         if (domains_to_finalize) {
785                                 DomainFinalizationReq *req = (DomainFinalizationReq *)domains_to_finalize->data;
786                                 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
787                                 mono_finalizer_unlock ();
788
789                                 finalize_domain_objects (req);
790                         } else {
791                                 mono_finalizer_unlock ();
792                         }
793                 }                               
794
795                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
796                  * before the domain is unloaded.
797                  */
798                 mono_gc_invoke_finalizers ();
799
800                 mono_threads_join_threads ();
801
802                 reference_queue_proccess_all ();
803
804                 hazard_free_queue_pump ();
805
806                 /* Avoid posting the pending done event until there are pending finalizers */
807                 if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == 0) {
808                         /* Don't wait again at the start of the loop */
809                         wait = FALSE;
810                 } else {
811                         SetEvent (pending_done_event);
812                 }
813         }
814
815         mono_finalizer_lock ();
816         finalizer_thread_exited = TRUE;
817         mono_coop_cond_signal (&exited_cond);
818         mono_finalizer_unlock ();
819
820         return 0;
821 }
822
823 #ifndef LAZY_GC_THREAD_CREATION
824 static
825 #endif
826 void
827 mono_gc_init_finalizer_thread (void)
828 {
829         gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
830 }
831
832 void
833 mono_gc_init (void)
834 {
835         mono_coop_mutex_init_recursive (&finalizer_mutex);
836         mono_coop_mutex_init_recursive (&reference_queue_mutex);
837
838         mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.minor_gc_count);
839         mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.major_gc_count);
840         mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time);
841         mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time);
842         mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent);
843
844         mono_gc_base_init ();
845
846         if (mono_gc_is_disabled ()) {
847                 gc_disabled = TRUE;
848                 return;
849         }
850
851         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
852         g_assert (pending_done_event);
853         mono_coop_cond_init (&exited_cond);
854         mono_coop_sem_init (&finalizer_sem, 0);
855
856 #ifndef LAZY_GC_THREAD_CREATION
857         mono_gc_init_finalizer_thread ();
858 #endif
859 }
860
861 void
862 mono_gc_cleanup (void)
863 {
864 #ifdef DEBUG
865         g_message ("%s: cleaning up finalizer", __func__);
866 #endif
867
868         if (mono_gc_is_null ())
869                 return;
870
871         if (!gc_disabled) {
872                 finished = TRUE;
873                 if (mono_thread_internal_current () != gc_thread) {
874                         gboolean timed_out = FALSE;
875                         guint32 start_ticks = mono_msec_ticks ();
876                         guint32 end_ticks = start_ticks + 2000;
877
878                         mono_gc_finalize_notify ();
879                         /* Finishing the finalizer thread, so wait a little bit... */
880                         /* MS seems to wait for about 2 seconds */
881                         while (!finalizer_thread_exited) {
882                                 guint32 current_ticks = mono_msec_ticks ();
883                                 guint32 timeout;
884
885                                 if (current_ticks >= end_ticks)
886                                         break;
887                                 else
888                                         timeout = end_ticks - current_ticks;
889                                 mono_finalizer_lock ();
890                                 if (!finalizer_thread_exited)
891                                         mono_coop_cond_timedwait (&exited_cond, &finalizer_mutex, timeout);
892                                 mono_finalizer_unlock ();
893                         }
894
895                         if (!finalizer_thread_exited) {
896                                 int ret;
897
898                                 /* Set a flag which the finalizer thread can check */
899                                 suspend_finalizers = TRUE;
900
901                                 /* Try to abort the thread, in the hope that it is running managed code */
902                                 mono_thread_internal_stop (gc_thread);
903
904                                 /* Wait for it to stop */
905                                 ret = guarded_wait (gc_thread->handle, 100, TRUE);
906
907                                 if (ret == WAIT_TIMEOUT) {
908                                         /* 
909                                          * The finalizer thread refused to die. There is not much we 
910                                          * can do here, since the runtime is shutting down so the 
911                                          * state the finalizer thread depends on will vanish.
912                                          */
913                                         g_warning ("Shutting down finalizer thread timed out.");
914                                         timed_out = TRUE;
915                                 }
916                         }
917
918                         if (!timed_out) {
919                                 int ret;
920
921                                 /* Wait for the thread to actually exit */
922                                 ret = guarded_wait (gc_thread->handle, INFINITE, TRUE);
923                                 g_assert (ret == WAIT_OBJECT_0);
924
925                                 mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
926                         }
927                         g_assert (finalizer_thread_exited);
928                 }
929                 gc_thread = NULL;
930                 mono_gc_base_cleanup ();
931         }
932
933         mono_reference_queue_cleanup ();
934
935         mono_coop_mutex_destroy (&finalizer_mutex);
936         mono_coop_mutex_destroy (&reference_queue_mutex);
937 }
938
939 gboolean
940 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
941 {
942         return thread == gc_thread;
943 }
944
945 /**
946  * mono_gc_is_finalizer_thread:
947  * @thread: the thread to test.
948  *
949  * In Mono objects are finalized asynchronously on a separate thread.
950  * This routine tests whether the @thread argument represents the
951  * finalization thread.
952  * 
953  * Returns: TRUE if @thread is the finalization thread.
954  */
955 gboolean
956 mono_gc_is_finalizer_thread (MonoThread *thread)
957 {
958         return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
959 }
960
961 #if defined(__MACH__)
962 static pthread_t mach_exception_thread;
963
964 void
965 mono_gc_register_mach_exception_thread (pthread_t thread)
966 {
967         mach_exception_thread = thread;
968 }
969
970 pthread_t
971 mono_gc_get_mach_exception_thread (void)
972 {
973         return mach_exception_thread;
974 }
975 #endif
976
977 static MonoReferenceQueue *ref_queues;
978
979 static void
980 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
981 {
982         do {
983                 /* Guard if head is changed concurrently. */
984                 while (*prev != element)
985                         prev = &(*prev)->next;
986         } while (prev && InterlockedCompareExchangePointer ((volatile gpointer *)prev, element->next, element) != element);
987 }
988
989 static void
990 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
991 {
992         RefQueueEntry *current;
993         do {
994                 current = *head;
995                 value->next = current;
996                 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
997         } while (InterlockedCompareExchangePointer ((volatile gpointer *)head, value, current) != current);
998 }
999
1000 static void
1001 reference_queue_proccess (MonoReferenceQueue *queue)
1002 {
1003         RefQueueEntry **iter = &queue->queue;
1004         RefQueueEntry *entry;
1005         while ((entry = *iter)) {
1006                 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1007                         mono_gchandle_free ((guint32)entry->gchandle);
1008                         ref_list_remove_element (iter, entry);
1009                         queue->callback (entry->user_data);
1010                         g_free (entry);
1011                 } else {
1012                         iter = &entry->next;
1013                 }
1014         }
1015 }
1016
1017 static void
1018 reference_queue_proccess_all (void)
1019 {
1020         MonoReferenceQueue **iter;
1021         MonoReferenceQueue *queue = ref_queues;
1022         for (; queue; queue = queue->next)
1023                 reference_queue_proccess (queue);
1024
1025 restart:
1026         mono_coop_mutex_lock (&reference_queue_mutex);
1027         for (iter = &ref_queues; *iter;) {
1028                 queue = *iter;
1029                 if (!queue->should_be_deleted) {
1030                         iter = &queue->next;
1031                         continue;
1032                 }
1033                 if (queue->queue) {
1034                         mono_coop_mutex_unlock (&reference_queue_mutex);
1035                         reference_queue_proccess (queue);
1036                         goto restart;
1037                 }
1038                 *iter = queue->next;
1039                 g_free (queue);
1040         }
1041         mono_coop_mutex_unlock (&reference_queue_mutex);
1042 }
1043
1044 static void
1045 mono_reference_queue_cleanup (void)
1046 {
1047         MonoReferenceQueue *queue = ref_queues;
1048         for (; queue; queue = queue->next)
1049                 queue->should_be_deleted = TRUE;
1050         reference_queue_proccess_all ();
1051 }
1052
1053 static void
1054 reference_queue_clear_for_domain (MonoDomain *domain)
1055 {
1056         MonoReferenceQueue *queue = ref_queues;
1057         for (; queue; queue = queue->next) {
1058                 RefQueueEntry **iter = &queue->queue;
1059                 RefQueueEntry *entry;
1060                 while ((entry = *iter)) {
1061                         if (entry->domain == domain) {
1062                                 mono_gchandle_free ((guint32)entry->gchandle);
1063                                 ref_list_remove_element (iter, entry);
1064                                 queue->callback (entry->user_data);
1065                                 g_free (entry);
1066                         } else {
1067                                 iter = &entry->next;
1068                         }
1069                 }
1070         }
1071 }
1072 /**
1073  * mono_gc_reference_queue_new:
1074  * @callback callback used when processing collected entries.
1075  *
1076  * Create a new reference queue used to process collected objects.
1077  * A reference queue let you add a pair of (managed object, user data)
1078  * using the mono_gc_reference_queue_add method.
1079  *
1080  * Once the managed object is collected @callback will be called
1081  * in the finalizer thread with 'user data' as argument.
1082  *
1083  * The callback is called from the finalizer thread without any locks held.
1084  * When a AppDomain is unloaded, all callbacks for objects belonging to it
1085  * will be invoked.
1086  *
1087  * @returns the new queue.
1088  */
1089 MonoReferenceQueue*
1090 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1091 {
1092         MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1093         res->callback = callback;
1094
1095         mono_coop_mutex_lock (&reference_queue_mutex);
1096         res->next = ref_queues;
1097         ref_queues = res;
1098         mono_coop_mutex_unlock (&reference_queue_mutex);
1099
1100         return res;
1101 }
1102
1103 /**
1104  * mono_gc_reference_queue_add:
1105  * @queue the queue to add the reference to.
1106  * @obj the object to be watched for collection
1107  * @user_data parameter to be passed to the queue callback
1108  *
1109  * Queue an object to be watched for collection, when the @obj is
1110  * collected, the callback that was registered for the @queue will
1111  * be invoked with @user_data as argument.
1112  *
1113  * @returns false if the queue is scheduled to be freed.
1114  */
1115 gboolean
1116 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1117 {
1118         MonoError error;
1119         RefQueueEntry *entry;
1120         if (queue->should_be_deleted)
1121                 return FALSE;
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, &error);
1129         mono_error_assert_ok (&error);
1130
1131         ref_list_push (&queue->queue, entry);
1132         return TRUE;
1133 }
1134
1135 /**
1136  * mono_gc_reference_queue_free:
1137  * @queue the queue that should be freed.
1138  *
1139  * This operation signals that @queue should be freed. This operation is deferred
1140  * as it happens on the finalizer thread.
1141  *
1142  * After this call, no further objects can be queued. It's the responsibility of the
1143  * caller to make sure that no further attempt to access queue will be made.
1144  */
1145 void
1146 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1147 {
1148         queue->should_be_deleted = TRUE;
1149 }