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>
41 typedef struct DomainFinalizationReq {
44 } DomainFinalizationReq;
46 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
47 extern void (*__imp_GC_finalizer_notifier)(void);
48 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
49 extern int __imp_GC_finalize_on_demand;
50 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
53 static gboolean gc_disabled = FALSE;
55 static gboolean finalizing_root_domain = FALSE;
57 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
58 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
59 static CRITICAL_SECTION finalizer_mutex;
60 static CRITICAL_SECTION reference_queue_mutex;
62 static GSList *domains_to_finalize= NULL;
63 static MonoMList *threads_to_finalize = NULL;
65 static MonoInternalThread *gc_thread;
67 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
69 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
71 static void reference_queue_proccess_all (void);
72 static void mono_reference_queue_cleanup (void);
73 static void reference_queue_clear_for_domain (MonoDomain *domain);
75 static HANDLE pending_done_event;
76 static HANDLE shutdown_event;
80 add_thread_to_finalize (MonoInternalThread *thread)
82 mono_finalizer_lock ();
83 if (!threads_to_finalize)
84 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
85 threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
86 mono_finalizer_unlock ();
89 static gboolean suspend_finalizers = FALSE;
91 * actually, we might want to queue the finalize requests in a separate thread,
92 * but we need to be careful about the execution domain of the thread...
95 mono_gc_run_finalize (void *obj, void *data)
97 MonoObject *exc = NULL;
102 MonoMethod* finalizer = NULL;
103 MonoDomain *caller_domain = mono_domain_get ();
105 RuntimeInvokeFunction runtime_invoke;
106 GSList *l, *refs = NULL;
108 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
110 if (suspend_finalizers)
113 domain = o->vtable->domain;
116 mono_domain_finalizers_lock (domain);
118 o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
120 refs = mono_gc_remove_weak_track_object (domain, o);
122 mono_domain_finalizers_unlock (domain);
125 /* Already finalized somehow */
131 * Support for GCHandles of type WeakTrackResurrection:
133 * Its not exactly clear how these are supposed to work, or how their
134 * semantics can be implemented. We only implement one crucial thing:
135 * these handles are only cleared after the finalizer has ran.
137 for (l = refs; l; l = l->next) {
138 guint32 gchandle = GPOINTER_TO_UINT (l->data);
140 mono_gchandle_set_target (gchandle, o);
146 /* make sure the finalizer is not called again if the object is resurrected */
147 object_register_finalizer (obj, NULL);
149 if (o->vtable->klass == mono_defaults.internal_thread_class) {
150 MonoInternalThread *t = (MonoInternalThread*)o;
152 if (mono_gc_is_finalizer_internal_thread (t))
153 /* Avoid finalizing ourselves */
156 if (t->threadpool_thread && finalizing_root_domain) {
157 /* Don't finalize threadpool threads when
158 shutting down - they're finalized when the
159 threadpool shuts down. */
160 add_thread_to_finalize (t);
165 if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
167 * These can't be finalized during unloading/shutdown, since that would
168 * free the native code which can still be referenced by other
170 * FIXME: This is not perfect, objects dying at the same time as
171 * dynamic methods can still reference them even when !shutdown.
176 if (mono_runtime_get_no_exec ())
179 /* speedup later... and use a timeout */
180 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
182 /* Use _internal here, since this thread can enter a doomed appdomain */
183 mono_domain_set_internal (mono_object_domain (o));
185 /* delegates that have a native function pointer allocated are
186 * registered for finalization, but they don't have a Finalize
187 * method, because in most cases it's not needed and it's just a waste.
189 if (o->vtable->klass->delegate) {
190 MonoDelegate* del = (MonoDelegate*)o;
191 if (del->delegate_trampoline)
192 mono_delegate_free_ftnptr ((MonoDelegate*)o);
193 mono_domain_set_internal (caller_domain);
197 finalizer = mono_class_get_finalizer (o->vtable->klass);
200 /* If object has a CCW but has no finalizer, it was only
201 * registered for finalization in order to free the CCW.
202 * Else it needs the regular finalizer run.
203 * FIXME: what to do about ressurection and suppression
204 * of finalizer on object with CCW.
206 if (mono_marshal_free_ccw (o) && !finalizer) {
207 mono_domain_set_internal (caller_domain);
213 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
214 * create and precompile a wrapper which calls the finalize method using
217 if (!domain->finalize_runtime_invoke) {
218 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
220 domain->finalize_runtime_invoke = mono_compile_method (invoke);
223 runtime_invoke = domain->finalize_runtime_invoke;
225 mono_runtime_class_init (o->vtable);
227 runtime_invoke (o, NULL, &exc, NULL);
230 mono_internal_thread_unhandled_exception (exc);
232 mono_domain_set_internal (caller_domain);
236 mono_gc_finalize_threadpool_threads (void)
238 while (threads_to_finalize) {
239 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
241 /* Force finalization of the thread. */
242 thread->threadpool_thread = FALSE;
243 mono_object_register_finalizer ((MonoObject*)thread);
245 mono_gc_run_finalize (thread, NULL);
247 threads_to_finalize = mono_mlist_next (threads_to_finalize);
252 mono_gc_out_of_memory (size_t size)
255 * we could allocate at program startup some memory that we could release
256 * back to the system at this point if we're really low on memory (ie, size is
257 * lower than the memory we set apart)
259 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
265 * Some of our objects may point to a different address than the address returned by GC_malloc()
266 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
267 * This also means that in the callback we need to adjust the pointer to get back the real
269 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
270 * since that, too, can cause the underlying pointer to be offset.
273 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
280 mono_raise_exception (mono_get_exception_argument_null ("obj"));
282 domain = obj->vtable->domain;
285 /* This assertion is not valid when GC_DEBUG is defined */
286 g_assert (GC_base (obj) == (char*)obj - offset);
289 if (mono_domain_is_unloading (domain) && (callback != NULL))
291 * Can't register finalizers in a dying appdomain, since they
292 * could be invoked after the appdomain has been unloaded.
296 mono_domain_finalizers_lock (domain);
299 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
301 g_hash_table_remove (domain->finalizable_objects_hash, obj);
303 mono_domain_finalizers_unlock (domain);
305 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
306 #elif defined(HAVE_SGEN_GC)
308 mono_raise_exception (mono_get_exception_argument_null ("obj"));
311 * If we register finalizers for domains that are unloading we might
312 * end up running them while or after the domain is being cleared, so
313 * the objects will not be valid anymore.
315 if (!mono_domain_is_unloading (obj->vtable->domain))
316 mono_gc_register_for_finalization (obj, callback);
321 * mono_object_register_finalizer:
322 * @obj: object to register
324 * Records that object @obj has a finalizer, this will call the
325 * Finalize method when the garbage collector disposes the object.
329 mono_object_register_finalizer (MonoObject *obj)
331 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
332 object_register_finalizer (obj, mono_gc_run_finalize);
336 * mono_domain_finalize:
337 * @domain: the domain to finalize
338 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
340 * Request finalization of all finalizable objects inside @domain. Wait
341 * @timeout msecs for the finalization to complete.
343 * Returns: TRUE if succeeded, FALSE if there was a timeout
347 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
349 DomainFinalizationReq *req;
352 MonoInternalThread *thread = mono_thread_internal_current ();
354 if (mono_thread_internal_current () == gc_thread)
355 /* We are called from inside a finalizer, not much we can do here */
359 * No need to create another thread 'cause the finalizer thread
360 * is still working and will take care of running the finalizers
367 mono_gc_collect (mono_gc_max_generation ());
369 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
370 if (done_event == NULL) {
374 req = g_new0 (DomainFinalizationReq, 1);
375 req->domain = domain;
376 req->done_event = done_event;
378 if (domain == mono_get_root_domain ())
379 finalizing_root_domain = TRUE;
381 mono_finalizer_lock ();
383 domains_to_finalize = g_slist_append (domains_to_finalize, req);
385 mono_finalizer_unlock ();
387 /* Tell the finalizer thread to finalize this appdomain */
388 mono_gc_finalize_notify ();
394 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
395 /* printf ("WAIT RES: %d.\n", res); */
397 if (res == WAIT_IO_COMPLETION) {
398 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
400 } else if (res == WAIT_TIMEOUT) {
401 /* We leak the handle here */
408 CloseHandle (done_event);
410 if (domain == mono_get_root_domain ()) {
411 mono_thread_pool_cleanup ();
412 mono_gc_finalize_threadpool_threads ();
417 /* We don't support domain finalization without a GC */
423 ves_icall_System_GC_InternalCollect (int generation)
425 mono_gc_collect (generation);
429 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
434 mono_gc_collect (mono_gc_max_generation ());
435 return mono_gc_get_used_size ();
439 ves_icall_System_GC_KeepAlive (MonoObject *obj)
449 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
452 mono_raise_exception (mono_get_exception_argument_null ("obj"));
454 object_register_finalizer (obj, mono_gc_run_finalize);
458 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
461 mono_raise_exception (mono_get_exception_argument_null ("obj"));
463 /* delegates have no finalizers, but we register them to deal with the
464 * unmanaged->managed trampoline. We don't let the user suppress it
465 * otherwise we'd leak it.
467 if (obj->vtable->klass->delegate)
470 /* FIXME: Need to handle case where obj has COM Callable Wrapper
471 * generated for it that needs cleaned up, but user wants to suppress
472 * their derived object finalizer. */
474 object_register_finalizer (obj, NULL);
478 ves_icall_System_GC_WaitForPendingFinalizers (void)
481 if (!mono_gc_pending_finalizers ())
484 if (mono_thread_internal_current () == gc_thread)
485 /* Avoid deadlocks */
489 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
490 be the one responsible for starting it up.
492 if (gc_thread == NULL)
495 ResetEvent (pending_done_event);
496 mono_gc_finalize_notify ();
497 /* g_print ("Waiting for pending finalizers....\n"); */
498 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
499 /* g_print ("Done pending....\n"); */
504 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
507 if (!mono_gc_ephemeron_array_add (array))
508 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
513 ves_icall_System_GC_get_ephemeron_tombstone (void)
515 return mono_domain_get ()->ephemeron_tombstone;
518 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
519 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
520 static CRITICAL_SECTION allocator_section;
521 static CRITICAL_SECTION handle_section;
530 static HandleType mono_gchandle_get_type (guint32 gchandle);
533 ves_icall_System_GCHandle_GetTarget (guint32 handle)
535 return mono_gchandle_get_target (handle);
539 * if type == -1, change the target of the handle, otherwise allocate a new handle.
542 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
545 mono_gchandle_set_target (handle, obj);
546 /* the handle doesn't change */
551 return mono_gchandle_new_weakref (obj, FALSE);
552 case HANDLE_WEAK_TRACK:
553 return mono_gchandle_new_weakref (obj, TRUE);
555 return mono_gchandle_new (obj, FALSE);
557 return mono_gchandle_new (obj, TRUE);
559 g_assert_not_reached ();
565 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
567 mono_gchandle_free (handle);
571 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
575 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
577 obj = mono_gchandle_get_target (handle);
579 MonoClass *klass = mono_object_class (obj);
580 if (klass == mono_defaults.string_class) {
581 return mono_string_chars ((MonoString*)obj);
582 } else if (klass->rank) {
583 return mono_array_addr ((MonoArray*)obj, char, 0);
585 /* the C# code will check and throw the exception */
586 /* FIXME: missing !klass->blittable test, see bug #61134 */
587 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
589 return (char*)obj + sizeof (MonoObject);
600 guint slot_hint : 24; /* starting slot for search */
601 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
602 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
606 /* weak and weak-track arrays will be allocated in malloc memory
608 static HandleData gc_handles [] = {
609 {NULL, NULL, 0, HANDLE_WEAK, 0},
610 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
611 {NULL, NULL, 0, HANDLE_NORMAL, 0},
612 {NULL, NULL, 0, HANDLE_PINNED, 0}
615 #define lock_handles(handles) EnterCriticalSection (&handle_section)
616 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
619 find_first_unset (guint32 bitmap)
622 for (i = 0; i < 32; ++i) {
623 if (!(bitmap & (1 << i)))
630 make_root_descr_all_refs (int numbits, gboolean pinned)
636 return mono_gc_make_root_descr_all_refs (numbits);
640 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
644 lock_handles (handles);
645 if (!handles->size) {
647 if (handles->type > HANDLE_WEAK_TRACK) {
648 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
650 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
651 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
653 handles->bitmap = g_malloc0 (handles->size / 8);
656 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
657 if (handles->bitmap [slot] != 0xffffffff) {
658 i = find_first_unset (handles->bitmap [slot]);
659 handles->slot_hint = slot;
663 if (i == -1 && handles->slot_hint != 0) {
664 for (slot = 0; slot < handles->slot_hint; ++slot) {
665 if (handles->bitmap [slot] != 0xffffffff) {
666 i = find_first_unset (handles->bitmap [slot]);
667 handles->slot_hint = slot;
674 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
676 /* resize and copy the bitmap */
677 new_bitmap = g_malloc0 (new_size / 8);
678 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
679 g_free (handles->bitmap);
680 handles->bitmap = new_bitmap;
682 /* resize and copy the entries */
683 if (handles->type > HANDLE_WEAK_TRACK) {
686 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
687 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
689 mono_gc_free_fixed (handles->entries);
690 handles->entries = entries;
694 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
695 entries = g_malloc (sizeof (gpointer) * new_size);
696 /* we disable GC because we could lose some disappearing link updates */
698 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
699 mono_gc_bzero (entries + handles->size, sizeof (gpointer) * handles->size);
700 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
701 for (i = 0; i < handles->size; ++i) {
702 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
703 if (handles->entries [i])
704 mono_gc_weak_link_remove (&(handles->entries [i]));
705 /*g_print ("reg/unreg entry %d of type %d at %p to object %p (%p), was: %p\n", i, handles->type, &(entries [i]), obj, entries [i], handles->entries [i]);*/
707 mono_gc_weak_link_add (&(entries [i]), obj, track);
710 g_free (handles->entries);
711 g_free (handles->domain_ids);
712 handles->entries = entries;
713 handles->domain_ids = domain_ids;
717 /* set i and slot to the next free position */
719 slot = (handles->size + 1) / 32;
720 handles->slot_hint = handles->size + 1;
721 handles->size = new_size;
723 handles->bitmap [slot] |= 1 << i;
724 slot = slot * 32 + i;
725 handles->entries [slot] = obj;
726 if (handles->type <= HANDLE_WEAK_TRACK) {
727 /*FIXME, what to use when obj == null?*/
728 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
730 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
733 mono_perfcounters->gc_num_handles++;
734 unlock_handles (handles);
735 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
736 res = (slot << 3) | (handles->type + 1);
737 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
743 * @obj: managed object to get a handle for
744 * @pinned: whether the object should be pinned
746 * This returns a handle that wraps the object, this is used to keep a
747 * reference to a managed object from the unmanaged world and preventing the
748 * object from being disposed.
750 * If @pinned is false the address of the object can not be obtained, if it is
751 * true the address of the object can be obtained. This will also pin the
752 * object so it will not be possible by a moving garbage collector to move the
755 * Returns: a handle that can be used to access the object from
759 mono_gchandle_new (MonoObject *obj, gboolean pinned)
761 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
765 * mono_gchandle_new_weakref:
766 * @obj: managed object to get a handle for
767 * @pinned: whether the object should be pinned
769 * This returns a weak handle that wraps the object, this is used to
770 * keep a reference to a managed object from the unmanaged world.
771 * Unlike the mono_gchandle_new the object can be reclaimed by the
772 * garbage collector. In this case the value of the GCHandle will be
775 * If @pinned is false the address of the object can not be obtained, if it is
776 * true the address of the object can be obtained. This will also pin the
777 * object so it will not be possible by a moving garbage collector to move the
780 * Returns: a handle that can be used to access the object from
784 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
786 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
789 if (track_resurrection)
790 mono_gc_add_weak_track_handle (obj, handle);
797 mono_gchandle_get_type (guint32 gchandle)
799 guint type = (gchandle & 7) - 1;
805 * mono_gchandle_get_target:
806 * @gchandle: a GCHandle's handle.
808 * The handle was previously created by calling mono_gchandle_new or
809 * mono_gchandle_new_weakref.
811 * Returns a pointer to the MonoObject represented by the handle or
812 * NULL for a collected object if using a weakref handle.
815 mono_gchandle_get_target (guint32 gchandle)
817 guint slot = gchandle >> 3;
818 guint type = (gchandle & 7) - 1;
819 HandleData *handles = &gc_handles [type];
820 MonoObject *obj = NULL;
823 lock_handles (handles);
824 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
825 if (handles->type <= HANDLE_WEAK_TRACK) {
826 obj = mono_gc_weak_link_get (&handles->entries [slot]);
828 obj = handles->entries [slot];
831 /* print a warning? */
833 unlock_handles (handles);
834 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
839 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
841 guint slot = gchandle >> 3;
842 guint type = (gchandle & 7) - 1;
843 HandleData *handles = &gc_handles [type];
844 MonoObject *old_obj = NULL;
848 lock_handles (handles);
849 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
850 if (handles->type <= HANDLE_WEAK_TRACK) {
851 old_obj = handles->entries [slot];
852 if (handles->entries [slot])
853 mono_gc_weak_link_remove (&handles->entries [slot]);
855 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
856 /*FIXME, what to use when obj == null?*/
857 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
859 handles->entries [slot] = obj;
862 /* print a warning? */
864 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
865 unlock_handles (handles);
868 if (type == HANDLE_WEAK_TRACK)
869 mono_gc_change_weak_track_handle (old_obj, obj, gchandle);
874 * mono_gchandle_is_in_domain:
875 * @gchandle: a GCHandle's handle.
876 * @domain: An application domain.
878 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
881 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
883 guint slot = gchandle >> 3;
884 guint type = (gchandle & 7) - 1;
885 HandleData *handles = &gc_handles [type];
886 gboolean result = FALSE;
889 lock_handles (handles);
890 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
891 if (handles->type <= HANDLE_WEAK_TRACK) {
892 result = domain->domain_id == handles->domain_ids [slot];
895 obj = handles->entries [slot];
899 result = domain == mono_object_domain (obj);
902 /* print a warning? */
904 unlock_handles (handles);
909 * mono_gchandle_free:
910 * @gchandle: a GCHandle's handle.
912 * Frees the @gchandle handle. If there are no outstanding
913 * references, the garbage collector can reclaim the memory of the
917 mono_gchandle_free (guint32 gchandle)
919 guint slot = gchandle >> 3;
920 guint type = (gchandle & 7) - 1;
921 HandleData *handles = &gc_handles [type];
925 if (type == HANDLE_WEAK_TRACK)
926 mono_gc_remove_weak_track_handle (gchandle);
929 lock_handles (handles);
930 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
931 if (handles->type <= HANDLE_WEAK_TRACK) {
932 if (handles->entries [slot])
933 mono_gc_weak_link_remove (&handles->entries [slot]);
935 handles->entries [slot] = NULL;
937 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
939 /* print a warning? */
941 mono_perfcounters->gc_num_handles--;
942 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
943 unlock_handles (handles);
944 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
948 * mono_gchandle_free_domain:
949 * @domain: domain that is unloading
951 * Function used internally to cleanup any GC handle for objects belonging
952 * to the specified domain during appdomain unload.
955 mono_gchandle_free_domain (MonoDomain *domain)
959 for (type = 0; type < 3; ++type) {
961 HandleData *handles = &gc_handles [type];
962 lock_handles (handles);
963 for (slot = 0; slot < handles->size; ++slot) {
964 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
966 if (type <= HANDLE_WEAK_TRACK) {
967 if (domain->domain_id == handles->domain_ids [slot]) {
968 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
969 if (handles->entries [slot])
970 mono_gc_weak_link_remove (&handles->entries [slot]);
973 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
974 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
975 handles->entries [slot] = NULL;
979 unlock_handles (handles);
985 GCHandle_CheckCurrentDomain (guint32 gchandle)
987 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
992 #ifdef MONO_HAS_SEMAPHORES
993 static MonoSemType finalizer_sem;
995 static HANDLE finalizer_event;
996 static volatile gboolean finished=FALSE;
999 mono_gc_finalize_notify (void)
1002 g_message ( "%s: prodding finalizer", __func__);
1005 #ifdef MONO_HAS_SEMAPHORES
1006 MONO_SEM_POST (&finalizer_sem);
1008 SetEvent (finalizer_event);
1012 #ifdef HAVE_BOEHM_GC
1015 collect_objects (gpointer key, gpointer value, gpointer user_data)
1017 GPtrArray *arr = (GPtrArray*)user_data;
1018 g_ptr_array_add (arr, key);
1024 * finalize_domain_objects:
1026 * Run the finalizers of all finalizable objects in req->domain.
1029 finalize_domain_objects (DomainFinalizationReq *req)
1031 MonoDomain *domain = req->domain;
1034 #define NUM_FOBJECTS 64
1035 MonoObject *to_finalize [NUM_FOBJECTS];
1039 /* Process finalizers which are already in the queue */
1040 mono_gc_invoke_finalizers ();
1042 #ifdef HAVE_BOEHM_GC
1043 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1047 * Since the domain is unloading, nobody is allowed to put
1048 * new entries into the hash table. But finalize_object might
1049 * remove entries from the hash table, so we make a copy.
1051 objs = g_ptr_array_new ();
1052 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1053 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1055 for (i = 0; i < objs->len; ++i) {
1056 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1057 /* FIXME: Avoid finalizing threads, etc */
1058 mono_gc_run_finalize (o, 0);
1061 g_ptr_array_free (objs, TRUE);
1063 #elif defined(HAVE_SGEN_GC)
1064 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1066 for (i = 0; i < count; ++i) {
1067 mono_gc_run_finalize (to_finalize [i], 0);
1072 /* cleanup the reference queue */
1073 reference_queue_clear_for_domain (domain);
1075 /* printf ("DONE.\n"); */
1076 SetEvent (req->done_event);
1078 /* The event is closed in mono_domain_finalize if we get here */
1083 finalizer_thread (gpointer unused)
1086 /* Wait to be notified that there's at least one
1090 g_assert (mono_domain_get () == mono_get_root_domain ());
1092 /* An alertable wait is required so this thread can be suspended on windows */
1093 #ifdef MONO_HAS_SEMAPHORES
1094 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1096 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1099 mono_threads_perform_thread_dump ();
1101 mono_console_handle_async_ops ();
1103 #ifndef DISABLE_ATTACH
1104 mono_attach_maybe_start ();
1107 if (domains_to_finalize) {
1108 mono_finalizer_lock ();
1109 if (domains_to_finalize) {
1110 DomainFinalizationReq *req = domains_to_finalize->data;
1111 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1112 mono_finalizer_unlock ();
1114 finalize_domain_objects (req);
1116 mono_finalizer_unlock ();
1120 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1121 * before the domain is unloaded.
1123 mono_gc_invoke_finalizers ();
1125 reference_queue_proccess_all ();
1127 SetEvent (pending_done_event);
1130 SetEvent (shutdown_event);
1137 InitializeCriticalSection (&handle_section);
1138 InitializeCriticalSection (&allocator_section);
1140 InitializeCriticalSection (&finalizer_mutex);
1141 InitializeCriticalSection (&reference_queue_mutex);
1143 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1144 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
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 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
1164 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1168 mono_gc_cleanup (void)
1171 g_message ("%s: cleaning up finalizer", __func__);
1175 ResetEvent (shutdown_event);
1177 if (mono_thread_internal_current () != gc_thread) {
1178 mono_gc_finalize_notify ();
1179 /* Finishing the finalizer thread, so wait a little bit... */
1180 /* MS seems to wait for about 2 seconds */
1181 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1184 /* Set a flag which the finalizer thread can check */
1185 suspend_finalizers = TRUE;
1187 /* Try to abort the thread, in the hope that it is running managed code */
1188 mono_thread_internal_stop (gc_thread);
1190 /* Wait for it to stop */
1191 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1193 if (ret == WAIT_TIMEOUT) {
1195 * The finalizer thread refused to die. There is not much we
1196 * can do here, since the runtime is shutting down so the
1197 * state the finalizer thread depends on will vanish.
1199 g_warning ("Shutting down finalizer thread timed out.");
1202 * FIXME: On unix, when the above wait returns, the thread
1203 * might still be running io-layer code, or pthreads code.
1211 #ifdef HAVE_BOEHM_GC
1212 GC_finalizer_notifier = NULL;
1216 mono_reference_queue_cleanup ();
1218 DeleteCriticalSection (&handle_section);
1219 DeleteCriticalSection (&allocator_section);
1220 DeleteCriticalSection (&finalizer_mutex);
1221 DeleteCriticalSection (&reference_queue_mutex);
1226 /* Null GC dummy functions */
1228 mono_gc_finalize_notify (void)
1232 void mono_gc_init (void)
1234 InitializeCriticalSection (&handle_section);
1237 void mono_gc_cleanup (void)
1244 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1246 return thread == gc_thread;
1250 * mono_gc_is_finalizer_thread:
1251 * @thread: the thread to test.
1253 * In Mono objects are finalized asynchronously on a separate thread.
1254 * This routine tests whether the @thread argument represents the
1255 * finalization thread.
1257 * Returns true if @thread is the finalization thread.
1260 mono_gc_is_finalizer_thread (MonoThread *thread)
1262 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1265 #if defined(__MACH__)
1266 static pthread_t mach_exception_thread;
1269 mono_gc_register_mach_exception_thread (pthread_t thread)
1271 mach_exception_thread = thread;
1275 mono_gc_get_mach_exception_thread (void)
1277 return mach_exception_thread;
1282 * mono_gc_parse_environment_string_extract_number:
1284 * @str: points to the first digit of the number
1285 * @out: pointer to the variable that will receive the value
1287 * Tries to extract a number from the passed string, taking in to account m, k
1290 * Returns true if passing was successful
1293 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1296 int len = strlen (str), shift = 0;
1298 gboolean is_suffix = FALSE;
1304 suffix = str [len - 1];
1319 if (!isdigit (suffix))
1325 val = strtol (str, &endptr, 10);
1327 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1328 || (errno != 0 && val == 0) || (endptr == str))
1332 if (*(endptr + 1)) /* Invalid string. */
1341 #ifndef HAVE_SGEN_GC
1343 mono_gc_alloc_mature (MonoVTable *vtable)
1345 return mono_object_new_specific (vtable);
1350 static MonoReferenceQueue *ref_queues;
1353 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1356 /* Guard if head is changed concurrently. */
1357 while (*prev != element)
1358 prev = &(*prev)->next;
1359 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1363 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1365 RefQueueEntry *current;
1368 value->next = current;
1369 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1370 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1374 reference_queue_proccess (MonoReferenceQueue *queue)
1376 RefQueueEntry **iter = &queue->queue;
1377 RefQueueEntry *entry;
1378 while ((entry = *iter)) {
1380 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1381 mono_gc_weak_link_remove (&entry->dis_link);
1383 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1384 mono_gchandle_free ((guint32)entry->gchandle);
1386 ref_list_remove_element (iter, entry);
1387 queue->callback (entry->user_data);
1390 iter = &entry->next;
1396 reference_queue_proccess_all (void)
1398 MonoReferenceQueue **iter;
1399 MonoReferenceQueue *queue = ref_queues;
1400 for (; queue; queue = queue->next)
1401 reference_queue_proccess (queue);
1404 EnterCriticalSection (&reference_queue_mutex);
1405 for (iter = &ref_queues; *iter;) {
1407 if (!queue->should_be_deleted) {
1408 iter = &queue->next;
1412 LeaveCriticalSection (&reference_queue_mutex);
1413 reference_queue_proccess (queue);
1416 *iter = queue->next;
1419 LeaveCriticalSection (&reference_queue_mutex);
1423 mono_reference_queue_cleanup (void)
1425 MonoReferenceQueue *queue = ref_queues;
1426 for (; queue; queue = queue->next)
1427 queue->should_be_deleted = TRUE;
1428 reference_queue_proccess_all ();
1432 reference_queue_clear_for_domain (MonoDomain *domain)
1434 MonoReferenceQueue *queue = ref_queues;
1435 for (; queue; queue = queue->next) {
1436 RefQueueEntry **iter = &queue->queue;
1437 RefQueueEntry *entry;
1438 while ((entry = *iter)) {
1441 obj = mono_gc_weak_link_get (&entry->dis_link);
1442 if (obj && mono_object_domain (obj) == domain) {
1443 mono_gc_weak_link_remove (&entry->dis_link);
1445 obj = mono_gchandle_get_target (entry->gchandle);
1446 if (obj && mono_object_domain (obj) == domain) {
1447 mono_gchandle_free ((guint32)entry->gchandle);
1449 ref_list_remove_element (iter, entry);
1450 queue->callback (entry->user_data);
1453 iter = &entry->next;
1459 * mono_gc_reference_queue_new:
1460 * @callback callback used when processing dead entries.
1462 * Create a new reference queue used to process collected objects.
1463 * A reference queue let you queue a pair (managed object, user data)
1464 * using the mono_gc_reference_queue_add method.
1466 * Once the managed object is collected @callback will be called
1467 * in the finalizer thread with 'user data' as argument.
1469 * The callback is called without any locks held.
1472 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1474 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1475 res->callback = callback;
1477 EnterCriticalSection (&reference_queue_mutex);
1478 res->next = ref_queues;
1480 LeaveCriticalSection (&reference_queue_mutex);
1486 * mono_gc_reference_queue_add:
1487 * @queue the queue to add the reference to.
1488 * @obj the object to be watched for collection
1489 * @user_data parameter to be passed to the queue callback
1491 * Queue an object to be watched for collection, when the @obj is
1492 * collected, the callback that was registered for the @queue will
1493 * be invoked with the @obj and @user_data arguments.
1495 * @returns false if the queue is scheduled to be freed.
1498 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1500 RefQueueEntry *entry;
1501 if (queue->should_be_deleted)
1504 entry = g_new0 (RefQueueEntry, 1);
1505 entry->user_data = user_data;
1508 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1510 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1511 mono_object_register_finalizer (obj);
1514 ref_list_push (&queue->queue, entry);
1519 * mono_gc_reference_queue_free:
1520 * @queue the queue that should be deleted.
1522 * This operation signals that @queue should be deleted. This operation is deferred
1523 * as it happens on the finalizer thread.
1525 * After this call, no further objects can be queued. It's the responsibility of the
1526 * caller to make sure that no further attempt to access queue will be made.
1529 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1531 queue->should_be_deleted = TRUE;
1534 #define ptr_mask ((sizeof (void*) - 1))
1535 #define _toi(ptr) ((size_t)ptr)
1536 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1537 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1538 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1542 * @dest: address to start to clear
1543 * @size: size of the region to clear
1545 * Zero @size bytes starting at @dest.
1547 * Use this to zero memory that can hold managed pointers.
1549 * FIXME borrow faster code from some BSD libc or bionic
1552 mono_gc_bzero (void *dest, size_t size)
1554 char *p = (char*)dest;
1555 char *end = p + size;
1556 char *align_end = align_up (p);
1559 while (p < align_end)
1562 word_end = align_down (end);
1563 while (p < word_end) {
1564 *((void**)p) = NULL;
1565 p += sizeof (void*);
1575 * @dest: destination of the move
1577 * @size: size of the block to move
1579 * Move @size bytes from @src to @dest.
1580 * size MUST be a multiple of sizeof (gpointer)
1582 * FIXME borrow faster code from some BSD libc or bionic
1585 mono_gc_memmove (void *dest, const void *src, size_t size)
1588 * If dest and src are differently aligned with respect to
1589 * pointer size then it makes no sense to do aligned copying.
1590 * In fact, we would end up with unaligned loads which is
1591 * incorrect on some architectures.
1593 if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
1594 memmove (dest, src, size);
1599 * A bit of explanation on why we align only dest before doing word copies.
1600 * Pointers to managed objects must always be stored in word aligned addresses, so
1601 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1603 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
1604 char *p = (char*)dest + size;
1605 char *s = (char*)src + size;
1606 char *start = (char*)dest;
1607 char *align_end = MAX((char*)dest, (char*)align_down (p));
1610 while (p > align_end)
1613 word_start = align_up (start);
1614 while (p > word_start) {
1615 p -= sizeof (void*);
1616 s -= sizeof (void*);
1617 *((void**)p) = *((void**)s);
1623 char *p = (char*)dest;
1624 char *s = (char*)src;
1625 char *end = p + size;
1626 char *align_end = MIN ((char*)end, (char*)align_up (p));
1629 while (p < align_end)
1632 word_end = align_down (end);
1633 while (p < word_end) {
1634 *((void**)p) = *((void**)s);
1635 p += sizeof (void*);
1636 s += sizeof (void*);