2 * metadata/gc.c: GC icalls.
4 * Author: Paolo Molaro <lupus@ximian.com>
6 * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
7 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
8 * Copyright 2012 Xamarin Inc (http://www.xamarin.com)
16 #include <mono/metadata/gc-internal.h>
17 #include <mono/metadata/mono-gc.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/class-internals.h>
24 #include <mono/metadata/metadata-internals.h>
25 #include <mono/metadata/mono-mlist.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/threadpool-internals.h>
28 #include <mono/metadata/threads-types.h>
29 #include <mono/utils/mono-logger-internal.h>
30 #include <mono/metadata/gc-internal.h>
31 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
32 #include <mono/metadata/attach.h>
33 #include <mono/metadata/console-io.h>
34 #include <mono/utils/mono-semaphore.h>
35 #include <mono/utils/mono-memory-model.h>
36 #include <mono/utils/mono-counters.h>
37 #include <mono/utils/dtrace.h>
38 #include <mono/utils/mono-threads.h>
44 typedef struct DomainFinalizationReq {
47 } DomainFinalizationReq;
49 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
50 extern void (*__imp_GC_finalizer_notifier)(void);
51 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
52 extern int __imp_GC_finalize_on_demand;
53 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
56 static gboolean gc_disabled = FALSE;
58 static gboolean finalizing_root_domain = FALSE;
60 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
61 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
62 static CRITICAL_SECTION finalizer_mutex;
63 static CRITICAL_SECTION reference_queue_mutex;
65 static GSList *domains_to_finalize= NULL;
66 static MonoMList *threads_to_finalize = NULL;
68 static MonoInternalThread *gc_thread;
70 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
72 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
74 static void reference_queue_proccess_all (void);
75 static void mono_reference_queue_cleanup (void);
76 static void reference_queue_clear_for_domain (MonoDomain *domain);
78 static HANDLE pending_done_event;
79 static HANDLE shutdown_event;
85 add_thread_to_finalize (MonoInternalThread *thread)
87 mono_finalizer_lock ();
88 if (!threads_to_finalize)
89 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
90 threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
91 mono_finalizer_unlock ();
94 static gboolean suspend_finalizers = FALSE;
96 * actually, we might want to queue the finalize requests in a separate thread,
97 * but we need to be careful about the execution domain of the thread...
100 mono_gc_run_finalize (void *obj, void *data)
102 MonoObject *exc = NULL;
107 MonoMethod* finalizer = NULL;
108 MonoDomain *caller_domain = mono_domain_get ();
110 RuntimeInvokeFunction runtime_invoke;
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 mono_domain_finalizers_unlock (domain);
127 /* Already finalized somehow */
131 /* make sure the finalizer is not called again if the object is resurrected */
132 object_register_finalizer (obj, NULL);
134 if (o->vtable->klass == mono_defaults.internal_thread_class) {
135 MonoInternalThread *t = (MonoInternalThread*)o;
137 if (mono_gc_is_finalizer_internal_thread (t))
138 /* Avoid finalizing ourselves */
141 if (t->threadpool_thread && finalizing_root_domain) {
142 /* Don't finalize threadpool threads when
143 shutting down - they're finalized when the
144 threadpool shuts down. */
145 add_thread_to_finalize (t);
150 if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
152 * These can't be finalized during unloading/shutdown, since that would
153 * free the native code which can still be referenced by other
155 * FIXME: This is not perfect, objects dying at the same time as
156 * dynamic methods can still reference them even when !shutdown.
161 if (mono_runtime_get_no_exec ())
164 /* speedup later... and use a timeout */
165 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
167 /* Use _internal here, since this thread can enter a doomed appdomain */
168 mono_domain_set_internal (mono_object_domain (o));
170 /* delegates that have a native function pointer allocated are
171 * registered for finalization, but they don't have a Finalize
172 * method, because in most cases it's not needed and it's just a waste.
174 if (o->vtable->klass->delegate) {
175 MonoDelegate* del = (MonoDelegate*)o;
176 if (del->delegate_trampoline)
177 mono_delegate_free_ftnptr ((MonoDelegate*)o);
178 mono_domain_set_internal (caller_domain);
182 finalizer = mono_class_get_finalizer (o->vtable->klass);
185 /* If object has a CCW but has no finalizer, it was only
186 * registered for finalization in order to free the CCW.
187 * Else it needs the regular finalizer run.
188 * FIXME: what to do about ressurection and suppression
189 * of finalizer on object with CCW.
191 if (mono_marshal_free_ccw (o) && !finalizer) {
192 mono_domain_set_internal (caller_domain);
198 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
199 * create and precompile a wrapper which calls the finalize method using
202 if (!domain->finalize_runtime_invoke) {
203 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
205 domain->finalize_runtime_invoke = mono_compile_method (invoke);
208 runtime_invoke = domain->finalize_runtime_invoke;
210 mono_runtime_class_init (o->vtable);
212 if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
213 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
214 o->vtable->klass->name_space, o->vtable->klass->name);
217 runtime_invoke (o, NULL, &exc, NULL);
220 mono_internal_thread_unhandled_exception (exc);
222 mono_domain_set_internal (caller_domain);
226 mono_gc_finalize_threadpool_threads (void)
228 while (threads_to_finalize) {
229 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
231 /* Force finalization of the thread. */
232 thread->threadpool_thread = FALSE;
233 mono_object_register_finalizer ((MonoObject*)thread);
235 mono_gc_run_finalize (thread, NULL);
237 threads_to_finalize = mono_mlist_next (threads_to_finalize);
242 mono_gc_out_of_memory (size_t size)
245 * we could allocate at program startup some memory that we could release
246 * back to the system at this point if we're really low on memory (ie, size is
247 * lower than the memory we set apart)
249 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
255 * Some of our objects may point to a different address than the address returned by GC_malloc()
256 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
257 * This also means that in the callback we need to adjust the pointer to get back the real
259 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
260 * since that, too, can cause the underlying pointer to be offset.
263 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
270 mono_raise_exception (mono_get_exception_argument_null ("obj"));
272 domain = obj->vtable->domain;
275 /* This assertion is not valid when GC_DEBUG is defined */
276 g_assert (GC_base (obj) == (char*)obj - offset);
279 if (mono_domain_is_unloading (domain) && (callback != NULL))
281 * Can't register finalizers in a dying appdomain, since they
282 * could be invoked after the appdomain has been unloaded.
286 mono_domain_finalizers_lock (domain);
289 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
291 g_hash_table_remove (domain->finalizable_objects_hash, obj);
293 mono_domain_finalizers_unlock (domain);
295 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
296 #elif defined(HAVE_SGEN_GC)
298 mono_raise_exception (mono_get_exception_argument_null ("obj"));
301 * If we register finalizers for domains that are unloading we might
302 * end up running them while or after the domain is being cleared, so
303 * the objects will not be valid anymore.
305 if (!mono_domain_is_unloading (obj->vtable->domain))
306 mono_gc_register_for_finalization (obj, callback);
311 * mono_object_register_finalizer:
312 * @obj: object to register
314 * Records that object @obj has a finalizer, this will call the
315 * Finalize method when the garbage collector disposes the object.
319 mono_object_register_finalizer (MonoObject *obj)
321 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
322 object_register_finalizer (obj, mono_gc_run_finalize);
326 * mono_domain_finalize:
327 * @domain: the domain to finalize
328 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
330 * Request finalization of all finalizable objects inside @domain. Wait
331 * @timeout msecs for the finalization to complete.
333 * Returns: TRUE if succeeded, FALSE if there was a timeout
337 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
339 DomainFinalizationReq *req;
342 MonoInternalThread *thread = mono_thread_internal_current ();
344 if (mono_thread_internal_current () == gc_thread)
345 /* We are called from inside a finalizer, not much we can do here */
349 * No need to create another thread 'cause the finalizer thread
350 * is still working and will take care of running the finalizers
357 mono_gc_collect (mono_gc_max_generation ());
359 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
360 if (done_event == NULL) {
364 req = g_new0 (DomainFinalizationReq, 1);
365 req->domain = domain;
366 req->done_event = done_event;
368 if (domain == mono_get_root_domain ())
369 finalizing_root_domain = TRUE;
371 mono_finalizer_lock ();
373 domains_to_finalize = g_slist_append (domains_to_finalize, req);
375 mono_finalizer_unlock ();
377 /* Tell the finalizer thread to finalize this appdomain */
378 mono_gc_finalize_notify ();
384 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
385 /* printf ("WAIT RES: %d.\n", res); */
387 if (res == WAIT_IO_COMPLETION) {
388 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
390 } else if (res == WAIT_TIMEOUT) {
391 /* We leak the handle here */
398 CloseHandle (done_event);
400 if (domain == mono_get_root_domain ()) {
401 mono_thread_pool_cleanup ();
402 mono_gc_finalize_threadpool_threads ();
407 /* We don't support domain finalization without a GC */
413 ves_icall_System_GC_InternalCollect (int generation)
415 mono_gc_collect (generation);
419 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
424 mono_gc_collect (mono_gc_max_generation ());
425 return mono_gc_get_used_size ();
429 ves_icall_System_GC_KeepAlive (MonoObject *obj)
439 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
442 mono_raise_exception (mono_get_exception_argument_null ("obj"));
444 object_register_finalizer (obj, mono_gc_run_finalize);
448 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
451 mono_raise_exception (mono_get_exception_argument_null ("obj"));
453 /* delegates have no finalizers, but we register them to deal with the
454 * unmanaged->managed trampoline. We don't let the user suppress it
455 * otherwise we'd leak it.
457 if (obj->vtable->klass->delegate)
460 /* FIXME: Need to handle case where obj has COM Callable Wrapper
461 * generated for it that needs cleaned up, but user wants to suppress
462 * their derived object finalizer. */
464 object_register_finalizer (obj, NULL);
468 ves_icall_System_GC_WaitForPendingFinalizers (void)
471 if (!mono_gc_pending_finalizers ())
474 if (mono_thread_internal_current () == gc_thread)
475 /* Avoid deadlocks */
479 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
480 be the one responsible for starting it up.
482 if (gc_thread == NULL)
485 ResetEvent (pending_done_event);
486 mono_gc_finalize_notify ();
487 /* g_print ("Waiting for pending finalizers....\n"); */
488 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
489 /* g_print ("Done pending....\n"); */
494 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
497 if (!mono_gc_ephemeron_array_add (array))
498 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
503 ves_icall_System_GC_get_ephemeron_tombstone (void)
505 return mono_domain_get ()->ephemeron_tombstone;
508 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
509 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
510 static CRITICAL_SECTION allocator_section;
511 static CRITICAL_SECTION handle_section;
520 static HandleType mono_gchandle_get_type (guint32 gchandle);
523 ves_icall_System_GCHandle_GetTarget (guint32 handle)
525 return mono_gchandle_get_target (handle);
529 * if type == -1, change the target of the handle, otherwise allocate a new handle.
532 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
535 mono_gchandle_set_target (handle, obj);
536 /* the handle doesn't change */
541 return mono_gchandle_new_weakref (obj, FALSE);
542 case HANDLE_WEAK_TRACK:
543 return mono_gchandle_new_weakref (obj, TRUE);
545 return mono_gchandle_new (obj, FALSE);
547 return mono_gchandle_new (obj, TRUE);
549 g_assert_not_reached ();
555 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
557 mono_gchandle_free (handle);
561 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
565 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
567 obj = mono_gchandle_get_target (handle);
569 MonoClass *klass = mono_object_class (obj);
570 if (klass == mono_defaults.string_class) {
571 return mono_string_chars ((MonoString*)obj);
572 } else if (klass->rank) {
573 return mono_array_addr ((MonoArray*)obj, char, 0);
575 /* the C# code will check and throw the exception */
576 /* FIXME: missing !klass->blittable test, see bug #61134 */
577 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
579 return (char*)obj + sizeof (MonoObject);
586 ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
588 return mono_gc_set_allow_synchronous_major (flag);
596 guint slot_hint : 24; /* starting slot for search */
597 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
598 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
602 /* weak and weak-track arrays will be allocated in malloc memory
604 static HandleData gc_handles [] = {
605 {NULL, NULL, 0, HANDLE_WEAK, 0},
606 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
607 {NULL, NULL, 0, HANDLE_NORMAL, 0},
608 {NULL, NULL, 0, HANDLE_PINNED, 0}
611 #define lock_handles(handles) EnterCriticalSection (&handle_section)
612 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
615 find_first_unset (guint32 bitmap)
618 for (i = 0; i < 32; ++i) {
619 if (!(bitmap & (1 << i)))
626 make_root_descr_all_refs (int numbits, gboolean pinned)
632 return mono_gc_make_root_descr_all_refs (numbits);
636 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
640 lock_handles (handles);
641 if (!handles->size) {
643 if (handles->type > HANDLE_WEAK_TRACK) {
644 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
646 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
647 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
649 handles->bitmap = g_malloc0 (handles->size / 8);
652 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
653 if (handles->bitmap [slot] != 0xffffffff) {
654 i = find_first_unset (handles->bitmap [slot]);
655 handles->slot_hint = slot;
659 if (i == -1 && handles->slot_hint != 0) {
660 for (slot = 0; slot < handles->slot_hint; ++slot) {
661 if (handles->bitmap [slot] != 0xffffffff) {
662 i = find_first_unset (handles->bitmap [slot]);
663 handles->slot_hint = slot;
670 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
672 /* resize and copy the bitmap */
673 new_bitmap = g_malloc0 (new_size / 8);
674 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
675 g_free (handles->bitmap);
676 handles->bitmap = new_bitmap;
678 /* resize and copy the entries */
679 if (handles->type > HANDLE_WEAK_TRACK) {
682 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
683 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
685 mono_gc_free_fixed (handles->entries);
686 handles->entries = entries;
690 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
691 entries = g_malloc0 (sizeof (gpointer) * new_size);
692 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
693 for (i = 0; i < handles->size; ++i) {
694 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
696 mono_gc_weak_link_add (&(entries [i]), obj, track);
697 mono_gc_weak_link_remove (&(handles->entries [i]), track);
699 g_assert (!handles->entries [i]);
702 g_free (handles->entries);
703 g_free (handles->domain_ids);
704 handles->entries = entries;
705 handles->domain_ids = domain_ids;
708 /* set i and slot to the next free position */
710 slot = (handles->size + 1) / 32;
711 handles->slot_hint = handles->size + 1;
712 handles->size = new_size;
714 handles->bitmap [slot] |= 1 << i;
715 slot = slot * 32 + i;
716 handles->entries [slot] = NULL;
717 if (handles->type <= HANDLE_WEAK_TRACK) {
718 /*FIXME, what to use when obj == null?*/
719 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
721 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
723 handles->entries [slot] = obj;
726 #ifndef DISABLE_PERFCOUNTERS
727 mono_perfcounters->gc_num_handles++;
729 unlock_handles (handles);
730 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
731 res = (slot << 3) | (handles->type + 1);
732 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
738 * @obj: managed object to get a handle for
739 * @pinned: whether the object should be pinned
741 * This returns a handle that wraps the object, this is used to keep a
742 * reference to a managed object from the unmanaged world and preventing the
743 * object from being disposed.
745 * If @pinned is false the address of the object can not be obtained, if it is
746 * true the address of the object can be obtained. This will also pin the
747 * object so it will not be possible by a moving garbage collector to move the
750 * Returns: a handle that can be used to access the object from
754 mono_gchandle_new (MonoObject *obj, gboolean pinned)
756 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
760 * mono_gchandle_new_weakref:
761 * @obj: managed object to get a handle for
762 * @pinned: whether the object should be pinned
764 * This returns a weak handle that wraps the object, this is used to
765 * keep a reference to a managed object from the unmanaged world.
766 * Unlike the mono_gchandle_new the object can be reclaimed by the
767 * garbage collector. In this case the value of the GCHandle will be
770 * If @pinned is false the address of the object can not be obtained, if it is
771 * true the address of the object can be obtained. This will also pin the
772 * object so it will not be possible by a moving garbage collector to move the
775 * Returns: a handle that can be used to access the object from
779 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
781 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
787 mono_gchandle_get_type (guint32 gchandle)
789 guint type = (gchandle & 7) - 1;
795 * mono_gchandle_get_target:
796 * @gchandle: a GCHandle's handle.
798 * The handle was previously created by calling mono_gchandle_new or
799 * mono_gchandle_new_weakref.
801 * Returns a pointer to the MonoObject represented by the handle or
802 * NULL for a collected object if using a weakref handle.
805 mono_gchandle_get_target (guint32 gchandle)
807 guint slot = gchandle >> 3;
808 guint type = (gchandle & 7) - 1;
809 HandleData *handles = &gc_handles [type];
810 MonoObject *obj = NULL;
813 lock_handles (handles);
814 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
815 if (handles->type <= HANDLE_WEAK_TRACK) {
816 obj = mono_gc_weak_link_get (&handles->entries [slot]);
818 obj = handles->entries [slot];
821 /* print a warning? */
823 unlock_handles (handles);
824 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
829 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
831 guint slot = gchandle >> 3;
832 guint type = (gchandle & 7) - 1;
833 HandleData *handles = &gc_handles [type];
834 MonoObject *old_obj = NULL;
838 lock_handles (handles);
839 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
840 if (handles->type <= HANDLE_WEAK_TRACK) {
841 old_obj = handles->entries [slot];
842 if (handles->entries [slot])
843 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
845 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
846 /*FIXME, what to use when obj == null?*/
847 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
849 handles->entries [slot] = obj;
852 /* print a warning? */
854 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
855 unlock_handles (handles);
859 * mono_gchandle_is_in_domain:
860 * @gchandle: a GCHandle's handle.
861 * @domain: An application domain.
863 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
866 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
868 guint slot = gchandle >> 3;
869 guint type = (gchandle & 7) - 1;
870 HandleData *handles = &gc_handles [type];
871 gboolean result = FALSE;
874 lock_handles (handles);
875 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
876 if (handles->type <= HANDLE_WEAK_TRACK) {
877 result = domain->domain_id == handles->domain_ids [slot];
880 obj = handles->entries [slot];
884 result = domain == mono_object_domain (obj);
887 /* print a warning? */
889 unlock_handles (handles);
894 * mono_gchandle_free:
895 * @gchandle: a GCHandle's handle.
897 * Frees the @gchandle handle. If there are no outstanding
898 * references, the garbage collector can reclaim the memory of the
902 mono_gchandle_free (guint32 gchandle)
904 guint slot = gchandle >> 3;
905 guint type = (gchandle & 7) - 1;
906 HandleData *handles = &gc_handles [type];
910 lock_handles (handles);
911 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
912 if (handles->type <= HANDLE_WEAK_TRACK) {
913 if (handles->entries [slot])
914 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
916 handles->entries [slot] = NULL;
918 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
920 /* print a warning? */
922 #ifndef DISABLE_PERFCOUNTERS
923 mono_perfcounters->gc_num_handles--;
925 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
926 unlock_handles (handles);
927 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
931 * mono_gchandle_free_domain:
932 * @domain: domain that is unloading
934 * Function used internally to cleanup any GC handle for objects belonging
935 * to the specified domain during appdomain unload.
938 mono_gchandle_free_domain (MonoDomain *domain)
942 for (type = 0; type < 3; ++type) {
944 HandleData *handles = &gc_handles [type];
945 lock_handles (handles);
946 for (slot = 0; slot < handles->size; ++slot) {
947 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
949 if (type <= HANDLE_WEAK_TRACK) {
950 if (domain->domain_id == handles->domain_ids [slot]) {
951 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
952 if (handles->entries [slot])
953 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
956 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
957 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
958 handles->entries [slot] = NULL;
962 unlock_handles (handles);
968 GCHandle_CheckCurrentDomain (guint32 gchandle)
970 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
975 #ifdef MONO_HAS_SEMAPHORES
976 static MonoSemType finalizer_sem;
978 static HANDLE finalizer_event;
979 static volatile gboolean finished=FALSE;
982 mono_gc_finalize_notify (void)
985 g_message ( "%s: prodding finalizer", __func__);
988 #ifdef MONO_HAS_SEMAPHORES
989 MONO_SEM_POST (&finalizer_sem);
991 SetEvent (finalizer_event);
998 collect_objects (gpointer key, gpointer value, gpointer user_data)
1000 GPtrArray *arr = (GPtrArray*)user_data;
1001 g_ptr_array_add (arr, key);
1007 * finalize_domain_objects:
1009 * Run the finalizers of all finalizable objects in req->domain.
1012 finalize_domain_objects (DomainFinalizationReq *req)
1014 MonoDomain *domain = req->domain;
1017 #define NUM_FOBJECTS 64
1018 MonoObject *to_finalize [NUM_FOBJECTS];
1022 /* Process finalizers which are already in the queue */
1023 mono_gc_invoke_finalizers ();
1025 #ifdef HAVE_BOEHM_GC
1026 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1030 * Since the domain is unloading, nobody is allowed to put
1031 * new entries into the hash table. But finalize_object might
1032 * remove entries from the hash table, so we make a copy.
1034 objs = g_ptr_array_new ();
1035 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1036 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1038 for (i = 0; i < objs->len; ++i) {
1039 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1040 /* FIXME: Avoid finalizing threads, etc */
1041 mono_gc_run_finalize (o, 0);
1044 g_ptr_array_free (objs, TRUE);
1046 #elif defined(HAVE_SGEN_GC)
1047 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1049 for (i = 0; i < count; ++i) {
1050 mono_gc_run_finalize (to_finalize [i], 0);
1055 /* cleanup the reference queue */
1056 reference_queue_clear_for_domain (domain);
1058 /* printf ("DONE.\n"); */
1059 SetEvent (req->done_event);
1061 /* The event is closed in mono_domain_finalize if we get here */
1066 finalizer_thread (gpointer unused)
1069 /* Wait to be notified that there's at least one
1073 g_assert (mono_domain_get () == mono_get_root_domain ());
1075 /* An alertable wait is required so this thread can be suspended on windows */
1076 #ifdef MONO_HAS_SEMAPHORES
1077 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1079 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1082 mono_threads_perform_thread_dump ();
1084 mono_console_handle_async_ops ();
1086 #ifndef DISABLE_ATTACH
1087 mono_attach_maybe_start ();
1090 if (domains_to_finalize) {
1091 mono_finalizer_lock ();
1092 if (domains_to_finalize) {
1093 DomainFinalizationReq *req = domains_to_finalize->data;
1094 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1095 mono_finalizer_unlock ();
1097 finalize_domain_objects (req);
1099 mono_finalizer_unlock ();
1103 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1104 * before the domain is unloaded.
1106 mono_gc_invoke_finalizers ();
1108 reference_queue_proccess_all ();
1110 SetEvent (pending_done_event);
1113 SetEvent (shutdown_event);
1117 #ifndef LAZY_GC_THREAD_CREATION
1121 mono_gc_init_finalizer_thread (void)
1123 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
1124 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1130 InitializeCriticalSection (&handle_section);
1131 InitializeCriticalSection (&allocator_section);
1133 InitializeCriticalSection (&finalizer_mutex);
1134 InitializeCriticalSection (&reference_queue_mutex);
1136 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1137 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1139 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1140 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1141 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1142 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1144 mono_gc_base_init ();
1146 if (mono_gc_is_disabled ()) {
1151 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1152 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1153 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1154 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1155 g_assert_not_reached ();
1157 #ifdef MONO_HAS_SEMAPHORES
1158 MONO_SEM_INIT (&finalizer_sem, 0);
1161 #ifndef LAZY_GC_THREAD_CREATION
1162 mono_gc_init_finalizer_thread ();
1167 mono_gc_cleanup (void)
1170 g_message ("%s: cleaning up finalizer", __func__);
1174 ResetEvent (shutdown_event);
1176 if (mono_thread_internal_current () != gc_thread) {
1177 mono_gc_finalize_notify ();
1178 /* Finishing the finalizer thread, so wait a little bit... */
1179 /* MS seems to wait for about 2 seconds */
1180 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1183 /* Set a flag which the finalizer thread can check */
1184 suspend_finalizers = TRUE;
1186 /* Try to abort the thread, in the hope that it is running managed code */
1187 mono_thread_internal_stop (gc_thread);
1189 /* Wait for it to stop */
1190 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1192 if (ret == WAIT_TIMEOUT) {
1194 * The finalizer thread refused to die. There is not much we
1195 * can do here, since the runtime is shutting down so the
1196 * state the finalizer thread depends on will vanish.
1198 g_warning ("Shutting down finalizer thread timed out.");
1201 * FIXME: On unix, when the above wait returns, the thread
1202 * might still be running io-layer code, or pthreads code.
1209 /* Wait for the thread to actually exit */
1210 ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
1211 g_assert (ret == WAIT_OBJECT_0);
1215 * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
1216 * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
1218 ret = pthread_join ((MonoNativeThreadId)(gpointer)(gsize)gc_thread->tid, NULL);
1219 g_assert (ret == 0);
1224 #ifdef HAVE_BOEHM_GC
1225 GC_finalizer_notifier = NULL;
1229 mono_reference_queue_cleanup ();
1231 DeleteCriticalSection (&handle_section);
1232 DeleteCriticalSection (&allocator_section);
1233 DeleteCriticalSection (&finalizer_mutex);
1234 DeleteCriticalSection (&reference_queue_mutex);
1239 /* Null GC dummy functions */
1241 mono_gc_finalize_notify (void)
1245 void mono_gc_init (void)
1247 InitializeCriticalSection (&handle_section);
1250 void mono_gc_cleanup (void)
1257 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1259 return thread == gc_thread;
1263 * mono_gc_is_finalizer_thread:
1264 * @thread: the thread to test.
1266 * In Mono objects are finalized asynchronously on a separate thread.
1267 * This routine tests whether the @thread argument represents the
1268 * finalization thread.
1270 * Returns true if @thread is the finalization thread.
1273 mono_gc_is_finalizer_thread (MonoThread *thread)
1275 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1278 #if defined(__MACH__)
1279 static pthread_t mach_exception_thread;
1282 mono_gc_register_mach_exception_thread (pthread_t thread)
1284 mach_exception_thread = thread;
1288 mono_gc_get_mach_exception_thread (void)
1290 return mach_exception_thread;
1295 * mono_gc_parse_environment_string_extract_number:
1297 * @str: points to the first digit of the number
1298 * @out: pointer to the variable that will receive the value
1300 * Tries to extract a number from the passed string, taking in to account m, k
1303 * Returns true if passing was successful
1306 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1309 int len = strlen (str), shift = 0;
1311 gboolean is_suffix = FALSE;
1317 suffix = str [len - 1];
1332 if (!isdigit (suffix))
1338 val = strtol (str, &endptr, 10);
1340 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1341 || (errno != 0 && val == 0) || (endptr == str))
1347 if (val < 0) /* negative numbers cannot be suffixed */
1349 if (*(endptr + 1)) /* Invalid string. */
1352 unshifted = (gulong)val;
1354 if (val < 0) /* overflow */
1356 if (((gulong)val >> shift) != unshifted) /* value too large */
1364 #ifndef HAVE_SGEN_GC
1366 mono_gc_alloc_mature (MonoVTable *vtable)
1368 return mono_object_new_specific (vtable);
1373 static MonoReferenceQueue *ref_queues;
1376 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1379 /* Guard if head is changed concurrently. */
1380 while (*prev != element)
1381 prev = &(*prev)->next;
1382 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1386 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1388 RefQueueEntry *current;
1391 value->next = current;
1392 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1393 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1397 reference_queue_proccess (MonoReferenceQueue *queue)
1399 RefQueueEntry **iter = &queue->queue;
1400 RefQueueEntry *entry;
1401 while ((entry = *iter)) {
1403 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1404 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1406 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1407 mono_gchandle_free ((guint32)entry->gchandle);
1409 ref_list_remove_element (iter, entry);
1410 queue->callback (entry->user_data);
1413 iter = &entry->next;
1419 reference_queue_proccess_all (void)
1421 MonoReferenceQueue **iter;
1422 MonoReferenceQueue *queue = ref_queues;
1423 for (; queue; queue = queue->next)
1424 reference_queue_proccess (queue);
1427 EnterCriticalSection (&reference_queue_mutex);
1428 for (iter = &ref_queues; *iter;) {
1430 if (!queue->should_be_deleted) {
1431 iter = &queue->next;
1435 LeaveCriticalSection (&reference_queue_mutex);
1436 reference_queue_proccess (queue);
1439 *iter = queue->next;
1442 LeaveCriticalSection (&reference_queue_mutex);
1446 mono_reference_queue_cleanup (void)
1448 MonoReferenceQueue *queue = ref_queues;
1449 for (; queue; queue = queue->next)
1450 queue->should_be_deleted = TRUE;
1451 reference_queue_proccess_all ();
1455 reference_queue_clear_for_domain (MonoDomain *domain)
1457 MonoReferenceQueue *queue = ref_queues;
1458 for (; queue; queue = queue->next) {
1459 RefQueueEntry **iter = &queue->queue;
1460 RefQueueEntry *entry;
1461 while ((entry = *iter)) {
1464 obj = mono_gc_weak_link_get (&entry->dis_link);
1465 if (obj && mono_object_domain (obj) == domain) {
1466 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1468 obj = mono_gchandle_get_target (entry->gchandle);
1469 if (obj && mono_object_domain (obj) == domain) {
1470 mono_gchandle_free ((guint32)entry->gchandle);
1472 ref_list_remove_element (iter, entry);
1473 queue->callback (entry->user_data);
1476 iter = &entry->next;
1482 * mono_gc_reference_queue_new:
1483 * @callback callback used when processing dead entries.
1485 * Create a new reference queue used to process collected objects.
1486 * A reference queue let you queue a pair (managed object, user data)
1487 * using the mono_gc_reference_queue_add method.
1489 * Once the managed object is collected @callback will be called
1490 * in the finalizer thread with 'user data' as argument.
1492 * The callback is called without any locks held.
1495 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1497 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1498 res->callback = callback;
1500 EnterCriticalSection (&reference_queue_mutex);
1501 res->next = ref_queues;
1503 LeaveCriticalSection (&reference_queue_mutex);
1509 * mono_gc_reference_queue_add:
1510 * @queue the queue to add the reference to.
1511 * @obj the object to be watched for collection
1512 * @user_data parameter to be passed to the queue callback
1514 * Queue an object to be watched for collection, when the @obj is
1515 * collected, the callback that was registered for the @queue will
1516 * be invoked with the @obj and @user_data arguments.
1518 * @returns false if the queue is scheduled to be freed.
1521 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1523 RefQueueEntry *entry;
1524 if (queue->should_be_deleted)
1527 entry = g_new0 (RefQueueEntry, 1);
1528 entry->user_data = user_data;
1531 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1533 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1534 mono_object_register_finalizer (obj);
1537 ref_list_push (&queue->queue, entry);
1542 * mono_gc_reference_queue_free:
1543 * @queue the queue that should be deleted.
1545 * This operation signals that @queue should be deleted. This operation is deferred
1546 * as it happens on the finalizer thread.
1548 * After this call, no further objects can be queued. It's the responsibility of the
1549 * caller to make sure that no further attempt to access queue will be made.
1552 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1554 queue->should_be_deleted = TRUE;
1557 #define ptr_mask ((sizeof (void*) - 1))
1558 #define _toi(ptr) ((size_t)ptr)
1559 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1560 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1561 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1565 * @dest: address to start to clear
1566 * @size: size of the region to clear
1568 * Zero @size bytes starting at @dest.
1570 * Use this to zero memory that can hold managed pointers.
1572 * FIXME borrow faster code from some BSD libc or bionic
1575 mono_gc_bzero (void *dest, size_t size)
1577 char *p = (char*)dest;
1578 char *end = p + size;
1579 char *align_end = align_up (p);
1582 while (p < align_end)
1585 word_end = align_down (end);
1586 while (p < word_end) {
1587 *((void**)p) = NULL;
1588 p += sizeof (void*);
1598 * @dest: destination of the move
1600 * @size: size of the block to move
1602 * Move @size bytes from @src to @dest.
1603 * size MUST be a multiple of sizeof (gpointer)
1605 * FIXME borrow faster code from some BSD libc or bionic
1608 mono_gc_memmove (void *dest, const void *src, size_t size)
1611 * If dest and src are differently aligned with respect to
1612 * pointer size then it makes no sense to do aligned copying.
1613 * In fact, we would end up with unaligned loads which is
1614 * incorrect on some architectures.
1616 if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
1617 memmove (dest, src, size);
1622 * A bit of explanation on why we align only dest before doing word copies.
1623 * Pointers to managed objects must always be stored in word aligned addresses, so
1624 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1626 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
1627 char *p = (char*)dest + size;
1628 char *s = (char*)src + size;
1629 char *start = (char*)dest;
1630 char *align_end = MAX((char*)dest, (char*)align_down (p));
1633 while (p > align_end)
1636 word_start = align_up (start);
1637 while (p > word_start) {
1638 p -= sizeof (void*);
1639 s -= sizeof (void*);
1640 *((void**)p) = *((void**)s);
1646 char *p = (char*)dest;
1647 char *s = (char*)src;
1648 char *end = p + size;
1649 char *align_end = MIN ((char*)end, (char*)align_up (p));
1652 while (p < align_end)
1655 word_end = align_down (end);
1656 while (p < word_end) {
1657 *((void**)p) = *((void**)s);
1658 p += sizeof (void*);
1659 s += sizeof (void*);