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;
111 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
113 if (suspend_finalizers)
116 domain = o->vtable->domain;
119 mono_domain_finalizers_lock (domain);
121 o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
123 mono_domain_finalizers_unlock (domain);
126 /* Already finalized somehow */
130 /* make sure the finalizer is not called again if the object is resurrected */
131 object_register_finalizer (obj, NULL);
133 if (o->vtable->klass == mono_defaults.internal_thread_class) {
134 MonoInternalThread *t = (MonoInternalThread*)o;
136 if (mono_gc_is_finalizer_internal_thread (t))
137 /* Avoid finalizing ourselves */
140 if (t->threadpool_thread && finalizing_root_domain) {
141 /* Don't finalize threadpool threads when
142 shutting down - they're finalized when the
143 threadpool shuts down. */
144 add_thread_to_finalize (t);
149 if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
151 * These can't be finalized during unloading/shutdown, since that would
152 * free the native code which can still be referenced by other
154 * FIXME: This is not perfect, objects dying at the same time as
155 * dynamic methods can still reference them even when !shutdown.
160 if (mono_runtime_get_no_exec ())
163 /* speedup later... and use a timeout */
164 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
166 /* Use _internal here, since this thread can enter a doomed appdomain */
167 mono_domain_set_internal (mono_object_domain (o));
169 /* delegates that have a native function pointer allocated are
170 * registered for finalization, but they don't have a Finalize
171 * method, because in most cases it's not needed and it's just a waste.
173 if (o->vtable->klass->delegate) {
174 MonoDelegate* del = (MonoDelegate*)o;
175 if (del->delegate_trampoline)
176 mono_delegate_free_ftnptr ((MonoDelegate*)o);
177 mono_domain_set_internal (caller_domain);
181 finalizer = mono_class_get_finalizer (o->vtable->klass);
184 /* If object has a CCW but has no finalizer, it was only
185 * registered for finalization in order to free the CCW.
186 * Else it needs the regular finalizer run.
187 * FIXME: what to do about ressurection and suppression
188 * of finalizer on object with CCW.
190 if (mono_marshal_free_ccw (o) && !finalizer) {
191 mono_domain_set_internal (caller_domain);
197 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
198 * create and precompile a wrapper which calls the finalize method using
201 if (!domain->finalize_runtime_invoke) {
202 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
204 domain->finalize_runtime_invoke = mono_compile_method (invoke);
207 runtime_invoke = domain->finalize_runtime_invoke;
209 mono_runtime_class_init (o->vtable);
211 if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
212 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
213 o->vtable->klass->name_space, o->vtable->klass->name);
216 runtime_invoke (o, NULL, &exc, NULL);
219 mono_internal_thread_unhandled_exception (exc);
221 mono_domain_set_internal (caller_domain);
225 mono_gc_finalize_threadpool_threads (void)
227 while (threads_to_finalize) {
228 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
230 /* Force finalization of the thread. */
231 thread->threadpool_thread = FALSE;
232 mono_object_register_finalizer ((MonoObject*)thread);
234 mono_gc_run_finalize (thread, NULL);
236 threads_to_finalize = mono_mlist_next (threads_to_finalize);
241 mono_gc_out_of_memory (size_t size)
244 * we could allocate at program startup some memory that we could release
245 * back to the system at this point if we're really low on memory (ie, size is
246 * lower than the memory we set apart)
248 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
254 * Some of our objects may point to a different address than the address returned by GC_malloc()
255 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
256 * This also means that in the callback we need to adjust the pointer to get back the real
258 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
259 * since that, too, can cause the underlying pointer to be offset.
262 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 /* This assertion is not valid when GC_DEBUG is defined */
275 g_assert (GC_base (obj) == (char*)obj - offset);
278 if (mono_domain_is_unloading (domain) && (callback != NULL))
280 * Can't register finalizers in a dying appdomain, since they
281 * could be invoked after the appdomain has been unloaded.
285 mono_domain_finalizers_lock (domain);
288 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
290 g_hash_table_remove (domain->finalizable_objects_hash, obj);
292 mono_domain_finalizers_unlock (domain);
294 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
295 #elif defined(HAVE_SGEN_GC)
297 mono_raise_exception (mono_get_exception_argument_null ("obj"));
300 * If we register finalizers for domains that are unloading we might
301 * end up running them while or after the domain is being cleared, so
302 * the objects will not be valid anymore.
304 if (!mono_domain_is_unloading (obj->vtable->domain))
305 mono_gc_register_for_finalization (obj, callback);
310 * mono_object_register_finalizer:
311 * @obj: object to register
313 * Records that object @obj has a finalizer, this will call the
314 * Finalize method when the garbage collector disposes the object.
318 mono_object_register_finalizer (MonoObject *obj)
320 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
321 object_register_finalizer (obj, mono_gc_run_finalize);
325 * mono_domain_finalize:
326 * @domain: the domain to finalize
327 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
329 * Request finalization of all finalizable objects inside @domain. Wait
330 * @timeout msecs for the finalization to complete.
332 * Returns: TRUE if succeeded, FALSE if there was a timeout
336 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
338 DomainFinalizationReq *req;
341 MonoInternalThread *thread = mono_thread_internal_current ();
343 if (mono_thread_internal_current () == gc_thread)
344 /* We are called from inside a finalizer, not much we can do here */
348 * No need to create another thread 'cause the finalizer thread
349 * is still working and will take care of running the finalizers
356 mono_gc_collect (mono_gc_max_generation ());
358 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
359 if (done_event == NULL) {
363 req = g_new0 (DomainFinalizationReq, 1);
364 req->domain = domain;
365 req->done_event = done_event;
367 if (domain == mono_get_root_domain ())
368 finalizing_root_domain = TRUE;
370 mono_finalizer_lock ();
372 domains_to_finalize = g_slist_append (domains_to_finalize, req);
374 mono_finalizer_unlock ();
376 /* Tell the finalizer thread to finalize this appdomain */
377 mono_gc_finalize_notify ();
383 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
384 /* printf ("WAIT RES: %d.\n", res); */
386 if (res == WAIT_IO_COMPLETION) {
387 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
389 } else if (res == WAIT_TIMEOUT) {
390 /* We leak the handle here */
397 CloseHandle (done_event);
399 if (domain == mono_get_root_domain ()) {
400 mono_thread_pool_cleanup ();
401 mono_gc_finalize_threadpool_threads ();
406 /* We don't support domain finalization without a GC */
412 ves_icall_System_GC_InternalCollect (int generation)
414 mono_gc_collect (generation);
418 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
423 mono_gc_collect (mono_gc_max_generation ());
424 return mono_gc_get_used_size ();
428 ves_icall_System_GC_KeepAlive (MonoObject *obj)
438 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
441 mono_raise_exception (mono_get_exception_argument_null ("obj"));
443 object_register_finalizer (obj, mono_gc_run_finalize);
447 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
450 mono_raise_exception (mono_get_exception_argument_null ("obj"));
452 /* delegates have no finalizers, but we register them to deal with the
453 * unmanaged->managed trampoline. We don't let the user suppress it
454 * otherwise we'd leak it.
456 if (obj->vtable->klass->delegate)
459 /* FIXME: Need to handle case where obj has COM Callable Wrapper
460 * generated for it that needs cleaned up, but user wants to suppress
461 * their derived object finalizer. */
463 object_register_finalizer (obj, NULL);
467 ves_icall_System_GC_WaitForPendingFinalizers (void)
470 if (!mono_gc_pending_finalizers ())
473 if (mono_thread_internal_current () == gc_thread)
474 /* Avoid deadlocks */
478 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
479 be the one responsible for starting it up.
481 if (gc_thread == NULL)
484 ResetEvent (pending_done_event);
485 mono_gc_finalize_notify ();
486 /* g_print ("Waiting for pending finalizers....\n"); */
487 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
488 /* g_print ("Done pending....\n"); */
493 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
496 if (!mono_gc_ephemeron_array_add (array))
497 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
502 ves_icall_System_GC_get_ephemeron_tombstone (void)
504 return mono_domain_get ()->ephemeron_tombstone;
507 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
508 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
509 static CRITICAL_SECTION allocator_section;
510 static CRITICAL_SECTION handle_section;
519 static HandleType mono_gchandle_get_type (guint32 gchandle);
522 ves_icall_System_GCHandle_GetTarget (guint32 handle)
524 return mono_gchandle_get_target (handle);
528 * if type == -1, change the target of the handle, otherwise allocate a new handle.
531 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
534 mono_gchandle_set_target (handle, obj);
535 /* the handle doesn't change */
540 return mono_gchandle_new_weakref (obj, FALSE);
541 case HANDLE_WEAK_TRACK:
542 return mono_gchandle_new_weakref (obj, TRUE);
544 return mono_gchandle_new (obj, FALSE);
546 return mono_gchandle_new (obj, TRUE);
548 g_assert_not_reached ();
554 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
556 mono_gchandle_free (handle);
560 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
564 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
566 obj = mono_gchandle_get_target (handle);
568 MonoClass *klass = mono_object_class (obj);
569 if (klass == mono_defaults.string_class) {
570 return mono_string_chars ((MonoString*)obj);
571 } else if (klass->rank) {
572 return mono_array_addr ((MonoArray*)obj, char, 0);
574 /* the C# code will check and throw the exception */
575 /* FIXME: missing !klass->blittable test, see bug #61134 */
576 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
578 return (char*)obj + sizeof (MonoObject);
589 guint slot_hint : 24; /* starting slot for search */
590 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
591 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
595 /* weak and weak-track arrays will be allocated in malloc memory
597 static HandleData gc_handles [] = {
598 {NULL, NULL, 0, HANDLE_WEAK, 0},
599 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
600 {NULL, NULL, 0, HANDLE_NORMAL, 0},
601 {NULL, NULL, 0, HANDLE_PINNED, 0}
604 #define lock_handles(handles) EnterCriticalSection (&handle_section)
605 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
608 find_first_unset (guint32 bitmap)
611 for (i = 0; i < 32; ++i) {
612 if (!(bitmap & (1 << i)))
619 make_root_descr_all_refs (int numbits, gboolean pinned)
625 return mono_gc_make_root_descr_all_refs (numbits);
629 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
633 lock_handles (handles);
634 if (!handles->size) {
636 if (handles->type > HANDLE_WEAK_TRACK) {
637 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
639 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
640 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
642 handles->bitmap = g_malloc0 (handles->size / 8);
645 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
646 if (handles->bitmap [slot] != 0xffffffff) {
647 i = find_first_unset (handles->bitmap [slot]);
648 handles->slot_hint = slot;
652 if (i == -1 && handles->slot_hint != 0) {
653 for (slot = 0; slot < handles->slot_hint; ++slot) {
654 if (handles->bitmap [slot] != 0xffffffff) {
655 i = find_first_unset (handles->bitmap [slot]);
656 handles->slot_hint = slot;
663 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
665 /* resize and copy the bitmap */
666 new_bitmap = g_malloc0 (new_size / 8);
667 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
668 g_free (handles->bitmap);
669 handles->bitmap = new_bitmap;
671 /* resize and copy the entries */
672 if (handles->type > HANDLE_WEAK_TRACK) {
675 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
676 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
678 mono_gc_free_fixed (handles->entries);
679 handles->entries = entries;
683 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
684 entries = g_malloc (sizeof (gpointer) * new_size);
685 /* we disable GC because we could lose some disappearing link updates */
687 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
688 mono_gc_bzero (entries + handles->size, sizeof (gpointer) * handles->size);
689 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
690 for (i = 0; i < handles->size; ++i) {
691 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
692 if (handles->entries [i])
693 mono_gc_weak_link_remove (&(handles->entries [i]), track);
694 /*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]);*/
696 mono_gc_weak_link_add (&(entries [i]), obj, track);
699 g_free (handles->entries);
700 g_free (handles->domain_ids);
701 handles->entries = entries;
702 handles->domain_ids = domain_ids;
706 /* set i and slot to the next free position */
708 slot = (handles->size + 1) / 32;
709 handles->slot_hint = handles->size + 1;
710 handles->size = new_size;
712 handles->bitmap [slot] |= 1 << i;
713 slot = slot * 32 + i;
714 handles->entries [slot] = NULL;
715 if (handles->type <= HANDLE_WEAK_TRACK) {
716 /*FIXME, what to use when obj == null?*/
717 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
719 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
721 handles->entries [slot] = obj;
724 #ifndef DISABLE_PERFCOUNTERS
725 mono_perfcounters->gc_num_handles++;
727 unlock_handles (handles);
728 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
729 res = (slot << 3) | (handles->type + 1);
730 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
736 * @obj: managed object to get a handle for
737 * @pinned: whether the object should be pinned
739 * This returns a handle that wraps the object, this is used to keep a
740 * reference to a managed object from the unmanaged world and preventing the
741 * object from being disposed.
743 * If @pinned is false the address of the object can not be obtained, if it is
744 * true the address of the object can be obtained. This will also pin the
745 * object so it will not be possible by a moving garbage collector to move the
748 * Returns: a handle that can be used to access the object from
752 mono_gchandle_new (MonoObject *obj, gboolean pinned)
754 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
758 * mono_gchandle_new_weakref:
759 * @obj: managed object to get a handle for
760 * @pinned: whether the object should be pinned
762 * This returns a weak handle that wraps the object, this is used to
763 * keep a reference to a managed object from the unmanaged world.
764 * Unlike the mono_gchandle_new the object can be reclaimed by the
765 * garbage collector. In this case the value of the GCHandle will be
768 * If @pinned is false the address of the object can not be obtained, if it is
769 * true the address of the object can be obtained. This will also pin the
770 * object so it will not be possible by a moving garbage collector to move the
773 * Returns: a handle that can be used to access the object from
777 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
779 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
785 mono_gchandle_get_type (guint32 gchandle)
787 guint type = (gchandle & 7) - 1;
793 * mono_gchandle_get_target:
794 * @gchandle: a GCHandle's handle.
796 * The handle was previously created by calling mono_gchandle_new or
797 * mono_gchandle_new_weakref.
799 * Returns a pointer to the MonoObject represented by the handle or
800 * NULL for a collected object if using a weakref handle.
803 mono_gchandle_get_target (guint32 gchandle)
805 guint slot = gchandle >> 3;
806 guint type = (gchandle & 7) - 1;
807 HandleData *handles = &gc_handles [type];
808 MonoObject *obj = NULL;
811 lock_handles (handles);
812 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
813 if (handles->type <= HANDLE_WEAK_TRACK) {
814 obj = mono_gc_weak_link_get (&handles->entries [slot]);
816 obj = handles->entries [slot];
819 /* print a warning? */
821 unlock_handles (handles);
822 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
827 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
829 guint slot = gchandle >> 3;
830 guint type = (gchandle & 7) - 1;
831 HandleData *handles = &gc_handles [type];
832 MonoObject *old_obj = NULL;
836 lock_handles (handles);
837 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
838 if (handles->type <= HANDLE_WEAK_TRACK) {
839 old_obj = handles->entries [slot];
840 if (handles->entries [slot])
841 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
843 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
844 /*FIXME, what to use when obj == null?*/
845 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
847 handles->entries [slot] = obj;
850 /* print a warning? */
852 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
853 unlock_handles (handles);
857 * mono_gchandle_is_in_domain:
858 * @gchandle: a GCHandle's handle.
859 * @domain: An application domain.
861 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
864 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
866 guint slot = gchandle >> 3;
867 guint type = (gchandle & 7) - 1;
868 HandleData *handles = &gc_handles [type];
869 gboolean result = FALSE;
872 lock_handles (handles);
873 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
874 if (handles->type <= HANDLE_WEAK_TRACK) {
875 result = domain->domain_id == handles->domain_ids [slot];
878 obj = handles->entries [slot];
882 result = domain == mono_object_domain (obj);
885 /* print a warning? */
887 unlock_handles (handles);
892 * mono_gchandle_free:
893 * @gchandle: a GCHandle's handle.
895 * Frees the @gchandle handle. If there are no outstanding
896 * references, the garbage collector can reclaim the memory of the
900 mono_gchandle_free (guint32 gchandle)
902 guint slot = gchandle >> 3;
903 guint type = (gchandle & 7) - 1;
904 HandleData *handles = &gc_handles [type];
908 lock_handles (handles);
909 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
910 if (handles->type <= HANDLE_WEAK_TRACK) {
911 if (handles->entries [slot])
912 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
914 handles->entries [slot] = NULL;
916 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
918 /* print a warning? */
920 #ifndef DISABLE_PERFCOUNTERS
921 mono_perfcounters->gc_num_handles--;
923 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
924 unlock_handles (handles);
925 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
929 * mono_gchandle_free_domain:
930 * @domain: domain that is unloading
932 * Function used internally to cleanup any GC handle for objects belonging
933 * to the specified domain during appdomain unload.
936 mono_gchandle_free_domain (MonoDomain *domain)
940 for (type = 0; type < 3; ++type) {
942 HandleData *handles = &gc_handles [type];
943 lock_handles (handles);
944 for (slot = 0; slot < handles->size; ++slot) {
945 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
947 if (type <= HANDLE_WEAK_TRACK) {
948 if (domain->domain_id == handles->domain_ids [slot]) {
949 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
950 if (handles->entries [slot])
951 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
954 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
955 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
956 handles->entries [slot] = NULL;
960 unlock_handles (handles);
966 GCHandle_CheckCurrentDomain (guint32 gchandle)
968 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
973 #ifdef MONO_HAS_SEMAPHORES
974 static MonoSemType finalizer_sem;
976 static HANDLE finalizer_event;
977 static volatile gboolean finished=FALSE;
980 mono_gc_finalize_notify (void)
983 g_message ( "%s: prodding finalizer", __func__);
986 #ifdef MONO_HAS_SEMAPHORES
987 MONO_SEM_POST (&finalizer_sem);
989 SetEvent (finalizer_event);
996 collect_objects (gpointer key, gpointer value, gpointer user_data)
998 GPtrArray *arr = (GPtrArray*)user_data;
999 g_ptr_array_add (arr, key);
1005 * finalize_domain_objects:
1007 * Run the finalizers of all finalizable objects in req->domain.
1010 finalize_domain_objects (DomainFinalizationReq *req)
1012 MonoDomain *domain = req->domain;
1015 #define NUM_FOBJECTS 64
1016 MonoObject *to_finalize [NUM_FOBJECTS];
1020 /* Process finalizers which are already in the queue */
1021 mono_gc_invoke_finalizers ();
1023 #ifdef HAVE_BOEHM_GC
1024 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1028 * Since the domain is unloading, nobody is allowed to put
1029 * new entries into the hash table. But finalize_object might
1030 * remove entries from the hash table, so we make a copy.
1032 objs = g_ptr_array_new ();
1033 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1034 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1036 for (i = 0; i < objs->len; ++i) {
1037 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1038 /* FIXME: Avoid finalizing threads, etc */
1039 mono_gc_run_finalize (o, 0);
1042 g_ptr_array_free (objs, TRUE);
1044 #elif defined(HAVE_SGEN_GC)
1045 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1047 for (i = 0; i < count; ++i) {
1048 mono_gc_run_finalize (to_finalize [i], 0);
1053 /* cleanup the reference queue */
1054 reference_queue_clear_for_domain (domain);
1056 /* printf ("DONE.\n"); */
1057 SetEvent (req->done_event);
1059 /* The event is closed in mono_domain_finalize if we get here */
1064 finalizer_thread (gpointer unused)
1067 /* Wait to be notified that there's at least one
1071 g_assert (mono_domain_get () == mono_get_root_domain ());
1073 /* An alertable wait is required so this thread can be suspended on windows */
1074 #ifdef MONO_HAS_SEMAPHORES
1075 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1077 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1080 mono_threads_perform_thread_dump ();
1082 mono_console_handle_async_ops ();
1084 #ifndef DISABLE_ATTACH
1085 mono_attach_maybe_start ();
1088 if (domains_to_finalize) {
1089 mono_finalizer_lock ();
1090 if (domains_to_finalize) {
1091 DomainFinalizationReq *req = domains_to_finalize->data;
1092 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1093 mono_finalizer_unlock ();
1095 finalize_domain_objects (req);
1097 mono_finalizer_unlock ();
1101 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1102 * before the domain is unloaded.
1104 mono_gc_invoke_finalizers ();
1106 reference_queue_proccess_all ();
1108 SetEvent (pending_done_event);
1111 SetEvent (shutdown_event);
1115 #ifndef LAZY_GC_THREAD_CREATION
1119 mono_gc_init_finalizer_thread (void)
1121 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
1122 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1128 InitializeCriticalSection (&handle_section);
1129 InitializeCriticalSection (&allocator_section);
1131 InitializeCriticalSection (&finalizer_mutex);
1132 InitializeCriticalSection (&reference_queue_mutex);
1134 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1135 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1137 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1138 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1139 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1140 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1142 mono_gc_base_init ();
1144 if (mono_gc_is_disabled ()) {
1149 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1150 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1151 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1152 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1153 g_assert_not_reached ();
1155 #ifdef MONO_HAS_SEMAPHORES
1156 MONO_SEM_INIT (&finalizer_sem, 0);
1159 #ifndef LAZY_GC_THREAD_CREATION
1160 mono_gc_init_finalizer_thread ();
1165 mono_gc_cleanup (void)
1168 g_message ("%s: cleaning up finalizer", __func__);
1172 ResetEvent (shutdown_event);
1174 if (mono_thread_internal_current () != gc_thread) {
1175 mono_gc_finalize_notify ();
1176 /* Finishing the finalizer thread, so wait a little bit... */
1177 /* MS seems to wait for about 2 seconds */
1178 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1181 /* Set a flag which the finalizer thread can check */
1182 suspend_finalizers = TRUE;
1184 /* Try to abort the thread, in the hope that it is running managed code */
1185 mono_thread_internal_stop (gc_thread);
1187 /* Wait for it to stop */
1188 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1190 if (ret == WAIT_TIMEOUT) {
1192 * The finalizer thread refused to die. There is not much we
1193 * can do here, since the runtime is shutting down so the
1194 * state the finalizer thread depends on will vanish.
1196 g_warning ("Shutting down finalizer thread timed out.");
1199 * FIXME: On unix, when the above wait returns, the thread
1200 * might still be running io-layer code, or pthreads code.
1207 /* Wait for the thread to actually exit */
1208 ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
1209 g_assert (ret == WAIT_OBJECT_0);
1213 * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
1214 * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
1216 ret = pthread_join ((gpointer)(gsize)gc_thread->tid, NULL);
1217 g_assert (ret == 0);
1222 #ifdef HAVE_BOEHM_GC
1223 GC_finalizer_notifier = NULL;
1227 mono_reference_queue_cleanup ();
1229 DeleteCriticalSection (&handle_section);
1230 DeleteCriticalSection (&allocator_section);
1231 DeleteCriticalSection (&finalizer_mutex);
1232 DeleteCriticalSection (&reference_queue_mutex);
1237 /* Null GC dummy functions */
1239 mono_gc_finalize_notify (void)
1243 void mono_gc_init (void)
1245 InitializeCriticalSection (&handle_section);
1248 void mono_gc_cleanup (void)
1255 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1257 return thread == gc_thread;
1261 * mono_gc_is_finalizer_thread:
1262 * @thread: the thread to test.
1264 * In Mono objects are finalized asynchronously on a separate thread.
1265 * This routine tests whether the @thread argument represents the
1266 * finalization thread.
1268 * Returns true if @thread is the finalization thread.
1271 mono_gc_is_finalizer_thread (MonoThread *thread)
1273 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1276 #if defined(__MACH__)
1277 static pthread_t mach_exception_thread;
1280 mono_gc_register_mach_exception_thread (pthread_t thread)
1282 mach_exception_thread = thread;
1286 mono_gc_get_mach_exception_thread (void)
1288 return mach_exception_thread;
1293 * mono_gc_parse_environment_string_extract_number:
1295 * @str: points to the first digit of the number
1296 * @out: pointer to the variable that will receive the value
1298 * Tries to extract a number from the passed string, taking in to account m, k
1301 * Returns true if passing was successful
1304 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1307 int len = strlen (str), shift = 0;
1309 gboolean is_suffix = FALSE;
1315 suffix = str [len - 1];
1330 if (!isdigit (suffix))
1336 val = strtol (str, &endptr, 10);
1338 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1339 || (errno != 0 && val == 0) || (endptr == str))
1345 if (val < 0) /* negative numbers cannot be suffixed */
1347 if (*(endptr + 1)) /* Invalid string. */
1350 unshifted = (gulong)val;
1352 if (val < 0) /* overflow */
1354 if (((gulong)val >> shift) != unshifted) /* value too large */
1362 #ifndef HAVE_SGEN_GC
1364 mono_gc_alloc_mature (MonoVTable *vtable)
1366 return mono_object_new_specific (vtable);
1371 static MonoReferenceQueue *ref_queues;
1374 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1377 /* Guard if head is changed concurrently. */
1378 while (*prev != element)
1379 prev = &(*prev)->next;
1380 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1384 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1386 RefQueueEntry *current;
1389 value->next = current;
1390 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1391 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1395 reference_queue_proccess (MonoReferenceQueue *queue)
1397 RefQueueEntry **iter = &queue->queue;
1398 RefQueueEntry *entry;
1399 while ((entry = *iter)) {
1401 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1402 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1404 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1405 mono_gchandle_free ((guint32)entry->gchandle);
1407 ref_list_remove_element (iter, entry);
1408 queue->callback (entry->user_data);
1411 iter = &entry->next;
1417 reference_queue_proccess_all (void)
1419 MonoReferenceQueue **iter;
1420 MonoReferenceQueue *queue = ref_queues;
1421 for (; queue; queue = queue->next)
1422 reference_queue_proccess (queue);
1425 EnterCriticalSection (&reference_queue_mutex);
1426 for (iter = &ref_queues; *iter;) {
1428 if (!queue->should_be_deleted) {
1429 iter = &queue->next;
1433 LeaveCriticalSection (&reference_queue_mutex);
1434 reference_queue_proccess (queue);
1437 *iter = queue->next;
1440 LeaveCriticalSection (&reference_queue_mutex);
1444 mono_reference_queue_cleanup (void)
1446 MonoReferenceQueue *queue = ref_queues;
1447 for (; queue; queue = queue->next)
1448 queue->should_be_deleted = TRUE;
1449 reference_queue_proccess_all ();
1453 reference_queue_clear_for_domain (MonoDomain *domain)
1455 MonoReferenceQueue *queue = ref_queues;
1456 for (; queue; queue = queue->next) {
1457 RefQueueEntry **iter = &queue->queue;
1458 RefQueueEntry *entry;
1459 while ((entry = *iter)) {
1462 obj = mono_gc_weak_link_get (&entry->dis_link);
1463 if (obj && mono_object_domain (obj) == domain) {
1464 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1466 obj = mono_gchandle_get_target (entry->gchandle);
1467 if (obj && mono_object_domain (obj) == domain) {
1468 mono_gchandle_free ((guint32)entry->gchandle);
1470 ref_list_remove_element (iter, entry);
1471 queue->callback (entry->user_data);
1474 iter = &entry->next;
1480 * mono_gc_reference_queue_new:
1481 * @callback callback used when processing dead entries.
1483 * Create a new reference queue used to process collected objects.
1484 * A reference queue let you queue a pair (managed object, user data)
1485 * using the mono_gc_reference_queue_add method.
1487 * Once the managed object is collected @callback will be called
1488 * in the finalizer thread with 'user data' as argument.
1490 * The callback is called without any locks held.
1493 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1495 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1496 res->callback = callback;
1498 EnterCriticalSection (&reference_queue_mutex);
1499 res->next = ref_queues;
1501 LeaveCriticalSection (&reference_queue_mutex);
1507 * mono_gc_reference_queue_add:
1508 * @queue the queue to add the reference to.
1509 * @obj the object to be watched for collection
1510 * @user_data parameter to be passed to the queue callback
1512 * Queue an object to be watched for collection, when the @obj is
1513 * collected, the callback that was registered for the @queue will
1514 * be invoked with the @obj and @user_data arguments.
1516 * @returns false if the queue is scheduled to be freed.
1519 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1521 RefQueueEntry *entry;
1522 if (queue->should_be_deleted)
1525 entry = g_new0 (RefQueueEntry, 1);
1526 entry->user_data = user_data;
1529 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1531 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1532 mono_object_register_finalizer (obj);
1535 ref_list_push (&queue->queue, entry);
1540 * mono_gc_reference_queue_free:
1541 * @queue the queue that should be deleted.
1543 * This operation signals that @queue should be deleted. This operation is deferred
1544 * as it happens on the finalizer thread.
1546 * After this call, no further objects can be queued. It's the responsibility of the
1547 * caller to make sure that no further attempt to access queue will be made.
1550 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1552 queue->should_be_deleted = TRUE;
1555 #define ptr_mask ((sizeof (void*) - 1))
1556 #define _toi(ptr) ((size_t)ptr)
1557 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1558 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1559 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1563 * @dest: address to start to clear
1564 * @size: size of the region to clear
1566 * Zero @size bytes starting at @dest.
1568 * Use this to zero memory that can hold managed pointers.
1570 * FIXME borrow faster code from some BSD libc or bionic
1573 mono_gc_bzero (void *dest, size_t size)
1575 char *p = (char*)dest;
1576 char *end = p + size;
1577 char *align_end = align_up (p);
1580 while (p < align_end)
1583 word_end = align_down (end);
1584 while (p < word_end) {
1585 *((void**)p) = NULL;
1586 p += sizeof (void*);
1596 * @dest: destination of the move
1598 * @size: size of the block to move
1600 * Move @size bytes from @src to @dest.
1601 * size MUST be a multiple of sizeof (gpointer)
1603 * FIXME borrow faster code from some BSD libc or bionic
1606 mono_gc_memmove (void *dest, const void *src, size_t size)
1609 * If dest and src are differently aligned with respect to
1610 * pointer size then it makes no sense to do aligned copying.
1611 * In fact, we would end up with unaligned loads which is
1612 * incorrect on some architectures.
1614 if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
1615 memmove (dest, src, size);
1620 * A bit of explanation on why we align only dest before doing word copies.
1621 * Pointers to managed objects must always be stored in word aligned addresses, so
1622 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1624 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
1625 char *p = (char*)dest + size;
1626 char *s = (char*)src + size;
1627 char *start = (char*)dest;
1628 char *align_end = MAX((char*)dest, (char*)align_down (p));
1631 while (p > align_end)
1634 word_start = align_up (start);
1635 while (p > word_start) {
1636 p -= sizeof (void*);
1637 s -= sizeof (void*);
1638 *((void**)p) = *((void**)s);
1644 char *p = (char*)dest;
1645 char *s = (char*)src;
1646 char *end = p + size;
1647 char *align_end = MIN ((char*)end, (char*)align_up (p));
1650 while (p < align_end)
1653 word_end = align_down (end);
1654 while (p < word_end) {
1655 *((void**)p) = *((void**)s);
1656 p += sizeof (void*);
1657 s += sizeof (void*);