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