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