Merge pull request #4782 from lambdageek/dev-mono_string_new-excise
[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         MonoString *finalizer = mono_string_new_checked (mono_get_root_domain (), "Finalizer", &error);
849         mono_error_assert_ok (&error);
850         mono_thread_set_name_internal (mono_thread_internal_current (), finalizer, FALSE, FALSE, &error);
851         mono_error_assert_ok (&error);
852
853         /* Register a hazard free queue pump callback */
854         mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);
855
856         while (!finished) {
857                 /* Wait to be notified that there's at least one
858                  * finaliser to run
859                  */
860
861                 g_assert (mono_domain_get () == mono_get_root_domain ());
862                 mono_gc_set_skip_thread (TRUE);
863
864                 if (wait) {
865                         /* An alertable wait is required so this thread can be suspended on windows */
866                         mono_coop_sem_wait (&finalizer_sem, MONO_SEM_FLAGS_ALERTABLE);
867                 }
868                 wait = TRUE;
869
870                 mono_gc_set_skip_thread (FALSE);
871
872                 mono_threads_perform_thread_dump ();
873
874                 mono_console_handle_async_ops ();
875
876                 mono_attach_maybe_start ();
877
878                 finalize_domain_objects ();
879
880                 mono_profiler_gc_finalize_begin ();
881
882                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
883                  * before the domain is unloaded.
884                  */
885                 mono_gc_invoke_finalizers ();
886
887                 mono_profiler_gc_finalize_end ();
888
889                 mono_threads_join_threads ();
890
891                 reference_queue_proccess_all ();
892
893                 hazard_free_queue_pump ();
894
895                 /* Avoid posting the pending done event until there are pending finalizers */
896                 if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == MONO_SEM_TIMEDWAIT_RET_SUCCESS) {
897                         /* Don't wait again at the start of the loop */
898                         wait = FALSE;
899                 } else {
900 #ifdef TARGET_WIN32
901                         SetEvent (pending_done_event);
902 #else
903                         mono_coop_mutex_lock (&pending_done_mutex);
904                         pending_done = TRUE;
905                         mono_coop_cond_signal (&pending_done_cond);
906                         mono_coop_mutex_unlock (&pending_done_mutex);
907 #endif
908                 }
909         }
910
911         mono_finalizer_lock ();
912         finalizer_thread_exited = TRUE;
913         mono_coop_cond_signal (&exited_cond);
914         mono_finalizer_unlock ();
915
916         return 0;
917 }
918
919 #ifndef LAZY_GC_THREAD_CREATION
920 static
921 #endif
922 void
923 mono_gc_init_finalizer_thread (void)
924 {
925         MonoError error;
926         gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
927         mono_error_assert_ok (&error);
928 }
929
930 void
931 mono_gc_init (void)
932 {
933         mono_coop_mutex_init_recursive (&finalizer_mutex);
934         mono_coop_mutex_init_recursive (&reference_queue_mutex);
935
936         mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.minor_gc_count);
937         mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.major_gc_count);
938         mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time);
939         mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time);
940         mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent);
941
942         mono_gc_base_init ();
943
944         if (mono_gc_is_disabled ()) {
945                 gc_disabled = TRUE;
946                 return;
947         }
948
949 #ifdef TARGET_WIN32
950         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
951         g_assert (pending_done_event);
952 #else
953         mono_coop_cond_init (&pending_done_cond);
954         mono_coop_mutex_init (&pending_done_mutex);
955 #endif
956
957         mono_coop_cond_init (&exited_cond);
958         mono_coop_sem_init (&finalizer_sem, 0);
959
960 #ifndef LAZY_GC_THREAD_CREATION
961         mono_gc_init_finalizer_thread ();
962 #endif
963 }
964
965 void
966 mono_gc_cleanup (void)
967 {
968 #ifdef DEBUG
969         g_message ("%s: cleaning up finalizer", __func__);
970 #endif
971
972         if (mono_gc_is_null ())
973                 return;
974
975         if (!gc_disabled) {
976                 finished = TRUE;
977                 if (mono_thread_internal_current () != gc_thread) {
978                         int ret;
979                         gint64 start;
980                         const gint64 timeout = 40 * 1000;
981
982                         mono_gc_finalize_notify ();
983
984                         start = mono_msec_ticks ();
985
986                         /* Finishing the finalizer thread, so wait a little bit... */
987                         /* MS seems to wait for about 2 seconds per finalizer thread */
988                         /* and 40 seconds for all finalizers to finish */
989                         for (;;) {
990                                 gint64 elapsed;
991
992                                 if (finalizer_thread_exited) {
993                                         /* Wait for the thread to actually exit. We don't want the wait
994                                          * to be alertable, because we assert on the result to be SUCCESS_0 */
995                                         ret = guarded_wait (gc_thread->handle, MONO_INFINITE_WAIT, FALSE);
996                                         g_assert (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0);
997
998                                         mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
999                                         break;
1000                                 }
1001
1002                                 elapsed = mono_msec_ticks () - start;
1003                                 if (elapsed >= timeout) {
1004                                         /* timeout */
1005
1006                                         /* Set a flag which the finalizer thread can check */
1007                                         suspend_finalizers = TRUE;
1008                                         mono_gc_suspend_finalizers ();
1009
1010                                         /* Try to abort the thread, in the hope that it is running managed code */
1011                                         mono_thread_internal_abort (gc_thread);
1012
1013                                         /* Wait for it to stop */
1014                                         ret = guarded_wait (gc_thread->handle, 100, FALSE);
1015                                         if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT) {
1016                                                 /* The finalizer thread refused to exit, suspend it forever. */
1017                                                 mono_thread_internal_suspend_for_shutdown (gc_thread);
1018                                                 break;
1019                                         }
1020
1021                                         g_assert (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0);
1022
1023                                         mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
1024                                         break;
1025                                 }
1026
1027                                 mono_finalizer_lock ();
1028                                 if (!finalizer_thread_exited)
1029                                         mono_coop_cond_timedwait (&exited_cond, &finalizer_mutex, timeout - elapsed);
1030                                 mono_finalizer_unlock ();
1031                         }
1032                 }
1033                 gc_thread = NULL;
1034                 mono_gc_base_cleanup ();
1035         }
1036
1037         mono_reference_queue_cleanup ();
1038
1039         mono_coop_mutex_destroy (&finalizer_mutex);
1040         mono_coop_mutex_destroy (&reference_queue_mutex);
1041 }
1042
1043 gboolean
1044 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1045 {
1046         return thread == gc_thread;
1047 }
1048
1049 /**
1050  * mono_gc_is_finalizer_thread:
1051  * \param thread the thread to test.
1052  *
1053  * In Mono objects are finalized asynchronously on a separate thread.
1054  * This routine tests whether the \p thread argument represents the
1055  * finalization thread.
1056  * 
1057  * \returns TRUE if \p thread is the finalization thread.
1058  */
1059 gboolean
1060 mono_gc_is_finalizer_thread (MonoThread *thread)
1061 {
1062         return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1063 }
1064
1065 #if defined(__MACH__)
1066 static pthread_t mach_exception_thread;
1067
1068 void
1069 mono_gc_register_mach_exception_thread (pthread_t thread)
1070 {
1071         mach_exception_thread = thread;
1072 }
1073
1074 pthread_t
1075 mono_gc_get_mach_exception_thread (void)
1076 {
1077         return mach_exception_thread;
1078 }
1079 #endif
1080
1081 static MonoReferenceQueue *ref_queues;
1082
1083 static void
1084 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1085 {
1086         do {
1087                 /* Guard if head is changed concurrently. */
1088                 while (*prev != element)
1089                         prev = &(*prev)->next;
1090         } while (prev && InterlockedCompareExchangePointer ((volatile gpointer *)prev, element->next, element) != element);
1091 }
1092
1093 static void
1094 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1095 {
1096         RefQueueEntry *current;
1097         do {
1098                 current = *head;
1099                 value->next = current;
1100                 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1101         } while (InterlockedCompareExchangePointer ((volatile gpointer *)head, value, current) != current);
1102 }
1103
1104 static void
1105 reference_queue_proccess (MonoReferenceQueue *queue)
1106 {
1107         RefQueueEntry **iter = &queue->queue;
1108         RefQueueEntry *entry;
1109         while ((entry = *iter)) {
1110                 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1111                         mono_gchandle_free ((guint32)entry->gchandle);
1112                         ref_list_remove_element (iter, entry);
1113                         queue->callback (entry->user_data);
1114                         g_free (entry);
1115                 } else {
1116                         iter = &entry->next;
1117                 }
1118         }
1119 }
1120
1121 static void
1122 reference_queue_proccess_all (void)
1123 {
1124         MonoReferenceQueue **iter;
1125         MonoReferenceQueue *queue = ref_queues;
1126         for (; queue; queue = queue->next)
1127                 reference_queue_proccess (queue);
1128
1129 restart:
1130         mono_coop_mutex_lock (&reference_queue_mutex);
1131         for (iter = &ref_queues; *iter;) {
1132                 queue = *iter;
1133                 if (!queue->should_be_deleted) {
1134                         iter = &queue->next;
1135                         continue;
1136                 }
1137                 if (queue->queue) {
1138                         mono_coop_mutex_unlock (&reference_queue_mutex);
1139                         reference_queue_proccess (queue);
1140                         goto restart;
1141                 }
1142                 *iter = queue->next;
1143                 g_free (queue);
1144         }
1145         mono_coop_mutex_unlock (&reference_queue_mutex);
1146 }
1147
1148 static void
1149 mono_reference_queue_cleanup (void)
1150 {
1151         MonoReferenceQueue *queue = ref_queues;
1152         for (; queue; queue = queue->next)
1153                 queue->should_be_deleted = TRUE;
1154         reference_queue_proccess_all ();
1155 }
1156
1157 static void
1158 reference_queue_clear_for_domain (MonoDomain *domain)
1159 {
1160         MonoReferenceQueue *queue = ref_queues;
1161         for (; queue; queue = queue->next) {
1162                 RefQueueEntry **iter = &queue->queue;
1163                 RefQueueEntry *entry;
1164                 while ((entry = *iter)) {
1165                         if (entry->domain == domain) {
1166                                 mono_gchandle_free ((guint32)entry->gchandle);
1167                                 ref_list_remove_element (iter, entry);
1168                                 queue->callback (entry->user_data);
1169                                 g_free (entry);
1170                         } else {
1171                                 iter = &entry->next;
1172                         }
1173                 }
1174         }
1175 }
1176 /**
1177  * mono_gc_reference_queue_new:
1178  * \param callback callback used when processing collected entries.
1179  *
1180  * Create a new reference queue used to process collected objects.
1181  * A reference queue let you add a pair of (managed object, user data)
1182  * using the \c mono_gc_reference_queue_add method.
1183  *
1184  * Once the managed object is collected \p callback will be called
1185  * in the finalizer thread with 'user data' as argument.
1186  *
1187  * The callback is called from the finalizer thread without any locks held.
1188  * When an AppDomain is unloaded, all callbacks for objects belonging to it
1189  * will be invoked.
1190  *
1191  * \returns the new queue.
1192  */
1193 MonoReferenceQueue*
1194 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1195 {
1196         MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1197         res->callback = callback;
1198
1199         mono_coop_mutex_lock (&reference_queue_mutex);
1200         res->next = ref_queues;
1201         ref_queues = res;
1202         mono_coop_mutex_unlock (&reference_queue_mutex);
1203
1204         return res;
1205 }
1206
1207 /**
1208  * mono_gc_reference_queue_add:
1209  * \param queue the queue to add the reference to.
1210  * \param obj the object to be watched for collection
1211  * \param user_data parameter to be passed to the queue callback
1212  *
1213  * Queue an object to be watched for collection, when the \p obj is
1214  * collected, the callback that was registered for the \p queue will
1215  * be invoked with \p user_data as argument.
1216  *
1217  * \returns FALSE if the queue is scheduled to be freed.
1218  */
1219 gboolean
1220 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1221 {
1222         RefQueueEntry *entry;
1223         if (queue->should_be_deleted)
1224                 return FALSE;
1225
1226         g_assert (obj != NULL);
1227
1228         entry = g_new0 (RefQueueEntry, 1);
1229         entry->user_data = user_data;
1230         entry->domain = mono_object_domain (obj);
1231
1232         entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1233         mono_object_register_finalizer (obj);
1234
1235         ref_list_push (&queue->queue, entry);
1236         return TRUE;
1237 }
1238
1239 /**
1240  * mono_gc_reference_queue_free:
1241  * \param queue the queue that should be freed.
1242  *
1243  * This operation signals that \p queue should be freed. This operation is deferred
1244  * as it happens on the finalizer thread.
1245  *
1246  * After this call, no further objects can be queued. It's the responsibility of the
1247  * caller to make sure that no further attempt to access queue will be made.
1248  */
1249 void
1250 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1251 {
1252         queue->should_be_deleted = TRUE;
1253 }