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