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