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