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