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>
43 typedef struct DomainFinalizationReq {
46 } DomainFinalizationReq;
48 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
49 extern void (*__imp_GC_finalizer_notifier)(void);
50 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
51 extern int __imp_GC_finalize_on_demand;
52 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
55 static gboolean gc_disabled = FALSE;
57 static gboolean finalizing_root_domain = FALSE;
59 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
60 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
61 static CRITICAL_SECTION finalizer_mutex;
62 static CRITICAL_SECTION reference_queue_mutex;
64 static GSList *domains_to_finalize= NULL;
65 static MonoMList *threads_to_finalize = NULL;
67 static MonoInternalThread *gc_thread;
69 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
71 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
73 static void reference_queue_proccess_all (void);
74 static void mono_reference_queue_cleanup (void);
75 static void reference_queue_clear_for_domain (MonoDomain *domain);
77 static HANDLE pending_done_event;
78 static HANDLE shutdown_event;
84 add_thread_to_finalize (MonoInternalThread *thread)
86 mono_finalizer_lock ();
87 if (!threads_to_finalize)
88 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
89 threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
90 mono_finalizer_unlock ();
93 static gboolean suspend_finalizers = FALSE;
95 * actually, we might want to queue the finalize requests in a separate thread,
96 * but we need to be careful about the execution domain of the thread...
99 mono_gc_run_finalize (void *obj, void *data)
101 MonoObject *exc = NULL;
106 MonoMethod* finalizer = NULL;
107 MonoDomain *caller_domain = mono_domain_get ();
109 RuntimeInvokeFunction runtime_invoke;
110 GSList *l, *refs = NULL;
112 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
114 if (suspend_finalizers)
117 domain = o->vtable->domain;
120 mono_domain_finalizers_lock (domain);
122 o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
124 refs = mono_gc_remove_weak_track_object (domain, o);
126 mono_domain_finalizers_unlock (domain);
129 /* Already finalized somehow */
135 * Support for GCHandles of type WeakTrackResurrection:
137 * Its not exactly clear how these are supposed to work, or how their
138 * semantics can be implemented. We only implement one crucial thing:
139 * these handles are only cleared after the finalizer has ran.
141 for (l = refs; l; l = l->next) {
142 guint32 gchandle = GPOINTER_TO_UINT (l->data);
144 mono_gchandle_set_target (gchandle, o);
150 /* make sure the finalizer is not called again if the object is resurrected */
151 object_register_finalizer (obj, NULL);
153 if (o->vtable->klass == mono_defaults.internal_thread_class) {
154 MonoInternalThread *t = (MonoInternalThread*)o;
156 if (mono_gc_is_finalizer_internal_thread (t))
157 /* Avoid finalizing ourselves */
160 if (t->threadpool_thread && finalizing_root_domain) {
161 /* Don't finalize threadpool threads when
162 shutting down - they're finalized when the
163 threadpool shuts down. */
164 add_thread_to_finalize (t);
169 if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
171 * These can't be finalized during unloading/shutdown, since that would
172 * free the native code which can still be referenced by other
174 * FIXME: This is not perfect, objects dying at the same time as
175 * dynamic methods can still reference them even when !shutdown.
180 if (mono_runtime_get_no_exec ())
183 /* speedup later... and use a timeout */
184 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
186 /* Use _internal here, since this thread can enter a doomed appdomain */
187 mono_domain_set_internal (mono_object_domain (o));
189 /* delegates that have a native function pointer allocated are
190 * registered for finalization, but they don't have a Finalize
191 * method, because in most cases it's not needed and it's just a waste.
193 if (o->vtable->klass->delegate) {
194 MonoDelegate* del = (MonoDelegate*)o;
195 if (del->delegate_trampoline)
196 mono_delegate_free_ftnptr ((MonoDelegate*)o);
197 mono_domain_set_internal (caller_domain);
201 finalizer = mono_class_get_finalizer (o->vtable->klass);
204 /* If object has a CCW but has no finalizer, it was only
205 * registered for finalization in order to free the CCW.
206 * Else it needs the regular finalizer run.
207 * FIXME: what to do about ressurection and suppression
208 * of finalizer on object with CCW.
210 if (mono_marshal_free_ccw (o) && !finalizer) {
211 mono_domain_set_internal (caller_domain);
217 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
218 * create and precompile a wrapper which calls the finalize method using
221 if (!domain->finalize_runtime_invoke) {
222 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
224 domain->finalize_runtime_invoke = mono_compile_method (invoke);
227 runtime_invoke = domain->finalize_runtime_invoke;
229 mono_runtime_class_init (o->vtable);
231 if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
232 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
233 o->vtable->klass->name_space, o->vtable->klass->name);
236 runtime_invoke (o, NULL, &exc, NULL);
239 mono_internal_thread_unhandled_exception (exc);
241 mono_domain_set_internal (caller_domain);
245 mono_gc_finalize_threadpool_threads (void)
247 while (threads_to_finalize) {
248 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
250 /* Force finalization of the thread. */
251 thread->threadpool_thread = FALSE;
252 mono_object_register_finalizer ((MonoObject*)thread);
254 mono_gc_run_finalize (thread, NULL);
256 threads_to_finalize = mono_mlist_next (threads_to_finalize);
261 mono_gc_out_of_memory (size_t size)
264 * we could allocate at program startup some memory that we could release
265 * back to the system at this point if we're really low on memory (ie, size is
266 * lower than the memory we set apart)
268 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
274 * Some of our objects may point to a different address than the address returned by GC_malloc()
275 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
276 * This also means that in the callback we need to adjust the pointer to get back the real
278 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
279 * since that, too, can cause the underlying pointer to be offset.
282 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
289 mono_raise_exception (mono_get_exception_argument_null ("obj"));
291 domain = obj->vtable->domain;
294 /* This assertion is not valid when GC_DEBUG is defined */
295 g_assert (GC_base (obj) == (char*)obj - offset);
298 if (mono_domain_is_unloading (domain) && (callback != NULL))
300 * Can't register finalizers in a dying appdomain, since they
301 * could be invoked after the appdomain has been unloaded.
305 mono_domain_finalizers_lock (domain);
308 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
310 g_hash_table_remove (domain->finalizable_objects_hash, obj);
312 mono_domain_finalizers_unlock (domain);
314 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
315 #elif defined(HAVE_SGEN_GC)
317 mono_raise_exception (mono_get_exception_argument_null ("obj"));
320 * If we register finalizers for domains that are unloading we might
321 * end up running them while or after the domain is being cleared, so
322 * the objects will not be valid anymore.
324 if (!mono_domain_is_unloading (obj->vtable->domain))
325 mono_gc_register_for_finalization (obj, callback);
330 * mono_object_register_finalizer:
331 * @obj: object to register
333 * Records that object @obj has a finalizer, this will call the
334 * Finalize method when the garbage collector disposes the object.
338 mono_object_register_finalizer (MonoObject *obj)
340 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
341 object_register_finalizer (obj, mono_gc_run_finalize);
345 * mono_domain_finalize:
346 * @domain: the domain to finalize
347 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
349 * Request finalization of all finalizable objects inside @domain. Wait
350 * @timeout msecs for the finalization to complete.
352 * Returns: TRUE if succeeded, FALSE if there was a timeout
356 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
358 DomainFinalizationReq *req;
361 MonoInternalThread *thread = mono_thread_internal_current ();
363 if (mono_thread_internal_current () == gc_thread)
364 /* We are called from inside a finalizer, not much we can do here */
368 * No need to create another thread 'cause the finalizer thread
369 * is still working and will take care of running the finalizers
376 mono_gc_collect (mono_gc_max_generation ());
378 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
379 if (done_event == NULL) {
383 req = g_new0 (DomainFinalizationReq, 1);
384 req->domain = domain;
385 req->done_event = done_event;
387 if (domain == mono_get_root_domain ())
388 finalizing_root_domain = TRUE;
390 mono_finalizer_lock ();
392 domains_to_finalize = g_slist_append (domains_to_finalize, req);
394 mono_finalizer_unlock ();
396 /* Tell the finalizer thread to finalize this appdomain */
397 mono_gc_finalize_notify ();
403 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
404 /* printf ("WAIT RES: %d.\n", res); */
406 if (res == WAIT_IO_COMPLETION) {
407 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
409 } else if (res == WAIT_TIMEOUT) {
410 /* We leak the handle here */
417 CloseHandle (done_event);
419 if (domain == mono_get_root_domain ()) {
420 mono_thread_pool_cleanup ();
421 mono_gc_finalize_threadpool_threads ();
426 /* We don't support domain finalization without a GC */
432 ves_icall_System_GC_InternalCollect (int generation)
434 mono_gc_collect (generation);
438 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
443 mono_gc_collect (mono_gc_max_generation ());
444 return mono_gc_get_used_size ();
448 ves_icall_System_GC_KeepAlive (MonoObject *obj)
458 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
461 mono_raise_exception (mono_get_exception_argument_null ("obj"));
463 object_register_finalizer (obj, mono_gc_run_finalize);
467 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
470 mono_raise_exception (mono_get_exception_argument_null ("obj"));
472 /* delegates have no finalizers, but we register them to deal with the
473 * unmanaged->managed trampoline. We don't let the user suppress it
474 * otherwise we'd leak it.
476 if (obj->vtable->klass->delegate)
479 /* FIXME: Need to handle case where obj has COM Callable Wrapper
480 * generated for it that needs cleaned up, but user wants to suppress
481 * their derived object finalizer. */
483 object_register_finalizer (obj, NULL);
487 ves_icall_System_GC_WaitForPendingFinalizers (void)
490 if (!mono_gc_pending_finalizers ())
493 if (mono_thread_internal_current () == gc_thread)
494 /* Avoid deadlocks */
498 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
499 be the one responsible for starting it up.
501 if (gc_thread == NULL)
504 ResetEvent (pending_done_event);
505 mono_gc_finalize_notify ();
506 /* g_print ("Waiting for pending finalizers....\n"); */
507 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
508 /* g_print ("Done pending....\n"); */
513 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
516 if (!mono_gc_ephemeron_array_add (array))
517 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
522 ves_icall_System_GC_get_ephemeron_tombstone (void)
524 return mono_domain_get ()->ephemeron_tombstone;
527 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
528 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
529 static CRITICAL_SECTION allocator_section;
530 static CRITICAL_SECTION handle_section;
539 static HandleType mono_gchandle_get_type (guint32 gchandle);
542 ves_icall_System_GCHandle_GetTarget (guint32 handle)
544 return mono_gchandle_get_target (handle);
548 * if type == -1, change the target of the handle, otherwise allocate a new handle.
551 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
554 mono_gchandle_set_target (handle, obj);
555 /* the handle doesn't change */
560 return mono_gchandle_new_weakref (obj, FALSE);
561 case HANDLE_WEAK_TRACK:
562 return mono_gchandle_new_weakref (obj, TRUE);
564 return mono_gchandle_new (obj, FALSE);
566 return mono_gchandle_new (obj, TRUE);
568 g_assert_not_reached ();
574 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
576 mono_gchandle_free (handle);
580 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
584 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
586 obj = mono_gchandle_get_target (handle);
588 MonoClass *klass = mono_object_class (obj);
589 if (klass == mono_defaults.string_class) {
590 return mono_string_chars ((MonoString*)obj);
591 } else if (klass->rank) {
592 return mono_array_addr ((MonoArray*)obj, char, 0);
594 /* the C# code will check and throw the exception */
595 /* FIXME: missing !klass->blittable test, see bug #61134 */
596 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
598 return (char*)obj + sizeof (MonoObject);
609 guint slot_hint : 24; /* starting slot for search */
610 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
611 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
615 /* weak and weak-track arrays will be allocated in malloc memory
617 static HandleData gc_handles [] = {
618 {NULL, NULL, 0, HANDLE_WEAK, 0},
619 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
620 {NULL, NULL, 0, HANDLE_NORMAL, 0},
621 {NULL, NULL, 0, HANDLE_PINNED, 0}
624 #define lock_handles(handles) EnterCriticalSection (&handle_section)
625 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
628 find_first_unset (guint32 bitmap)
631 for (i = 0; i < 32; ++i) {
632 if (!(bitmap & (1 << i)))
639 make_root_descr_all_refs (int numbits, gboolean pinned)
645 return mono_gc_make_root_descr_all_refs (numbits);
649 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
653 lock_handles (handles);
654 if (!handles->size) {
656 if (handles->type > HANDLE_WEAK_TRACK) {
657 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
659 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
660 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
662 handles->bitmap = g_malloc0 (handles->size / 8);
665 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
666 if (handles->bitmap [slot] != 0xffffffff) {
667 i = find_first_unset (handles->bitmap [slot]);
668 handles->slot_hint = slot;
672 if (i == -1 && handles->slot_hint != 0) {
673 for (slot = 0; slot < handles->slot_hint; ++slot) {
674 if (handles->bitmap [slot] != 0xffffffff) {
675 i = find_first_unset (handles->bitmap [slot]);
676 handles->slot_hint = slot;
683 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
685 /* resize and copy the bitmap */
686 new_bitmap = g_malloc0 (new_size / 8);
687 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
688 g_free (handles->bitmap);
689 handles->bitmap = new_bitmap;
691 /* resize and copy the entries */
692 if (handles->type > HANDLE_WEAK_TRACK) {
695 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
696 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
698 mono_gc_free_fixed (handles->entries);
699 handles->entries = entries;
703 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
704 entries = g_malloc (sizeof (gpointer) * new_size);
705 /* we disable GC because we could lose some disappearing link updates */
707 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
708 mono_gc_bzero (entries + handles->size, sizeof (gpointer) * handles->size);
709 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
710 for (i = 0; i < handles->size; ++i) {
711 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
712 if (handles->entries [i])
713 mono_gc_weak_link_remove (&(handles->entries [i]));
714 /*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]);*/
716 mono_gc_weak_link_add (&(entries [i]), obj, track);
719 g_free (handles->entries);
720 g_free (handles->domain_ids);
721 handles->entries = entries;
722 handles->domain_ids = domain_ids;
726 /* set i and slot to the next free position */
728 slot = (handles->size + 1) / 32;
729 handles->slot_hint = handles->size + 1;
730 handles->size = new_size;
732 handles->bitmap [slot] |= 1 << i;
733 slot = slot * 32 + i;
734 handles->entries [slot] = obj;
735 if (handles->type <= HANDLE_WEAK_TRACK) {
736 /*FIXME, what to use when obj == null?*/
737 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
739 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
742 #ifndef DISABLE_PERFCOUNTERS
743 mono_perfcounters->gc_num_handles++;
745 unlock_handles (handles);
746 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
747 res = (slot << 3) | (handles->type + 1);
748 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
754 * @obj: managed object to get a handle for
755 * @pinned: whether the object should be pinned
757 * This returns a handle that wraps the object, this is used to keep a
758 * reference to a managed object from the unmanaged world and preventing the
759 * object from being disposed.
761 * If @pinned is false the address of the object can not be obtained, if it is
762 * true the address of the object can be obtained. This will also pin the
763 * object so it will not be possible by a moving garbage collector to move the
766 * Returns: a handle that can be used to access the object from
770 mono_gchandle_new (MonoObject *obj, gboolean pinned)
772 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
776 * mono_gchandle_new_weakref:
777 * @obj: managed object to get a handle for
778 * @pinned: whether the object should be pinned
780 * This returns a weak handle that wraps the object, this is used to
781 * keep a reference to a managed object from the unmanaged world.
782 * Unlike the mono_gchandle_new the object can be reclaimed by the
783 * garbage collector. In this case the value of the GCHandle will be
786 * If @pinned is false the address of the object can not be obtained, if it is
787 * true the address of the object can be obtained. This will also pin the
788 * object so it will not be possible by a moving garbage collector to move the
791 * Returns: a handle that can be used to access the object from
795 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
797 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
800 if (track_resurrection)
801 mono_gc_add_weak_track_handle (obj, handle);
808 mono_gchandle_get_type (guint32 gchandle)
810 guint type = (gchandle & 7) - 1;
816 * mono_gchandle_get_target:
817 * @gchandle: a GCHandle's handle.
819 * The handle was previously created by calling mono_gchandle_new or
820 * mono_gchandle_new_weakref.
822 * Returns a pointer to the MonoObject represented by the handle or
823 * NULL for a collected object if using a weakref handle.
826 mono_gchandle_get_target (guint32 gchandle)
828 guint slot = gchandle >> 3;
829 guint type = (gchandle & 7) - 1;
830 HandleData *handles = &gc_handles [type];
831 MonoObject *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 obj = mono_gc_weak_link_get (&handles->entries [slot]);
839 obj = handles->entries [slot];
842 /* print a warning? */
844 unlock_handles (handles);
845 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
850 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
852 guint slot = gchandle >> 3;
853 guint type = (gchandle & 7) - 1;
854 HandleData *handles = &gc_handles [type];
855 MonoObject *old_obj = NULL;
859 lock_handles (handles);
860 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
861 if (handles->type <= HANDLE_WEAK_TRACK) {
862 old_obj = handles->entries [slot];
863 if (handles->entries [slot])
864 mono_gc_weak_link_remove (&handles->entries [slot]);
866 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
867 /*FIXME, what to use when obj == null?*/
868 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
870 handles->entries [slot] = obj;
873 /* print a warning? */
875 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
876 unlock_handles (handles);
879 if (type == HANDLE_WEAK_TRACK)
880 mono_gc_change_weak_track_handle (old_obj, obj, gchandle);
885 * mono_gchandle_is_in_domain:
886 * @gchandle: a GCHandle's handle.
887 * @domain: An application domain.
889 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
892 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
894 guint slot = gchandle >> 3;
895 guint type = (gchandle & 7) - 1;
896 HandleData *handles = &gc_handles [type];
897 gboolean result = FALSE;
900 lock_handles (handles);
901 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
902 if (handles->type <= HANDLE_WEAK_TRACK) {
903 result = domain->domain_id == handles->domain_ids [slot];
906 obj = handles->entries [slot];
910 result = domain == mono_object_domain (obj);
913 /* print a warning? */
915 unlock_handles (handles);
920 * mono_gchandle_free:
921 * @gchandle: a GCHandle's handle.
923 * Frees the @gchandle handle. If there are no outstanding
924 * references, the garbage collector can reclaim the memory of the
928 mono_gchandle_free (guint32 gchandle)
930 guint slot = gchandle >> 3;
931 guint type = (gchandle & 7) - 1;
932 HandleData *handles = &gc_handles [type];
936 if (type == HANDLE_WEAK_TRACK)
937 mono_gc_remove_weak_track_handle (gchandle);
940 lock_handles (handles);
941 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
942 if (handles->type <= HANDLE_WEAK_TRACK) {
943 if (handles->entries [slot])
944 mono_gc_weak_link_remove (&handles->entries [slot]);
946 handles->entries [slot] = NULL;
948 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
950 /* print a warning? */
952 #ifndef DISABLE_PERFCOUNTERS
953 mono_perfcounters->gc_num_handles--;
955 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
956 unlock_handles (handles);
957 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
961 * mono_gchandle_free_domain:
962 * @domain: domain that is unloading
964 * Function used internally to cleanup any GC handle for objects belonging
965 * to the specified domain during appdomain unload.
968 mono_gchandle_free_domain (MonoDomain *domain)
972 for (type = 0; type < 3; ++type) {
974 HandleData *handles = &gc_handles [type];
975 lock_handles (handles);
976 for (slot = 0; slot < handles->size; ++slot) {
977 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
979 if (type <= HANDLE_WEAK_TRACK) {
980 if (domain->domain_id == handles->domain_ids [slot]) {
981 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
982 if (handles->entries [slot])
983 mono_gc_weak_link_remove (&handles->entries [slot]);
986 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
987 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
988 handles->entries [slot] = NULL;
992 unlock_handles (handles);
998 GCHandle_CheckCurrentDomain (guint32 gchandle)
1000 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
1003 #ifndef HAVE_NULL_GC
1005 #ifdef MONO_HAS_SEMAPHORES
1006 static MonoSemType finalizer_sem;
1008 static HANDLE finalizer_event;
1009 static volatile gboolean finished=FALSE;
1012 mono_gc_finalize_notify (void)
1015 g_message ( "%s: prodding finalizer", __func__);
1018 #ifdef MONO_HAS_SEMAPHORES
1019 MONO_SEM_POST (&finalizer_sem);
1021 SetEvent (finalizer_event);
1025 #ifdef HAVE_BOEHM_GC
1028 collect_objects (gpointer key, gpointer value, gpointer user_data)
1030 GPtrArray *arr = (GPtrArray*)user_data;
1031 g_ptr_array_add (arr, key);
1037 * finalize_domain_objects:
1039 * Run the finalizers of all finalizable objects in req->domain.
1042 finalize_domain_objects (DomainFinalizationReq *req)
1044 MonoDomain *domain = req->domain;
1047 #define NUM_FOBJECTS 64
1048 MonoObject *to_finalize [NUM_FOBJECTS];
1052 /* Process finalizers which are already in the queue */
1053 mono_gc_invoke_finalizers ();
1055 #ifdef HAVE_BOEHM_GC
1056 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1060 * Since the domain is unloading, nobody is allowed to put
1061 * new entries into the hash table. But finalize_object might
1062 * remove entries from the hash table, so we make a copy.
1064 objs = g_ptr_array_new ();
1065 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1066 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1068 for (i = 0; i < objs->len; ++i) {
1069 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1070 /* FIXME: Avoid finalizing threads, etc */
1071 mono_gc_run_finalize (o, 0);
1074 g_ptr_array_free (objs, TRUE);
1076 #elif defined(HAVE_SGEN_GC)
1077 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1079 for (i = 0; i < count; ++i) {
1080 mono_gc_run_finalize (to_finalize [i], 0);
1085 /* cleanup the reference queue */
1086 reference_queue_clear_for_domain (domain);
1088 /* printf ("DONE.\n"); */
1089 SetEvent (req->done_event);
1091 /* The event is closed in mono_domain_finalize if we get here */
1096 finalizer_thread (gpointer unused)
1099 /* Wait to be notified that there's at least one
1103 g_assert (mono_domain_get () == mono_get_root_domain ());
1105 /* An alertable wait is required so this thread can be suspended on windows */
1106 #ifdef MONO_HAS_SEMAPHORES
1107 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1109 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1112 mono_threads_perform_thread_dump ();
1114 mono_console_handle_async_ops ();
1116 #ifndef DISABLE_ATTACH
1117 mono_attach_maybe_start ();
1120 if (domains_to_finalize) {
1121 mono_finalizer_lock ();
1122 if (domains_to_finalize) {
1123 DomainFinalizationReq *req = domains_to_finalize->data;
1124 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1125 mono_finalizer_unlock ();
1127 finalize_domain_objects (req);
1129 mono_finalizer_unlock ();
1133 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1134 * before the domain is unloaded.
1136 mono_gc_invoke_finalizers ();
1138 reference_queue_proccess_all ();
1140 SetEvent (pending_done_event);
1143 SetEvent (shutdown_event);
1147 #ifndef LAZY_GC_THREAD_CREATION
1151 mono_gc_init_finalizer_thread (void)
1153 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
1154 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1160 InitializeCriticalSection (&handle_section);
1161 InitializeCriticalSection (&allocator_section);
1163 InitializeCriticalSection (&finalizer_mutex);
1164 InitializeCriticalSection (&reference_queue_mutex);
1166 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1167 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1169 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1170 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1171 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1172 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1174 mono_gc_base_init ();
1176 if (mono_gc_is_disabled ()) {
1181 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1182 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1183 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1184 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1185 g_assert_not_reached ();
1187 #ifdef MONO_HAS_SEMAPHORES
1188 MONO_SEM_INIT (&finalizer_sem, 0);
1191 #ifndef LAZY_GC_THREAD_CREATION
1192 mono_gc_init_finalizer_thread ();
1197 mono_gc_cleanup (void)
1200 g_message ("%s: cleaning up finalizer", __func__);
1204 ResetEvent (shutdown_event);
1206 if (mono_thread_internal_current () != gc_thread) {
1207 mono_gc_finalize_notify ();
1208 /* Finishing the finalizer thread, so wait a little bit... */
1209 /* MS seems to wait for about 2 seconds */
1210 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1213 /* Set a flag which the finalizer thread can check */
1214 suspend_finalizers = TRUE;
1216 /* Try to abort the thread, in the hope that it is running managed code */
1217 mono_thread_internal_stop (gc_thread);
1219 /* Wait for it to stop */
1220 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1222 if (ret == WAIT_TIMEOUT) {
1224 * The finalizer thread refused to die. There is not much we
1225 * can do here, since the runtime is shutting down so the
1226 * state the finalizer thread depends on will vanish.
1228 g_warning ("Shutting down finalizer thread timed out.");
1231 * FIXME: On unix, when the above wait returns, the thread
1232 * might still be running io-layer code, or pthreads code.
1240 #ifdef HAVE_BOEHM_GC
1241 GC_finalizer_notifier = NULL;
1245 mono_reference_queue_cleanup ();
1247 DeleteCriticalSection (&handle_section);
1248 DeleteCriticalSection (&allocator_section);
1249 DeleteCriticalSection (&finalizer_mutex);
1250 DeleteCriticalSection (&reference_queue_mutex);
1255 /* Null GC dummy functions */
1257 mono_gc_finalize_notify (void)
1261 void mono_gc_init (void)
1263 InitializeCriticalSection (&handle_section);
1266 void mono_gc_cleanup (void)
1273 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1275 return thread == gc_thread;
1279 * mono_gc_is_finalizer_thread:
1280 * @thread: the thread to test.
1282 * In Mono objects are finalized asynchronously on a separate thread.
1283 * This routine tests whether the @thread argument represents the
1284 * finalization thread.
1286 * Returns true if @thread is the finalization thread.
1289 mono_gc_is_finalizer_thread (MonoThread *thread)
1291 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1294 #if defined(__MACH__)
1295 static pthread_t mach_exception_thread;
1298 mono_gc_register_mach_exception_thread (pthread_t thread)
1300 mach_exception_thread = thread;
1304 mono_gc_get_mach_exception_thread (void)
1306 return mach_exception_thread;
1311 * mono_gc_parse_environment_string_extract_number:
1313 * @str: points to the first digit of the number
1314 * @out: pointer to the variable that will receive the value
1316 * Tries to extract a number from the passed string, taking in to account m, k
1319 * Returns true if passing was successful
1322 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1325 int len = strlen (str), shift = 0;
1327 gboolean is_suffix = FALSE;
1333 suffix = str [len - 1];
1348 if (!isdigit (suffix))
1354 val = strtol (str, &endptr, 10);
1356 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1357 || (errno != 0 && val == 0) || (endptr == str))
1363 if (val < 0) /* negative numbers cannot be suffixed */
1365 if (*(endptr + 1)) /* Invalid string. */
1368 unshifted = (gulong)val;
1370 if (val < 0) /* overflow */
1372 if (((gulong)val >> shift) != unshifted) /* value too large */
1380 #ifndef HAVE_SGEN_GC
1382 mono_gc_alloc_mature (MonoVTable *vtable)
1384 return mono_object_new_specific (vtable);
1389 static MonoReferenceQueue *ref_queues;
1392 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1395 /* Guard if head is changed concurrently. */
1396 while (*prev != element)
1397 prev = &(*prev)->next;
1398 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1402 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1404 RefQueueEntry *current;
1407 value->next = current;
1408 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1409 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1413 reference_queue_proccess (MonoReferenceQueue *queue)
1415 RefQueueEntry **iter = &queue->queue;
1416 RefQueueEntry *entry;
1417 while ((entry = *iter)) {
1419 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1420 mono_gc_weak_link_remove (&entry->dis_link);
1422 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1423 mono_gchandle_free ((guint32)entry->gchandle);
1425 ref_list_remove_element (iter, entry);
1426 queue->callback (entry->user_data);
1429 iter = &entry->next;
1435 reference_queue_proccess_all (void)
1437 MonoReferenceQueue **iter;
1438 MonoReferenceQueue *queue = ref_queues;
1439 for (; queue; queue = queue->next)
1440 reference_queue_proccess (queue);
1443 EnterCriticalSection (&reference_queue_mutex);
1444 for (iter = &ref_queues; *iter;) {
1446 if (!queue->should_be_deleted) {
1447 iter = &queue->next;
1451 LeaveCriticalSection (&reference_queue_mutex);
1452 reference_queue_proccess (queue);
1455 *iter = queue->next;
1458 LeaveCriticalSection (&reference_queue_mutex);
1462 mono_reference_queue_cleanup (void)
1464 MonoReferenceQueue *queue = ref_queues;
1465 for (; queue; queue = queue->next)
1466 queue->should_be_deleted = TRUE;
1467 reference_queue_proccess_all ();
1471 reference_queue_clear_for_domain (MonoDomain *domain)
1473 MonoReferenceQueue *queue = ref_queues;
1474 for (; queue; queue = queue->next) {
1475 RefQueueEntry **iter = &queue->queue;
1476 RefQueueEntry *entry;
1477 while ((entry = *iter)) {
1480 obj = mono_gc_weak_link_get (&entry->dis_link);
1481 if (obj && mono_object_domain (obj) == domain) {
1482 mono_gc_weak_link_remove (&entry->dis_link);
1484 obj = mono_gchandle_get_target (entry->gchandle);
1485 if (obj && mono_object_domain (obj) == domain) {
1486 mono_gchandle_free ((guint32)entry->gchandle);
1488 ref_list_remove_element (iter, entry);
1489 queue->callback (entry->user_data);
1492 iter = &entry->next;
1498 * mono_gc_reference_queue_new:
1499 * @callback callback used when processing dead entries.
1501 * Create a new reference queue used to process collected objects.
1502 * A reference queue let you queue a pair (managed object, user data)
1503 * using the mono_gc_reference_queue_add method.
1505 * Once the managed object is collected @callback will be called
1506 * in the finalizer thread with 'user data' as argument.
1508 * The callback is called without any locks held.
1511 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1513 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1514 res->callback = callback;
1516 EnterCriticalSection (&reference_queue_mutex);
1517 res->next = ref_queues;
1519 LeaveCriticalSection (&reference_queue_mutex);
1525 * mono_gc_reference_queue_add:
1526 * @queue the queue to add the reference to.
1527 * @obj the object to be watched for collection
1528 * @user_data parameter to be passed to the queue callback
1530 * Queue an object to be watched for collection, when the @obj is
1531 * collected, the callback that was registered for the @queue will
1532 * be invoked with the @obj and @user_data arguments.
1534 * @returns false if the queue is scheduled to be freed.
1537 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1539 RefQueueEntry *entry;
1540 if (queue->should_be_deleted)
1543 entry = g_new0 (RefQueueEntry, 1);
1544 entry->user_data = user_data;
1547 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1549 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1550 mono_object_register_finalizer (obj);
1553 ref_list_push (&queue->queue, entry);
1558 * mono_gc_reference_queue_free:
1559 * @queue the queue that should be deleted.
1561 * This operation signals that @queue should be deleted. This operation is deferred
1562 * as it happens on the finalizer thread.
1564 * After this call, no further objects can be queued. It's the responsibility of the
1565 * caller to make sure that no further attempt to access queue will be made.
1568 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1570 queue->should_be_deleted = TRUE;
1573 #define ptr_mask ((sizeof (void*) - 1))
1574 #define _toi(ptr) ((size_t)ptr)
1575 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1576 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1577 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1581 * @dest: address to start to clear
1582 * @size: size of the region to clear
1584 * Zero @size bytes starting at @dest.
1586 * Use this to zero memory that can hold managed pointers.
1588 * FIXME borrow faster code from some BSD libc or bionic
1591 mono_gc_bzero (void *dest, size_t size)
1593 char *p = (char*)dest;
1594 char *end = p + size;
1595 char *align_end = align_up (p);
1598 while (p < align_end)
1601 word_end = align_down (end);
1602 while (p < word_end) {
1603 *((void**)p) = NULL;
1604 p += sizeof (void*);
1614 * @dest: destination of the move
1616 * @size: size of the block to move
1618 * Move @size bytes from @src to @dest.
1619 * size MUST be a multiple of sizeof (gpointer)
1621 * FIXME borrow faster code from some BSD libc or bionic
1624 mono_gc_memmove (void *dest, const void *src, size_t size)
1627 * If dest and src are differently aligned with respect to
1628 * pointer size then it makes no sense to do aligned copying.
1629 * In fact, we would end up with unaligned loads which is
1630 * incorrect on some architectures.
1632 if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
1633 memmove (dest, src, size);
1638 * A bit of explanation on why we align only dest before doing word copies.
1639 * Pointers to managed objects must always be stored in word aligned addresses, so
1640 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1642 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
1643 char *p = (char*)dest + size;
1644 char *s = (char*)src + size;
1645 char *start = (char*)dest;
1646 char *align_end = MAX((char*)dest, (char*)align_down (p));
1649 while (p > align_end)
1652 word_start = align_up (start);
1653 while (p > word_start) {
1654 p -= sizeof (void*);
1655 s -= sizeof (void*);
1656 *((void**)p) = *((void**)s);
1662 char *p = (char*)dest;
1663 char *s = (char*)src;
1664 char *end = p + size;
1665 char *align_end = MIN ((char*)end, (char*)align_up (p));
1668 while (p < align_end)
1671 word_end = align_down (end);
1672 while (p < word_end) {
1673 *((void**)p) = *((void**)s);
1674 p += sizeof (void*);
1675 s += sizeof (void*);