2 * metadata/gc.c: GC icalls.
4 * Author: Paolo Molaro <lupus@ximian.com>
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)
16 #include <mono/metadata/gc-internal.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/threadpool.h>
27 #include <mono/metadata/threadpool-internals.h>
28 #include <mono/metadata/threads-types.h>
29 #include <mono/utils/mono-logger-internal.h>
30 #include <mono/metadata/gc-internal.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-semaphore.h>
35 #include <mono/utils/mono-memory-model.h>
36 #include <mono/utils/mono-counters.h>
37 #include <mono/utils/dtrace.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/atomic.h>
45 typedef struct DomainFinalizationReq {
48 } DomainFinalizationReq;
50 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
51 extern void (*__imp_GC_finalizer_notifier)(void);
52 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
53 extern int __imp_GC_finalize_on_demand;
54 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
57 static gboolean gc_disabled = FALSE;
59 static gboolean finalizing_root_domain = FALSE;
61 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
62 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
63 static CRITICAL_SECTION finalizer_mutex;
64 static CRITICAL_SECTION reference_queue_mutex;
66 static GSList *domains_to_finalize= NULL;
67 static MonoMList *threads_to_finalize = NULL;
69 static MonoInternalThread *gc_thread;
71 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
73 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
75 static void reference_queue_proccess_all (void);
76 static void mono_reference_queue_cleanup (void);
77 static void reference_queue_clear_for_domain (MonoDomain *domain);
79 static HANDLE pending_done_event;
80 static HANDLE shutdown_event;
86 add_thread_to_finalize (MonoInternalThread *thread)
88 mono_finalizer_lock ();
89 if (!threads_to_finalize)
90 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
91 threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
92 mono_finalizer_unlock ();
95 static gboolean suspend_finalizers = FALSE;
97 * actually, we might want to queue the finalize requests in a separate thread,
98 * but we need to be careful about the execution domain of the thread...
101 mono_gc_run_finalize (void *obj, void *data)
103 MonoObject *exc = NULL;
108 MonoMethod* finalizer = NULL;
109 MonoDomain *caller_domain = mono_domain_get ();
111 RuntimeInvokeFunction runtime_invoke;
113 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
115 if (suspend_finalizers)
118 domain = o->vtable->domain;
121 mono_domain_finalizers_lock (domain);
123 o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
125 mono_domain_finalizers_unlock (domain);
128 /* Already finalized somehow */
132 /* make sure the finalizer is not called again if the object is resurrected */
133 object_register_finalizer (obj, NULL);
135 if (o->vtable->klass == mono_defaults.internal_thread_class) {
136 MonoInternalThread *t = (MonoInternalThread*)o;
138 if (mono_gc_is_finalizer_internal_thread (t))
139 /* Avoid finalizing ourselves */
142 if (t->threadpool_thread && finalizing_root_domain) {
143 /* Don't finalize threadpool threads when
144 shutting down - they're finalized when the
145 threadpool shuts down. */
146 add_thread_to_finalize (t);
151 if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
153 * These can't be finalized during unloading/shutdown, since that would
154 * free the native code which can still be referenced by other
156 * FIXME: This is not perfect, objects dying at the same time as
157 * dynamic methods can still reference them even when !shutdown.
162 if (mono_runtime_get_no_exec ())
165 /* speedup later... and use a timeout */
166 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
168 /* Use _internal here, since this thread can enter a doomed appdomain */
169 mono_domain_set_internal (mono_object_domain (o));
171 /* delegates that have a native function pointer allocated are
172 * registered for finalization, but they don't have a Finalize
173 * method, because in most cases it's not needed and it's just a waste.
175 if (o->vtable->klass->delegate) {
176 MonoDelegate* del = (MonoDelegate*)o;
177 if (del->delegate_trampoline)
178 mono_delegate_free_ftnptr ((MonoDelegate*)o);
179 mono_domain_set_internal (caller_domain);
183 finalizer = mono_class_get_finalizer (o->vtable->klass);
186 /* If object has a CCW but has no finalizer, it was only
187 * registered for finalization in order to free the CCW.
188 * Else it needs the regular finalizer run.
189 * FIXME: what to do about ressurection and suppression
190 * of finalizer on object with CCW.
192 if (mono_marshal_free_ccw (o) && !finalizer) {
193 mono_domain_set_internal (caller_domain);
199 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
200 * create and precompile a wrapper which calls the finalize method using
203 if (!domain->finalize_runtime_invoke) {
204 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
206 domain->finalize_runtime_invoke = mono_compile_method (invoke);
209 runtime_invoke = domain->finalize_runtime_invoke;
211 mono_runtime_class_init (o->vtable);
213 if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
214 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
215 o->vtable->klass->name_space, o->vtable->klass->name);
218 runtime_invoke (o, NULL, &exc, NULL);
221 mono_internal_thread_unhandled_exception (exc);
223 mono_domain_set_internal (caller_domain);
227 mono_gc_finalize_threadpool_threads (void)
229 while (threads_to_finalize) {
230 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
232 /* Force finalization of the thread. */
233 thread->threadpool_thread = FALSE;
234 mono_object_register_finalizer ((MonoObject*)thread);
236 mono_gc_run_finalize (thread, NULL);
238 threads_to_finalize = mono_mlist_next (threads_to_finalize);
243 mono_gc_out_of_memory (size_t size)
246 * we could allocate at program startup some memory that we could release
247 * back to the system at this point if we're really low on memory (ie, size is
248 * lower than the memory we set apart)
250 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
256 * Some of our objects may point to a different address than the address returned by GC_malloc()
257 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
258 * This also means that in the callback we need to adjust the pointer to get back the real
260 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
261 * since that, too, can cause the underlying pointer to be offset.
264 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
271 mono_raise_exception (mono_get_exception_argument_null ("obj"));
273 domain = obj->vtable->domain;
276 /* This assertion is not valid when GC_DEBUG is defined */
277 g_assert (GC_base (obj) == (char*)obj - offset);
280 if (mono_domain_is_unloading (domain) && (callback != NULL))
282 * Can't register finalizers in a dying appdomain, since they
283 * could be invoked after the appdomain has been unloaded.
287 mono_domain_finalizers_lock (domain);
290 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
292 g_hash_table_remove (domain->finalizable_objects_hash, obj);
294 mono_domain_finalizers_unlock (domain);
296 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
297 #elif defined(HAVE_SGEN_GC)
299 mono_raise_exception (mono_get_exception_argument_null ("obj"));
302 * If we register finalizers for domains that are unloading we might
303 * end up running them while or after the domain is being cleared, so
304 * the objects will not be valid anymore.
306 if (!mono_domain_is_unloading (obj->vtable->domain))
307 mono_gc_register_for_finalization (obj, callback);
312 * mono_object_register_finalizer:
313 * @obj: object to register
315 * Records that object @obj has a finalizer, this will call the
316 * Finalize method when the garbage collector disposes the object.
320 mono_object_register_finalizer (MonoObject *obj)
322 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
323 object_register_finalizer (obj, mono_gc_run_finalize);
327 * mono_domain_finalize:
328 * @domain: the domain to finalize
329 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
331 * Request finalization of all finalizable objects inside @domain. Wait
332 * @timeout msecs for the finalization to complete.
334 * Returns: TRUE if succeeded, FALSE if there was a timeout
338 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
340 DomainFinalizationReq *req;
343 MonoInternalThread *thread = mono_thread_internal_current ();
345 if (mono_thread_internal_current () == gc_thread)
346 /* We are called from inside a finalizer, not much we can do here */
350 * No need to create another thread 'cause the finalizer thread
351 * is still working and will take care of running the finalizers
358 mono_gc_collect (mono_gc_max_generation ());
360 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
361 if (done_event == NULL) {
365 req = g_new0 (DomainFinalizationReq, 1);
366 req->domain = domain;
367 req->done_event = done_event;
369 if (domain == mono_get_root_domain ())
370 finalizing_root_domain = TRUE;
372 mono_finalizer_lock ();
374 domains_to_finalize = g_slist_append (domains_to_finalize, req);
376 mono_finalizer_unlock ();
378 /* Tell the finalizer thread to finalize this appdomain */
379 mono_gc_finalize_notify ();
385 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
386 /* printf ("WAIT RES: %d.\n", res); */
388 if (res == WAIT_IO_COMPLETION) {
389 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
391 } else if (res == WAIT_TIMEOUT) {
392 /* We leak the handle here */
399 CloseHandle (done_event);
401 if (domain == mono_get_root_domain ()) {
402 mono_thread_pool_cleanup ();
403 mono_gc_finalize_threadpool_threads ();
408 /* We don't support domain finalization without a GC */
414 ves_icall_System_GC_InternalCollect (int generation)
416 mono_gc_collect (generation);
420 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
425 mono_gc_collect (mono_gc_max_generation ());
426 return mono_gc_get_used_size ();
430 ves_icall_System_GC_KeepAlive (MonoObject *obj)
440 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
443 mono_raise_exception (mono_get_exception_argument_null ("obj"));
445 object_register_finalizer (obj, mono_gc_run_finalize);
449 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
452 mono_raise_exception (mono_get_exception_argument_null ("obj"));
454 /* delegates have no finalizers, but we register them to deal with the
455 * unmanaged->managed trampoline. We don't let the user suppress it
456 * otherwise we'd leak it.
458 if (obj->vtable->klass->delegate)
461 /* FIXME: Need to handle case where obj has COM Callable Wrapper
462 * generated for it that needs cleaned up, but user wants to suppress
463 * their derived object finalizer. */
465 object_register_finalizer (obj, NULL);
469 ves_icall_System_GC_WaitForPendingFinalizers (void)
472 if (!mono_gc_pending_finalizers ())
475 if (mono_thread_internal_current () == gc_thread)
476 /* Avoid deadlocks */
480 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
481 be the one responsible for starting it up.
483 if (gc_thread == NULL)
486 ResetEvent (pending_done_event);
487 mono_gc_finalize_notify ();
488 /* g_print ("Waiting for pending finalizers....\n"); */
489 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
490 /* g_print ("Done pending....\n"); */
495 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
498 if (!mono_gc_ephemeron_array_add (array))
499 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
504 ves_icall_System_GC_get_ephemeron_tombstone (void)
506 return mono_domain_get ()->ephemeron_tombstone;
509 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
510 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
511 static CRITICAL_SECTION allocator_section;
512 static CRITICAL_SECTION handle_section;
521 static HandleType mono_gchandle_get_type (guint32 gchandle);
524 ves_icall_System_GCHandle_GetTarget (guint32 handle)
526 return mono_gchandle_get_target (handle);
530 * if type == -1, change the target of the handle, otherwise allocate a new handle.
533 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
536 mono_gchandle_set_target (handle, obj);
537 /* the handle doesn't change */
542 return mono_gchandle_new_weakref (obj, FALSE);
543 case HANDLE_WEAK_TRACK:
544 return mono_gchandle_new_weakref (obj, TRUE);
546 return mono_gchandle_new (obj, FALSE);
548 return mono_gchandle_new (obj, TRUE);
550 g_assert_not_reached ();
556 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
558 mono_gchandle_free (handle);
562 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
566 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
568 obj = mono_gchandle_get_target (handle);
570 MonoClass *klass = mono_object_class (obj);
571 if (klass == mono_defaults.string_class) {
572 return mono_string_chars ((MonoString*)obj);
573 } else if (klass->rank) {
574 return mono_array_addr ((MonoArray*)obj, char, 0);
576 /* the C# code will check and throw the exception */
577 /* FIXME: missing !klass->blittable test, see bug #61134 */
578 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
580 return (char*)obj + sizeof (MonoObject);
587 ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
589 return mono_gc_set_allow_synchronous_major (flag);
597 guint slot_hint : 24; /* starting slot for search */
598 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
599 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
603 /* weak and weak-track arrays will be allocated in malloc memory
605 static HandleData gc_handles [] = {
606 {NULL, NULL, 0, HANDLE_WEAK, 0},
607 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
608 {NULL, NULL, 0, HANDLE_NORMAL, 0},
609 {NULL, NULL, 0, HANDLE_PINNED, 0}
612 #define lock_handles(handles) EnterCriticalSection (&handle_section)
613 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
616 find_first_unset (guint32 bitmap)
619 for (i = 0; i < 32; ++i) {
620 if (!(bitmap & (1 << i)))
627 make_root_descr_all_refs (int numbits, gboolean pinned)
633 return mono_gc_make_root_descr_all_refs (numbits);
637 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
641 lock_handles (handles);
642 if (!handles->size) {
644 if (handles->type > HANDLE_WEAK_TRACK) {
645 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
647 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
648 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
650 handles->bitmap = g_malloc0 (handles->size / 8);
653 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
654 if (handles->bitmap [slot] != 0xffffffff) {
655 i = find_first_unset (handles->bitmap [slot]);
656 handles->slot_hint = slot;
660 if (i == -1 && handles->slot_hint != 0) {
661 for (slot = 0; slot < handles->slot_hint; ++slot) {
662 if (handles->bitmap [slot] != 0xffffffff) {
663 i = find_first_unset (handles->bitmap [slot]);
664 handles->slot_hint = slot;
671 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
673 /* resize and copy the bitmap */
674 new_bitmap = g_malloc0 (new_size / 8);
675 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
676 g_free (handles->bitmap);
677 handles->bitmap = new_bitmap;
679 /* resize and copy the entries */
680 if (handles->type > HANDLE_WEAK_TRACK) {
683 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
684 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
686 mono_gc_free_fixed (handles->entries);
687 handles->entries = entries;
691 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
692 entries = g_malloc0 (sizeof (gpointer) * new_size);
693 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
694 for (i = 0; i < handles->size; ++i) {
695 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
697 mono_gc_weak_link_add (&(entries [i]), obj, track);
698 mono_gc_weak_link_remove (&(handles->entries [i]), track);
700 g_assert (!handles->entries [i]);
703 g_free (handles->entries);
704 g_free (handles->domain_ids);
705 handles->entries = entries;
706 handles->domain_ids = domain_ids;
709 /* set i and slot to the next free position */
711 slot = (handles->size + 1) / 32;
712 handles->slot_hint = handles->size + 1;
713 handles->size = new_size;
715 handles->bitmap [slot] |= 1 << i;
716 slot = slot * 32 + i;
717 handles->entries [slot] = NULL;
718 if (handles->type <= HANDLE_WEAK_TRACK) {
719 /*FIXME, what to use when obj == null?*/
720 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
722 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
724 handles->entries [slot] = obj;
727 #ifndef DISABLE_PERFCOUNTERS
728 mono_perfcounters->gc_num_handles++;
730 unlock_handles (handles);
731 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
732 res = (slot << 3) | (handles->type + 1);
733 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
739 * @obj: managed object to get a handle for
740 * @pinned: whether the object should be pinned
742 * This returns a handle that wraps the object, this is used to keep a
743 * reference to a managed object from the unmanaged world and preventing the
744 * object from being disposed.
746 * If @pinned is false the address of the object can not be obtained, if it is
747 * true the address of the object can be obtained. This will also pin the
748 * object so it will not be possible by a moving garbage collector to move the
751 * Returns: a handle that can be used to access the object from
755 mono_gchandle_new (MonoObject *obj, gboolean pinned)
757 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
761 * mono_gchandle_new_weakref:
762 * @obj: managed object to get a handle for
763 * @pinned: whether the object should be pinned
765 * This returns a weak handle that wraps the object, this is used to
766 * keep a reference to a managed object from the unmanaged world.
767 * Unlike the mono_gchandle_new the object can be reclaimed by the
768 * garbage collector. In this case the value of the GCHandle will be
771 * If @pinned is false the address of the object can not be obtained, if it is
772 * true the address of the object can be obtained. This will also pin the
773 * object so it will not be possible by a moving garbage collector to move the
776 * Returns: a handle that can be used to access the object from
780 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
782 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
788 mono_gchandle_get_type (guint32 gchandle)
790 guint type = (gchandle & 7) - 1;
796 * mono_gchandle_get_target:
797 * @gchandle: a GCHandle's handle.
799 * The handle was previously created by calling mono_gchandle_new or
800 * mono_gchandle_new_weakref.
802 * Returns a pointer to the MonoObject represented by the handle or
803 * NULL for a collected object if using a weakref handle.
806 mono_gchandle_get_target (guint32 gchandle)
808 guint slot = gchandle >> 3;
809 guint type = (gchandle & 7) - 1;
810 HandleData *handles = &gc_handles [type];
811 MonoObject *obj = NULL;
814 lock_handles (handles);
815 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
816 if (handles->type <= HANDLE_WEAK_TRACK) {
817 obj = mono_gc_weak_link_get (&handles->entries [slot]);
819 obj = handles->entries [slot];
822 /* print a warning? */
824 unlock_handles (handles);
825 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
830 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
832 guint slot = gchandle >> 3;
833 guint type = (gchandle & 7) - 1;
834 HandleData *handles = &gc_handles [type];
835 MonoObject *old_obj = NULL;
839 lock_handles (handles);
840 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
841 if (handles->type <= HANDLE_WEAK_TRACK) {
842 old_obj = handles->entries [slot];
843 if (handles->entries [slot])
844 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
846 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
847 /*FIXME, what to use when obj == null?*/
848 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
850 handles->entries [slot] = obj;
853 /* print a warning? */
855 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
856 unlock_handles (handles);
860 * mono_gchandle_is_in_domain:
861 * @gchandle: a GCHandle's handle.
862 * @domain: An application domain.
864 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
867 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
869 guint slot = gchandle >> 3;
870 guint type = (gchandle & 7) - 1;
871 HandleData *handles = &gc_handles [type];
872 gboolean result = FALSE;
875 lock_handles (handles);
876 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
877 if (handles->type <= HANDLE_WEAK_TRACK) {
878 result = domain->domain_id == handles->domain_ids [slot];
881 obj = handles->entries [slot];
885 result = domain == mono_object_domain (obj);
888 /* print a warning? */
890 unlock_handles (handles);
895 * mono_gchandle_free:
896 * @gchandle: a GCHandle's handle.
898 * Frees the @gchandle handle. If there are no outstanding
899 * references, the garbage collector can reclaim the memory of the
903 mono_gchandle_free (guint32 gchandle)
905 guint slot = gchandle >> 3;
906 guint type = (gchandle & 7) - 1;
907 HandleData *handles = &gc_handles [type];
911 lock_handles (handles);
912 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
913 if (handles->type <= HANDLE_WEAK_TRACK) {
914 if (handles->entries [slot])
915 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
917 handles->entries [slot] = NULL;
919 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
921 /* print a warning? */
923 #ifndef DISABLE_PERFCOUNTERS
924 mono_perfcounters->gc_num_handles--;
926 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
927 unlock_handles (handles);
928 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
932 * mono_gchandle_free_domain:
933 * @domain: domain that is unloading
935 * Function used internally to cleanup any GC handle for objects belonging
936 * to the specified domain during appdomain unload.
939 mono_gchandle_free_domain (MonoDomain *domain)
943 for (type = 0; type < 3; ++type) {
945 HandleData *handles = &gc_handles [type];
946 lock_handles (handles);
947 for (slot = 0; slot < handles->size; ++slot) {
948 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
950 if (type <= HANDLE_WEAK_TRACK) {
951 if (domain->domain_id == handles->domain_ids [slot]) {
952 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
953 if (handles->entries [slot])
954 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
957 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
958 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
959 handles->entries [slot] = NULL;
963 unlock_handles (handles);
969 GCHandle_CheckCurrentDomain (guint32 gchandle)
971 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
976 #ifdef MONO_HAS_SEMAPHORES
977 static MonoSemType finalizer_sem;
979 static HANDLE finalizer_event;
980 static volatile gboolean finished=FALSE;
983 mono_gc_finalize_notify (void)
986 g_message ( "%s: prodding finalizer", __func__);
989 #ifdef MONO_HAS_SEMAPHORES
990 MONO_SEM_POST (&finalizer_sem);
992 SetEvent (finalizer_event);
999 collect_objects (gpointer key, gpointer value, gpointer user_data)
1001 GPtrArray *arr = (GPtrArray*)user_data;
1002 g_ptr_array_add (arr, key);
1008 * finalize_domain_objects:
1010 * Run the finalizers of all finalizable objects in req->domain.
1013 finalize_domain_objects (DomainFinalizationReq *req)
1015 MonoDomain *domain = req->domain;
1018 #define NUM_FOBJECTS 64
1019 MonoObject *to_finalize [NUM_FOBJECTS];
1023 /* Process finalizers which are already in the queue */
1024 mono_gc_invoke_finalizers ();
1026 #ifdef HAVE_BOEHM_GC
1027 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1031 * Since the domain is unloading, nobody is allowed to put
1032 * new entries into the hash table. But finalize_object might
1033 * remove entries from the hash table, so we make a copy.
1035 objs = g_ptr_array_new ();
1036 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1037 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1039 for (i = 0; i < objs->len; ++i) {
1040 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1041 /* FIXME: Avoid finalizing threads, etc */
1042 mono_gc_run_finalize (o, 0);
1045 g_ptr_array_free (objs, TRUE);
1047 #elif defined(HAVE_SGEN_GC)
1048 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1050 for (i = 0; i < count; ++i) {
1051 mono_gc_run_finalize (to_finalize [i], 0);
1056 /* cleanup the reference queue */
1057 reference_queue_clear_for_domain (domain);
1059 /* printf ("DONE.\n"); */
1060 SetEvent (req->done_event);
1062 /* The event is closed in mono_domain_finalize if we get here */
1067 finalizer_thread (gpointer unused)
1070 /* Wait to be notified that there's at least one
1074 g_assert (mono_domain_get () == mono_get_root_domain ());
1076 /* An alertable wait is required so this thread can be suspended on windows */
1077 #ifdef MONO_HAS_SEMAPHORES
1078 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1080 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1083 mono_threads_perform_thread_dump ();
1085 mono_console_handle_async_ops ();
1087 #ifndef DISABLE_ATTACH
1088 mono_attach_maybe_start ();
1091 if (domains_to_finalize) {
1092 mono_finalizer_lock ();
1093 if (domains_to_finalize) {
1094 DomainFinalizationReq *req = domains_to_finalize->data;
1095 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1096 mono_finalizer_unlock ();
1098 finalize_domain_objects (req);
1100 mono_finalizer_unlock ();
1104 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1105 * before the domain is unloaded.
1107 mono_gc_invoke_finalizers ();
1109 reference_queue_proccess_all ();
1111 SetEvent (pending_done_event);
1114 SetEvent (shutdown_event);
1118 #ifndef LAZY_GC_THREAD_CREATION
1122 mono_gc_init_finalizer_thread (void)
1124 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
1125 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1131 InitializeCriticalSection (&handle_section);
1132 InitializeCriticalSection (&allocator_section);
1134 InitializeCriticalSection (&finalizer_mutex);
1135 InitializeCriticalSection (&reference_queue_mutex);
1137 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1138 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1140 mono_counters_register ("Created object count", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &mono_stats.new_object_count);
1141 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1142 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1143 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1144 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1146 mono_gc_base_init ();
1148 if (mono_gc_is_disabled ()) {
1153 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1154 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1155 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1156 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1157 g_assert_not_reached ();
1159 #ifdef MONO_HAS_SEMAPHORES
1160 MONO_SEM_INIT (&finalizer_sem, 0);
1163 #ifndef LAZY_GC_THREAD_CREATION
1164 mono_gc_init_finalizer_thread ();
1169 mono_gc_cleanup (void)
1172 g_message ("%s: cleaning up finalizer", __func__);
1176 ResetEvent (shutdown_event);
1178 if (mono_thread_internal_current () != gc_thread) {
1179 mono_gc_finalize_notify ();
1180 /* Finishing the finalizer thread, so wait a little bit... */
1181 /* MS seems to wait for about 2 seconds */
1182 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1185 /* Set a flag which the finalizer thread can check */
1186 suspend_finalizers = TRUE;
1188 /* Try to abort the thread, in the hope that it is running managed code */
1189 mono_thread_internal_stop (gc_thread);
1191 /* Wait for it to stop */
1192 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1194 if (ret == WAIT_TIMEOUT) {
1196 * The finalizer thread refused to die. There is not much we
1197 * can do here, since the runtime is shutting down so the
1198 * state the finalizer thread depends on will vanish.
1200 g_warning ("Shutting down finalizer thread timed out.");
1203 * FIXME: On unix, when the above wait returns, the thread
1204 * might still be running io-layer code, or pthreads code.
1211 /* Wait for the thread to actually exit */
1212 ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
1213 g_assert (ret == WAIT_OBJECT_0);
1217 * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
1218 * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
1220 ret = pthread_join ((MonoNativeThreadId)(gpointer)(gsize)gc_thread->tid, NULL);
1221 g_assert (ret == 0);
1226 #ifdef HAVE_BOEHM_GC
1227 GC_finalizer_notifier = NULL;
1231 mono_reference_queue_cleanup ();
1233 DeleteCriticalSection (&handle_section);
1234 DeleteCriticalSection (&allocator_section);
1235 DeleteCriticalSection (&finalizer_mutex);
1236 DeleteCriticalSection (&reference_queue_mutex);
1241 /* Null GC dummy functions */
1243 mono_gc_finalize_notify (void)
1247 void mono_gc_init (void)
1249 InitializeCriticalSection (&handle_section);
1252 void mono_gc_cleanup (void)
1259 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1261 return thread == gc_thread;
1265 * mono_gc_is_finalizer_thread:
1266 * @thread: the thread to test.
1268 * In Mono objects are finalized asynchronously on a separate thread.
1269 * This routine tests whether the @thread argument represents the
1270 * finalization thread.
1272 * Returns true if @thread is the finalization thread.
1275 mono_gc_is_finalizer_thread (MonoThread *thread)
1277 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1280 #if defined(__MACH__)
1281 static pthread_t mach_exception_thread;
1284 mono_gc_register_mach_exception_thread (pthread_t thread)
1286 mach_exception_thread = thread;
1290 mono_gc_get_mach_exception_thread (void)
1292 return mach_exception_thread;
1297 * mono_gc_parse_environment_string_extract_number:
1299 * @str: points to the first digit of the number
1300 * @out: pointer to the variable that will receive the value
1302 * Tries to extract a number from the passed string, taking in to account m, k
1305 * Returns true if passing was successful
1308 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1311 int len = strlen (str), shift = 0;
1313 gboolean is_suffix = FALSE;
1319 suffix = str [len - 1];
1334 if (!isdigit (suffix))
1340 val = strtol (str, &endptr, 10);
1342 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1343 || (errno != 0 && val == 0) || (endptr == str))
1349 if (val < 0) /* negative numbers cannot be suffixed */
1351 if (*(endptr + 1)) /* Invalid string. */
1354 unshifted = (gulong)val;
1356 if (val < 0) /* overflow */
1358 if (((gulong)val >> shift) != unshifted) /* value too large */
1366 #ifndef HAVE_SGEN_GC
1368 mono_gc_alloc_mature (MonoVTable *vtable)
1370 return mono_object_new_specific (vtable);
1375 static MonoReferenceQueue *ref_queues;
1378 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1381 /* Guard if head is changed concurrently. */
1382 while (*prev != element)
1383 prev = &(*prev)->next;
1384 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1388 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1390 RefQueueEntry *current;
1393 value->next = current;
1394 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1395 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1399 reference_queue_proccess (MonoReferenceQueue *queue)
1401 RefQueueEntry **iter = &queue->queue;
1402 RefQueueEntry *entry;
1403 while ((entry = *iter)) {
1405 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1406 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1408 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1409 mono_gchandle_free ((guint32)entry->gchandle);
1411 ref_list_remove_element (iter, entry);
1412 queue->callback (entry->user_data);
1415 iter = &entry->next;
1421 reference_queue_proccess_all (void)
1423 MonoReferenceQueue **iter;
1424 MonoReferenceQueue *queue = ref_queues;
1425 for (; queue; queue = queue->next)
1426 reference_queue_proccess (queue);
1429 EnterCriticalSection (&reference_queue_mutex);
1430 for (iter = &ref_queues; *iter;) {
1432 if (!queue->should_be_deleted) {
1433 iter = &queue->next;
1437 LeaveCriticalSection (&reference_queue_mutex);
1438 reference_queue_proccess (queue);
1441 *iter = queue->next;
1444 LeaveCriticalSection (&reference_queue_mutex);
1448 mono_reference_queue_cleanup (void)
1450 MonoReferenceQueue *queue = ref_queues;
1451 for (; queue; queue = queue->next)
1452 queue->should_be_deleted = TRUE;
1453 reference_queue_proccess_all ();
1457 reference_queue_clear_for_domain (MonoDomain *domain)
1459 MonoReferenceQueue *queue = ref_queues;
1460 for (; queue; queue = queue->next) {
1461 RefQueueEntry **iter = &queue->queue;
1462 RefQueueEntry *entry;
1463 while ((entry = *iter)) {
1466 obj = mono_gc_weak_link_get (&entry->dis_link);
1467 if (obj && mono_object_domain (obj) == domain) {
1468 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1470 obj = mono_gchandle_get_target (entry->gchandle);
1471 if (obj && mono_object_domain (obj) == domain) {
1472 mono_gchandle_free ((guint32)entry->gchandle);
1474 ref_list_remove_element (iter, entry);
1475 queue->callback (entry->user_data);
1478 iter = &entry->next;
1484 * mono_gc_reference_queue_new:
1485 * @callback callback used when processing dead entries.
1487 * Create a new reference queue used to process collected objects.
1488 * A reference queue let you queue a pair (managed object, user data)
1489 * using the mono_gc_reference_queue_add method.
1491 * Once the managed object is collected @callback will be called
1492 * in the finalizer thread with 'user data' as argument.
1494 * The callback is called without any locks held.
1497 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1499 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1500 res->callback = callback;
1502 EnterCriticalSection (&reference_queue_mutex);
1503 res->next = ref_queues;
1505 LeaveCriticalSection (&reference_queue_mutex);
1511 * mono_gc_reference_queue_add:
1512 * @queue the queue to add the reference to.
1513 * @obj the object to be watched for collection
1514 * @user_data parameter to be passed to the queue callback
1516 * Queue an object to be watched for collection, when the @obj is
1517 * collected, the callback that was registered for the @queue will
1518 * be invoked with the @obj and @user_data arguments.
1520 * @returns false if the queue is scheduled to be freed.
1523 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1525 RefQueueEntry *entry;
1526 if (queue->should_be_deleted)
1529 entry = g_new0 (RefQueueEntry, 1);
1530 entry->user_data = user_data;
1533 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1535 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1536 mono_object_register_finalizer (obj);
1539 ref_list_push (&queue->queue, entry);
1544 * mono_gc_reference_queue_free:
1545 * @queue the queue that should be deleted.
1547 * This operation signals that @queue should be deleted. This operation is deferred
1548 * as it happens on the finalizer thread.
1550 * After this call, no further objects can be queued. It's the responsibility of the
1551 * caller to make sure that no further attempt to access queue will be made.
1554 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1556 queue->should_be_deleted = TRUE;
1559 #define ptr_mask ((sizeof (void*) - 1))
1560 #define _toi(ptr) ((size_t)ptr)
1561 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1562 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1563 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1565 #define BZERO_WORDS(dest,words) do { \
1567 for (__i = 0; __i < (words); ++__i) \
1568 ((void **)(dest))[__i] = 0; \
1573 * @dest: address to start to clear
1574 * @size: size of the region to clear
1576 * Zero @size bytes starting at @dest.
1578 * Use this to zero memory that can hold managed pointers.
1580 * FIXME borrow faster code from some BSD libc or bionic
1583 mono_gc_bzero (void *dest, size_t size)
1585 char *d = (char*)dest;
1586 size_t tail_bytes, word_bytes;
1589 If we're copying less than a word, just use memset.
1591 We cannot bail out early if both are aligned because some implementations
1592 use byte copying for sizes smaller than 16. OSX, on this case.
1594 if (size < sizeof(void*)) {
1595 memset (dest, 0, size);
1599 /*align to word boundary */
1600 while (unaligned_bytes (d) && size) {
1605 /* copy all words with memmove */
1606 word_bytes = (size_t)align_down (size);
1607 switch (word_bytes) {
1608 case sizeof (void*) * 1:
1611 case sizeof (void*) * 2:
1614 case sizeof (void*) * 3:
1617 case sizeof (void*) * 4:
1621 memset (d, 0, word_bytes);
1624 tail_bytes = unaligned_bytes (size);
1629 } while (--tail_bytes);
1635 * @dest: destination of the move
1637 * @size: size of the block to move
1639 * Move @size bytes from @src to @dest.
1640 * size MUST be a multiple of sizeof (gpointer)
1644 mono_gc_memmove (void *dest, const void *src, size_t size)
1647 If we're copying less than a word we don't need to worry about word tearing
1648 so we bailout to memmove early.
1650 If both dest is aligned and size is a multiple of word size, we can go straigh
1654 if (size < sizeof(void*) || !((_toi (dest) | (size)) & sizeof (void*))) {
1655 memmove (dest, src, size);
1660 * A bit of explanation on why we align only dest before doing word copies.
1661 * Pointers to managed objects must always be stored in word aligned addresses, so
1662 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1664 * We don't need to case when source and destination have different alignments since we only do word stores
1665 * using memmove, which must handle it.
1667 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
1668 char *p = (char*)dest + size;
1669 char *s = (char*)src + size;
1670 char *start = (char*)dest;
1671 char *align_end = MAX((char*)dest, (char*)align_down (p));
1673 size_t bytes_to_memmove;
1675 while (p > align_end)
1678 word_start = align_up (start);
1679 bytes_to_memmove = p - word_start;
1680 p -= bytes_to_memmove;
1681 s -= bytes_to_memmove;
1682 memmove (p, s, bytes_to_memmove);
1687 char *d = (char*)dest;
1688 const char *s = (const char*)src;
1691 /*align to word boundary */
1692 while (unaligned_bytes (d)) {
1697 /* copy all words with memmove */
1698 memmove (d, s, (size_t)align_down (size));
1700 tail_bytes = unaligned_bytes (size);
1702 d += (size_t)align_down (size);
1703 s += (size_t)align_down (size);
1706 } while (--tail_bytes);