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*))
269 mono_raise_exception (mono_get_exception_argument_null ("obj"));
271 domain = obj->vtable->domain;
274 if (mono_domain_is_unloading (domain) && (callback != NULL))
276 * Can't register finalizers in a dying appdomain, since they
277 * could be invoked after the appdomain has been unloaded.
281 mono_domain_finalizers_lock (domain);
284 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
286 g_hash_table_remove (domain->finalizable_objects_hash, obj);
288 mono_domain_finalizers_unlock (domain);
290 mono_gc_register_for_finalization (obj, callback);
291 #elif defined(HAVE_SGEN_GC)
293 * If we register finalizers for domains that are unloading we might
294 * end up running them while or after the domain is being cleared, so
295 * the objects will not be valid anymore.
297 if (!mono_domain_is_unloading (domain))
298 mono_gc_register_for_finalization (obj, callback);
303 * mono_object_register_finalizer:
304 * @obj: object to register
306 * Records that object @obj has a finalizer, this will call the
307 * Finalize method when the garbage collector disposes the object.
311 mono_object_register_finalizer (MonoObject *obj)
313 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
314 object_register_finalizer (obj, mono_gc_run_finalize);
318 * mono_domain_finalize:
319 * @domain: the domain to finalize
320 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
322 * Request finalization of all finalizable objects inside @domain. Wait
323 * @timeout msecs for the finalization to complete.
325 * Returns: TRUE if succeeded, FALSE if there was a timeout
329 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
331 DomainFinalizationReq *req;
334 MonoInternalThread *thread = mono_thread_internal_current ();
336 #if defined(__native_client__)
340 if (mono_thread_internal_current () == gc_thread)
341 /* We are called from inside a finalizer, not much we can do here */
345 * No need to create another thread 'cause the finalizer thread
346 * is still working and will take care of running the finalizers
353 mono_gc_collect (mono_gc_max_generation ());
355 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
356 if (done_event == NULL) {
360 req = g_new0 (DomainFinalizationReq, 1);
361 req->domain = domain;
362 req->done_event = done_event;
364 if (domain == mono_get_root_domain ())
365 finalizing_root_domain = TRUE;
367 mono_finalizer_lock ();
369 domains_to_finalize = g_slist_append (domains_to_finalize, req);
371 mono_finalizer_unlock ();
373 /* Tell the finalizer thread to finalize this appdomain */
374 mono_gc_finalize_notify ();
380 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
381 /* printf ("WAIT RES: %d.\n", res); */
383 if (res == WAIT_IO_COMPLETION) {
384 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
386 } else if (res == WAIT_TIMEOUT) {
387 /* We leak the handle here */
394 CloseHandle (done_event);
396 if (domain == mono_get_root_domain ()) {
397 mono_thread_pool_cleanup ();
398 mono_gc_finalize_threadpool_threads ();
403 /* We don't support domain finalization without a GC */
409 ves_icall_System_GC_InternalCollect (int generation)
411 mono_gc_collect (generation);
415 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
420 mono_gc_collect (mono_gc_max_generation ());
421 return mono_gc_get_used_size ();
425 ves_icall_System_GC_KeepAlive (MonoObject *obj)
435 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
438 mono_raise_exception (mono_get_exception_argument_null ("obj"));
440 object_register_finalizer (obj, mono_gc_run_finalize);
444 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
447 mono_raise_exception (mono_get_exception_argument_null ("obj"));
449 /* delegates have no finalizers, but we register them to deal with the
450 * unmanaged->managed trampoline. We don't let the user suppress it
451 * otherwise we'd leak it.
453 if (obj->vtable->klass->delegate)
456 /* FIXME: Need to handle case where obj has COM Callable Wrapper
457 * generated for it that needs cleaned up, but user wants to suppress
458 * their derived object finalizer. */
460 object_register_finalizer (obj, NULL);
464 ves_icall_System_GC_WaitForPendingFinalizers (void)
467 if (!mono_gc_pending_finalizers ())
470 if (mono_thread_internal_current () == gc_thread)
471 /* Avoid deadlocks */
475 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
476 be the one responsible for starting it up.
478 if (gc_thread == NULL)
481 ResetEvent (pending_done_event);
482 mono_gc_finalize_notify ();
483 /* g_print ("Waiting for pending finalizers....\n"); */
484 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
485 /* g_print ("Done pending....\n"); */
490 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
493 if (!mono_gc_ephemeron_array_add (array))
494 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
499 ves_icall_System_GC_get_ephemeron_tombstone (void)
501 return mono_domain_get ()->ephemeron_tombstone;
504 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
505 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
506 static CRITICAL_SECTION allocator_section;
507 static CRITICAL_SECTION handle_section;
516 static HandleType mono_gchandle_get_type (guint32 gchandle);
519 ves_icall_System_GCHandle_GetTarget (guint32 handle)
521 return mono_gchandle_get_target (handle);
525 * if type == -1, change the target of the handle, otherwise allocate a new handle.
528 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
531 mono_gchandle_set_target (handle, obj);
532 /* the handle doesn't change */
537 return mono_gchandle_new_weakref (obj, FALSE);
538 case HANDLE_WEAK_TRACK:
539 return mono_gchandle_new_weakref (obj, TRUE);
541 return mono_gchandle_new (obj, FALSE);
543 return mono_gchandle_new (obj, TRUE);
545 g_assert_not_reached ();
551 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
553 mono_gchandle_free (handle);
557 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
561 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
563 obj = mono_gchandle_get_target (handle);
565 MonoClass *klass = mono_object_class (obj);
566 if (klass == mono_defaults.string_class) {
567 return mono_string_chars ((MonoString*)obj);
568 } else if (klass->rank) {
569 return mono_array_addr ((MonoArray*)obj, char, 0);
571 /* the C# code will check and throw the exception */
572 /* FIXME: missing !klass->blittable test, see bug #61134 */
573 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
575 return (char*)obj + sizeof (MonoObject);
582 ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
584 return mono_gc_set_allow_synchronous_major (flag);
592 guint slot_hint : 24; /* starting slot for search */
593 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
594 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
598 /* weak and weak-track arrays will be allocated in malloc memory
600 static HandleData gc_handles [] = {
601 {NULL, NULL, 0, HANDLE_WEAK, 0},
602 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
603 {NULL, NULL, 0, HANDLE_NORMAL, 0},
604 {NULL, NULL, 0, HANDLE_PINNED, 0}
607 #define lock_handles(handles) EnterCriticalSection (&handle_section)
608 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
611 find_first_unset (guint32 bitmap)
614 for (i = 0; i < 32; ++i) {
615 if (!(bitmap & (1 << i)))
622 make_root_descr_all_refs (int numbits, gboolean pinned)
628 return mono_gc_make_root_descr_all_refs (numbits);
632 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
636 lock_handles (handles);
637 if (!handles->size) {
639 if (handles->type > HANDLE_WEAK_TRACK) {
640 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
642 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
643 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
645 handles->bitmap = g_malloc0 (handles->size / 8);
648 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
649 if (handles->bitmap [slot] != 0xffffffff) {
650 i = find_first_unset (handles->bitmap [slot]);
651 handles->slot_hint = slot;
655 if (i == -1 && handles->slot_hint != 0) {
656 for (slot = 0; slot < handles->slot_hint; ++slot) {
657 if (handles->bitmap [slot] != 0xffffffff) {
658 i = find_first_unset (handles->bitmap [slot]);
659 handles->slot_hint = slot;
666 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
668 /* resize and copy the bitmap */
669 new_bitmap = g_malloc0 (new_size / 8);
670 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
671 g_free (handles->bitmap);
672 handles->bitmap = new_bitmap;
674 /* resize and copy the entries */
675 if (handles->type > HANDLE_WEAK_TRACK) {
678 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
679 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
681 mono_gc_free_fixed (handles->entries);
682 handles->entries = entries;
686 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
687 entries = g_malloc0 (sizeof (gpointer) * new_size);
688 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
689 for (i = 0; i < handles->size; ++i) {
690 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
692 mono_gc_weak_link_add (&(entries [i]), obj, track);
693 mono_gc_weak_link_remove (&(handles->entries [i]), track);
695 g_assert (!handles->entries [i]);
698 g_free (handles->entries);
699 g_free (handles->domain_ids);
700 handles->entries = entries;
701 handles->domain_ids = domain_ids;
704 /* set i and slot to the next free position */
706 slot = (handles->size + 1) / 32;
707 handles->slot_hint = handles->size + 1;
708 handles->size = new_size;
710 handles->bitmap [slot] |= 1 << i;
711 slot = slot * 32 + i;
712 handles->entries [slot] = NULL;
713 if (handles->type <= HANDLE_WEAK_TRACK) {
714 /*FIXME, what to use when obj == null?*/
715 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
717 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
719 handles->entries [slot] = obj;
722 #ifndef DISABLE_PERFCOUNTERS
723 mono_perfcounters->gc_num_handles++;
725 unlock_handles (handles);
726 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
727 res = (slot << 3) | (handles->type + 1);
728 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
734 * @obj: managed object to get a handle for
735 * @pinned: whether the object should be pinned
737 * This returns a handle that wraps the object, this is used to keep a
738 * reference to a managed object from the unmanaged world and preventing the
739 * object from being disposed.
741 * If @pinned is false the address of the object can not be obtained, if it is
742 * true the address of the object can be obtained. This will also pin the
743 * object so it will not be possible by a moving garbage collector to move the
746 * Returns: a handle that can be used to access the object from
750 mono_gchandle_new (MonoObject *obj, gboolean pinned)
752 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
756 * mono_gchandle_new_weakref:
757 * @obj: managed object to get a handle for
758 * @pinned: whether the object should be pinned
760 * This returns a weak handle that wraps the object, this is used to
761 * keep a reference to a managed object from the unmanaged world.
762 * Unlike the mono_gchandle_new the object can be reclaimed by the
763 * garbage collector. In this case the value of the GCHandle will be
766 * If @pinned is false the address of the object can not be obtained, if it is
767 * true the address of the object can be obtained. This will also pin the
768 * object so it will not be possible by a moving garbage collector to move the
771 * Returns: a handle that can be used to access the object from
775 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
777 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
783 mono_gchandle_get_type (guint32 gchandle)
785 guint type = (gchandle & 7) - 1;
791 * mono_gchandle_get_target:
792 * @gchandle: a GCHandle's handle.
794 * The handle was previously created by calling mono_gchandle_new or
795 * mono_gchandle_new_weakref.
797 * Returns a pointer to the MonoObject represented by the handle or
798 * NULL for a collected object if using a weakref handle.
801 mono_gchandle_get_target (guint32 gchandle)
803 guint slot = gchandle >> 3;
804 guint type = (gchandle & 7) - 1;
805 HandleData *handles = &gc_handles [type];
806 MonoObject *obj = NULL;
809 lock_handles (handles);
810 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
811 if (handles->type <= HANDLE_WEAK_TRACK) {
812 obj = mono_gc_weak_link_get (&handles->entries [slot]);
814 obj = handles->entries [slot];
817 /* print a warning? */
819 unlock_handles (handles);
820 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
825 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
827 guint slot = gchandle >> 3;
828 guint type = (gchandle & 7) - 1;
829 HandleData *handles = &gc_handles [type];
830 MonoObject *old_obj = NULL;
834 lock_handles (handles);
835 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
836 if (handles->type <= HANDLE_WEAK_TRACK) {
837 old_obj = handles->entries [slot];
838 if (handles->entries [slot])
839 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
841 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
842 /*FIXME, what to use when obj == null?*/
843 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
845 handles->entries [slot] = obj;
848 /* print a warning? */
850 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
851 unlock_handles (handles);
855 * mono_gchandle_is_in_domain:
856 * @gchandle: a GCHandle's handle.
857 * @domain: An application domain.
859 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
862 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
864 guint slot = gchandle >> 3;
865 guint type = (gchandle & 7) - 1;
866 HandleData *handles = &gc_handles [type];
867 gboolean result = FALSE;
870 lock_handles (handles);
871 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
872 if (handles->type <= HANDLE_WEAK_TRACK) {
873 result = domain->domain_id == handles->domain_ids [slot];
876 obj = handles->entries [slot];
880 result = domain == mono_object_domain (obj);
883 /* print a warning? */
885 unlock_handles (handles);
890 * mono_gchandle_free:
891 * @gchandle: a GCHandle's handle.
893 * Frees the @gchandle handle. If there are no outstanding
894 * references, the garbage collector can reclaim the memory of the
898 mono_gchandle_free (guint32 gchandle)
900 guint slot = gchandle >> 3;
901 guint type = (gchandle & 7) - 1;
902 HandleData *handles = &gc_handles [type];
906 lock_handles (handles);
907 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
908 if (handles->type <= HANDLE_WEAK_TRACK) {
909 if (handles->entries [slot])
910 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
912 handles->entries [slot] = NULL;
914 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
916 /* print a warning? */
918 #ifndef DISABLE_PERFCOUNTERS
919 mono_perfcounters->gc_num_handles--;
921 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
922 unlock_handles (handles);
923 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
927 * mono_gchandle_free_domain:
928 * @domain: domain that is unloading
930 * Function used internally to cleanup any GC handle for objects belonging
931 * to the specified domain during appdomain unload.
934 mono_gchandle_free_domain (MonoDomain *domain)
938 for (type = 0; type < 3; ++type) {
940 HandleData *handles = &gc_handles [type];
941 lock_handles (handles);
942 for (slot = 0; slot < handles->size; ++slot) {
943 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
945 if (type <= HANDLE_WEAK_TRACK) {
946 if (domain->domain_id == handles->domain_ids [slot]) {
947 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
948 if (handles->entries [slot])
949 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
952 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
953 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
954 handles->entries [slot] = NULL;
958 unlock_handles (handles);
964 GCHandle_CheckCurrentDomain (guint32 gchandle)
966 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
971 #ifdef MONO_HAS_SEMAPHORES
972 static MonoSemType finalizer_sem;
974 static HANDLE finalizer_event;
975 static volatile gboolean finished=FALSE;
978 mono_gc_finalize_notify (void)
981 g_message ( "%s: prodding finalizer", __func__);
984 #ifdef MONO_HAS_SEMAPHORES
985 MONO_SEM_POST (&finalizer_sem);
987 SetEvent (finalizer_event);
994 collect_objects (gpointer key, gpointer value, gpointer user_data)
996 GPtrArray *arr = (GPtrArray*)user_data;
997 g_ptr_array_add (arr, key);
1003 * finalize_domain_objects:
1005 * Run the finalizers of all finalizable objects in req->domain.
1008 finalize_domain_objects (DomainFinalizationReq *req)
1010 MonoDomain *domain = req->domain;
1013 #define NUM_FOBJECTS 64
1014 MonoObject *to_finalize [NUM_FOBJECTS];
1018 /* Process finalizers which are already in the queue */
1019 mono_gc_invoke_finalizers ();
1021 #ifdef HAVE_BOEHM_GC
1022 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1026 * Since the domain is unloading, nobody is allowed to put
1027 * new entries into the hash table. But finalize_object might
1028 * remove entries from the hash table, so we make a copy.
1030 objs = g_ptr_array_new ();
1031 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1032 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1034 for (i = 0; i < objs->len; ++i) {
1035 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1036 /* FIXME: Avoid finalizing threads, etc */
1037 mono_gc_run_finalize (o, 0);
1040 g_ptr_array_free (objs, TRUE);
1042 #elif defined(HAVE_SGEN_GC)
1043 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1045 for (i = 0; i < count; ++i) {
1046 mono_gc_run_finalize (to_finalize [i], 0);
1051 /* cleanup the reference queue */
1052 reference_queue_clear_for_domain (domain);
1054 /* printf ("DONE.\n"); */
1055 SetEvent (req->done_event);
1057 /* The event is closed in mono_domain_finalize if we get here */
1062 finalizer_thread (gpointer unused)
1065 /* Wait to be notified that there's at least one
1069 g_assert (mono_domain_get () == mono_get_root_domain ());
1071 /* An alertable wait is required so this thread can be suspended on windows */
1072 #ifdef MONO_HAS_SEMAPHORES
1073 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1075 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1078 mono_threads_perform_thread_dump ();
1080 mono_console_handle_async_ops ();
1082 #ifndef DISABLE_ATTACH
1083 mono_attach_maybe_start ();
1086 if (domains_to_finalize) {
1087 mono_finalizer_lock ();
1088 if (domains_to_finalize) {
1089 DomainFinalizationReq *req = domains_to_finalize->data;
1090 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1091 mono_finalizer_unlock ();
1093 finalize_domain_objects (req);
1095 mono_finalizer_unlock ();
1099 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1100 * before the domain is unloaded.
1102 mono_gc_invoke_finalizers ();
1104 reference_queue_proccess_all ();
1106 SetEvent (pending_done_event);
1109 SetEvent (shutdown_event);
1113 #ifndef LAZY_GC_THREAD_CREATION
1117 mono_gc_init_finalizer_thread (void)
1119 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
1120 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1126 InitializeCriticalSection (&handle_section);
1127 InitializeCriticalSection (&allocator_section);
1129 InitializeCriticalSection (&finalizer_mutex);
1130 InitializeCriticalSection (&reference_queue_mutex);
1132 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1133 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1135 mono_counters_register ("Created object count", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &mono_stats.new_object_count);
1136 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1137 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1138 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1139 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1141 mono_gc_base_init ();
1143 if (mono_gc_is_disabled ()) {
1148 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1149 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1150 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1151 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1152 g_assert_not_reached ();
1154 #ifdef MONO_HAS_SEMAPHORES
1155 MONO_SEM_INIT (&finalizer_sem, 0);
1158 #ifndef LAZY_GC_THREAD_CREATION
1159 mono_gc_init_finalizer_thread ();
1164 mono_gc_cleanup (void)
1167 g_message ("%s: cleaning up finalizer", __func__);
1171 ResetEvent (shutdown_event);
1173 if (mono_thread_internal_current () != gc_thread) {
1174 mono_gc_finalize_notify ();
1175 /* Finishing the finalizer thread, so wait a little bit... */
1176 /* MS seems to wait for about 2 seconds */
1177 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1180 /* Set a flag which the finalizer thread can check */
1181 suspend_finalizers = TRUE;
1183 /* Try to abort the thread, in the hope that it is running managed code */
1184 mono_thread_internal_stop (gc_thread);
1186 /* Wait for it to stop */
1187 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1189 if (ret == WAIT_TIMEOUT) {
1191 * The finalizer thread refused to die. There is not much we
1192 * can do here, since the runtime is shutting down so the
1193 * state the finalizer thread depends on will vanish.
1195 g_warning ("Shutting down finalizer thread timed out.");
1198 * FIXME: On unix, when the above wait returns, the thread
1199 * might still be running io-layer code, or pthreads code.
1206 /* Wait for the thread to actually exit */
1207 ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
1208 g_assert (ret == WAIT_OBJECT_0);
1212 * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
1213 * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
1215 ret = pthread_join ((MonoNativeThreadId)(gpointer)(gsize)gc_thread->tid, NULL);
1216 g_assert (ret == 0);
1221 #ifdef HAVE_BOEHM_GC
1222 GC_finalizer_notifier = NULL;
1226 mono_reference_queue_cleanup ();
1228 DeleteCriticalSection (&handle_section);
1229 DeleteCriticalSection (&allocator_section);
1230 DeleteCriticalSection (&finalizer_mutex);
1231 DeleteCriticalSection (&reference_queue_mutex);
1236 /* Null GC dummy functions */
1238 mono_gc_finalize_notify (void)
1242 void mono_gc_init (void)
1244 InitializeCriticalSection (&handle_section);
1247 void mono_gc_cleanup (void)
1254 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1256 return thread == gc_thread;
1260 * mono_gc_is_finalizer_thread:
1261 * @thread: the thread to test.
1263 * In Mono objects are finalized asynchronously on a separate thread.
1264 * This routine tests whether the @thread argument represents the
1265 * finalization thread.
1267 * Returns true if @thread is the finalization thread.
1270 mono_gc_is_finalizer_thread (MonoThread *thread)
1272 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1275 #if defined(__MACH__)
1276 static pthread_t mach_exception_thread;
1279 mono_gc_register_mach_exception_thread (pthread_t thread)
1281 mach_exception_thread = thread;
1285 mono_gc_get_mach_exception_thread (void)
1287 return mach_exception_thread;
1292 * mono_gc_parse_environment_string_extract_number:
1294 * @str: points to the first digit of the number
1295 * @out: pointer to the variable that will receive the value
1297 * Tries to extract a number from the passed string, taking in to account m, k
1300 * Returns true if passing was successful
1303 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1306 int len = strlen (str), shift = 0;
1308 gboolean is_suffix = FALSE;
1314 suffix = str [len - 1];
1329 if (!isdigit (suffix))
1335 val = strtol (str, &endptr, 10);
1337 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1338 || (errno != 0 && val == 0) || (endptr == str))
1344 if (val < 0) /* negative numbers cannot be suffixed */
1346 if (*(endptr + 1)) /* Invalid string. */
1349 unshifted = (gulong)val;
1351 if (val < 0) /* overflow */
1353 if (((gulong)val >> shift) != unshifted) /* value too large */
1361 #ifndef HAVE_SGEN_GC
1363 mono_gc_alloc_mature (MonoVTable *vtable)
1365 return mono_object_new_specific (vtable);
1370 static MonoReferenceQueue *ref_queues;
1373 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1376 /* Guard if head is changed concurrently. */
1377 while (*prev != element)
1378 prev = &(*prev)->next;
1379 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1383 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1385 RefQueueEntry *current;
1388 value->next = current;
1389 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1390 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1394 reference_queue_proccess (MonoReferenceQueue *queue)
1396 RefQueueEntry **iter = &queue->queue;
1397 RefQueueEntry *entry;
1398 while ((entry = *iter)) {
1400 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1401 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1403 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1404 mono_gchandle_free ((guint32)entry->gchandle);
1406 ref_list_remove_element (iter, entry);
1407 queue->callback (entry->user_data);
1410 iter = &entry->next;
1416 reference_queue_proccess_all (void)
1418 MonoReferenceQueue **iter;
1419 MonoReferenceQueue *queue = ref_queues;
1420 for (; queue; queue = queue->next)
1421 reference_queue_proccess (queue);
1424 EnterCriticalSection (&reference_queue_mutex);
1425 for (iter = &ref_queues; *iter;) {
1427 if (!queue->should_be_deleted) {
1428 iter = &queue->next;
1432 LeaveCriticalSection (&reference_queue_mutex);
1433 reference_queue_proccess (queue);
1436 *iter = queue->next;
1439 LeaveCriticalSection (&reference_queue_mutex);
1443 mono_reference_queue_cleanup (void)
1445 MonoReferenceQueue *queue = ref_queues;
1446 for (; queue; queue = queue->next)
1447 queue->should_be_deleted = TRUE;
1448 reference_queue_proccess_all ();
1452 reference_queue_clear_for_domain (MonoDomain *domain)
1454 MonoReferenceQueue *queue = ref_queues;
1455 for (; queue; queue = queue->next) {
1456 RefQueueEntry **iter = &queue->queue;
1457 RefQueueEntry *entry;
1458 while ((entry = *iter)) {
1461 obj = mono_gc_weak_link_get (&entry->dis_link);
1462 if (obj && mono_object_domain (obj) == domain) {
1463 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1465 obj = mono_gchandle_get_target (entry->gchandle);
1466 if (obj && mono_object_domain (obj) == domain) {
1467 mono_gchandle_free ((guint32)entry->gchandle);
1469 ref_list_remove_element (iter, entry);
1470 queue->callback (entry->user_data);
1473 iter = &entry->next;
1479 * mono_gc_reference_queue_new:
1480 * @callback callback used when processing dead entries.
1482 * Create a new reference queue used to process collected objects.
1483 * A reference queue let you queue a pair (managed object, user data)
1484 * using the mono_gc_reference_queue_add method.
1486 * Once the managed object is collected @callback will be called
1487 * in the finalizer thread with 'user data' as argument.
1489 * The callback is called without any locks held.
1492 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1494 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1495 res->callback = callback;
1497 EnterCriticalSection (&reference_queue_mutex);
1498 res->next = ref_queues;
1500 LeaveCriticalSection (&reference_queue_mutex);
1506 * mono_gc_reference_queue_add:
1507 * @queue the queue to add the reference to.
1508 * @obj the object to be watched for collection
1509 * @user_data parameter to be passed to the queue callback
1511 * Queue an object to be watched for collection, when the @obj is
1512 * collected, the callback that was registered for the @queue will
1513 * be invoked with the @obj and @user_data arguments.
1515 * @returns false if the queue is scheduled to be freed.
1518 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1520 RefQueueEntry *entry;
1521 if (queue->should_be_deleted)
1524 entry = g_new0 (RefQueueEntry, 1);
1525 entry->user_data = user_data;
1528 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1530 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1531 mono_object_register_finalizer (obj);
1534 ref_list_push (&queue->queue, entry);
1539 * mono_gc_reference_queue_free:
1540 * @queue the queue that should be deleted.
1542 * This operation signals that @queue should be deleted. This operation is deferred
1543 * as it happens on the finalizer thread.
1545 * After this call, no further objects can be queued. It's the responsibility of the
1546 * caller to make sure that no further attempt to access queue will be made.
1549 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1551 queue->should_be_deleted = TRUE;
1554 #define ptr_mask ((sizeof (void*) - 1))
1555 #define _toi(ptr) ((size_t)ptr)
1556 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1557 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1558 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1560 #define BZERO_WORDS(dest,words) do { \
1562 for (__i = 0; __i < (words); ++__i) \
1563 ((void **)(dest))[__i] = 0; \
1568 * @dest: address to start to clear
1569 * @size: size of the region to clear
1571 * Zero @size bytes starting at @dest.
1573 * Use this to zero memory that can hold managed pointers.
1575 * FIXME borrow faster code from some BSD libc or bionic
1578 mono_gc_bzero (void *dest, size_t size)
1580 char *d = (char*)dest;
1581 size_t tail_bytes, word_bytes;
1584 If we're copying less than a word, just use memset.
1586 We cannot bail out early if both are aligned because some implementations
1587 use byte copying for sizes smaller than 16. OSX, on this case.
1589 if (size < sizeof(void*)) {
1590 memset (dest, 0, size);
1594 /*align to word boundary */
1595 while (unaligned_bytes (d) && size) {
1600 /* copy all words with memmove */
1601 word_bytes = (size_t)align_down (size);
1602 switch (word_bytes) {
1603 case sizeof (void*) * 1:
1606 case sizeof (void*) * 2:
1609 case sizeof (void*) * 3:
1612 case sizeof (void*) * 4:
1616 memset (d, 0, word_bytes);
1619 tail_bytes = unaligned_bytes (size);
1624 } while (--tail_bytes);
1630 * @dest: destination of the move
1632 * @size: size of the block to move
1634 * Move @size bytes from @src to @dest.
1635 * size MUST be a multiple of sizeof (gpointer)
1639 mono_gc_memmove (void *dest, const void *src, size_t size)
1642 If we're copying less than a word we don't need to worry about word tearing
1643 so we bailout to memmove early.
1645 If both dest is aligned and size is a multiple of word size, we can go straigh
1649 if (size < sizeof(void*) || !((_toi (dest) | (size)) & sizeof (void*))) {
1650 memmove (dest, src, size);
1655 * A bit of explanation on why we align only dest before doing word copies.
1656 * Pointers to managed objects must always be stored in word aligned addresses, so
1657 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1659 * We don't need to case when source and destination have different alignments since we only do word stores
1660 * using memmove, which must handle it.
1662 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
1663 char *p = (char*)dest + size;
1664 char *s = (char*)src + size;
1665 char *start = (char*)dest;
1666 char *align_end = MAX((char*)dest, (char*)align_down (p));
1668 size_t bytes_to_memmove;
1670 while (p > align_end)
1673 word_start = align_up (start);
1674 bytes_to_memmove = p - word_start;
1675 p -= bytes_to_memmove;
1676 s -= bytes_to_memmove;
1677 memmove (p, s, bytes_to_memmove);
1682 char *d = (char*)dest;
1683 const char *s = (const char*)src;
1686 /*align to word boundary */
1687 while (unaligned_bytes (d)) {
1692 /* copy all words with memmove */
1693 memmove (d, s, (size_t)align_down (size));
1695 tail_bytes = unaligned_bytes (size);
1697 d += (size_t)align_down (size);
1698 s += (size_t)align_down (size);
1701 } while (--tail_bytes);