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>
42 typedef struct DomainFinalizationReq {
45 } DomainFinalizationReq;
47 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
48 extern void (*__imp_GC_finalizer_notifier)(void);
49 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
50 extern int __imp_GC_finalize_on_demand;
51 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
54 static gboolean gc_disabled = FALSE;
56 static gboolean finalizing_root_domain = FALSE;
58 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
59 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
60 static CRITICAL_SECTION finalizer_mutex;
61 static CRITICAL_SECTION reference_queue_mutex;
63 static GSList *domains_to_finalize= NULL;
64 static MonoMList *threads_to_finalize = NULL;
66 static MonoInternalThread *gc_thread;
68 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
70 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
72 static void reference_queue_proccess_all (void);
73 static void mono_reference_queue_cleanup (void);
74 static void reference_queue_clear_for_domain (MonoDomain *domain);
76 static HANDLE pending_done_event;
77 static HANDLE shutdown_event;
83 add_thread_to_finalize (MonoInternalThread *thread)
85 mono_finalizer_lock ();
86 if (!threads_to_finalize)
87 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
88 threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
89 mono_finalizer_unlock ();
92 static gboolean suspend_finalizers = FALSE;
94 * actually, we might want to queue the finalize requests in a separate thread,
95 * but we need to be careful about the execution domain of the thread...
98 mono_gc_run_finalize (void *obj, void *data)
100 MonoObject *exc = NULL;
105 MonoMethod* finalizer = NULL;
106 MonoDomain *caller_domain = mono_domain_get ();
108 RuntimeInvokeFunction runtime_invoke;
109 GSList *l, *refs = NULL;
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 refs = mono_gc_remove_weak_track_object (domain, o);
125 mono_domain_finalizers_unlock (domain);
128 /* Already finalized somehow */
134 * Support for GCHandles of type WeakTrackResurrection:
136 * Its not exactly clear how these are supposed to work, or how their
137 * semantics can be implemented. We only implement one crucial thing:
138 * these handles are only cleared after the finalizer has ran.
140 for (l = refs; l; l = l->next) {
141 guint32 gchandle = GPOINTER_TO_UINT (l->data);
143 mono_gchandle_set_target (gchandle, o);
149 /* make sure the finalizer is not called again if the object is resurrected */
150 object_register_finalizer (obj, NULL);
152 if (o->vtable->klass == mono_defaults.internal_thread_class) {
153 MonoInternalThread *t = (MonoInternalThread*)o;
155 if (mono_gc_is_finalizer_internal_thread (t))
156 /* Avoid finalizing ourselves */
159 if (t->threadpool_thread && finalizing_root_domain) {
160 /* Don't finalize threadpool threads when
161 shutting down - they're finalized when the
162 threadpool shuts down. */
163 add_thread_to_finalize (t);
168 if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
170 * These can't be finalized during unloading/shutdown, since that would
171 * free the native code which can still be referenced by other
173 * FIXME: This is not perfect, objects dying at the same time as
174 * dynamic methods can still reference them even when !shutdown.
179 if (mono_runtime_get_no_exec ())
182 /* speedup later... and use a timeout */
183 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
185 /* Use _internal here, since this thread can enter a doomed appdomain */
186 mono_domain_set_internal (mono_object_domain (o));
188 /* delegates that have a native function pointer allocated are
189 * registered for finalization, but they don't have a Finalize
190 * method, because in most cases it's not needed and it's just a waste.
192 if (o->vtable->klass->delegate) {
193 MonoDelegate* del = (MonoDelegate*)o;
194 if (del->delegate_trampoline)
195 mono_delegate_free_ftnptr ((MonoDelegate*)o);
196 mono_domain_set_internal (caller_domain);
200 finalizer = mono_class_get_finalizer (o->vtable->klass);
203 /* If object has a CCW but has no finalizer, it was only
204 * registered for finalization in order to free the CCW.
205 * Else it needs the regular finalizer run.
206 * FIXME: what to do about ressurection and suppression
207 * of finalizer on object with CCW.
209 if (mono_marshal_free_ccw (o) && !finalizer) {
210 mono_domain_set_internal (caller_domain);
216 * To avoid the locking plus the other overhead of mono_runtime_invoke (),
217 * create and precompile a wrapper which calls the finalize method using
220 if (!domain->finalize_runtime_invoke) {
221 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
223 domain->finalize_runtime_invoke = mono_compile_method (invoke);
226 runtime_invoke = domain->finalize_runtime_invoke;
228 mono_runtime_class_init (o->vtable);
230 runtime_invoke (o, NULL, &exc, NULL);
233 mono_internal_thread_unhandled_exception (exc);
235 mono_domain_set_internal (caller_domain);
239 mono_gc_finalize_threadpool_threads (void)
241 while (threads_to_finalize) {
242 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
244 /* Force finalization of the thread. */
245 thread->threadpool_thread = FALSE;
246 mono_object_register_finalizer ((MonoObject*)thread);
248 mono_gc_run_finalize (thread, NULL);
250 threads_to_finalize = mono_mlist_next (threads_to_finalize);
255 mono_gc_out_of_memory (size_t size)
258 * we could allocate at program startup some memory that we could release
259 * back to the system at this point if we're really low on memory (ie, size is
260 * lower than the memory we set apart)
262 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
268 * Some of our objects may point to a different address than the address returned by GC_malloc()
269 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
270 * This also means that in the callback we need to adjust the pointer to get back the real
272 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
273 * since that, too, can cause the underlying pointer to be offset.
276 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
283 mono_raise_exception (mono_get_exception_argument_null ("obj"));
285 domain = obj->vtable->domain;
288 /* This assertion is not valid when GC_DEBUG is defined */
289 g_assert (GC_base (obj) == (char*)obj - offset);
292 if (mono_domain_is_unloading (domain) && (callback != NULL))
294 * Can't register finalizers in a dying appdomain, since they
295 * could be invoked after the appdomain has been unloaded.
299 mono_domain_finalizers_lock (domain);
302 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
304 g_hash_table_remove (domain->finalizable_objects_hash, obj);
306 mono_domain_finalizers_unlock (domain);
308 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
309 #elif defined(HAVE_SGEN_GC)
311 mono_raise_exception (mono_get_exception_argument_null ("obj"));
314 * If we register finalizers for domains that are unloading we might
315 * end up running them while or after the domain is being cleared, so
316 * the objects will not be valid anymore.
318 if (!mono_domain_is_unloading (obj->vtable->domain))
319 mono_gc_register_for_finalization (obj, callback);
324 * mono_object_register_finalizer:
325 * @obj: object to register
327 * Records that object @obj has a finalizer, this will call the
328 * Finalize method when the garbage collector disposes the object.
332 mono_object_register_finalizer (MonoObject *obj)
334 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
335 object_register_finalizer (obj, mono_gc_run_finalize);
339 * mono_domain_finalize:
340 * @domain: the domain to finalize
341 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
343 * Request finalization of all finalizable objects inside @domain. Wait
344 * @timeout msecs for the finalization to complete.
346 * Returns: TRUE if succeeded, FALSE if there was a timeout
350 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
352 DomainFinalizationReq *req;
355 MonoInternalThread *thread = mono_thread_internal_current ();
357 if (mono_thread_internal_current () == gc_thread)
358 /* We are called from inside a finalizer, not much we can do here */
362 * No need to create another thread 'cause the finalizer thread
363 * is still working and will take care of running the finalizers
370 mono_gc_collect (mono_gc_max_generation ());
372 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
373 if (done_event == NULL) {
377 req = g_new0 (DomainFinalizationReq, 1);
378 req->domain = domain;
379 req->done_event = done_event;
381 if (domain == mono_get_root_domain ())
382 finalizing_root_domain = TRUE;
384 mono_finalizer_lock ();
386 domains_to_finalize = g_slist_append (domains_to_finalize, req);
388 mono_finalizer_unlock ();
390 /* Tell the finalizer thread to finalize this appdomain */
391 mono_gc_finalize_notify ();
397 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
398 /* printf ("WAIT RES: %d.\n", res); */
400 if (res == WAIT_IO_COMPLETION) {
401 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
403 } else if (res == WAIT_TIMEOUT) {
404 /* We leak the handle here */
411 CloseHandle (done_event);
413 if (domain == mono_get_root_domain ()) {
414 mono_thread_pool_cleanup ();
415 mono_gc_finalize_threadpool_threads ();
420 /* We don't support domain finalization without a GC */
426 ves_icall_System_GC_InternalCollect (int generation)
428 mono_gc_collect (generation);
432 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
437 mono_gc_collect (mono_gc_max_generation ());
438 return mono_gc_get_used_size ();
442 ves_icall_System_GC_KeepAlive (MonoObject *obj)
452 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
455 mono_raise_exception (mono_get_exception_argument_null ("obj"));
457 object_register_finalizer (obj, mono_gc_run_finalize);
461 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
464 mono_raise_exception (mono_get_exception_argument_null ("obj"));
466 /* delegates have no finalizers, but we register them to deal with the
467 * unmanaged->managed trampoline. We don't let the user suppress it
468 * otherwise we'd leak it.
470 if (obj->vtable->klass->delegate)
473 /* FIXME: Need to handle case where obj has COM Callable Wrapper
474 * generated for it that needs cleaned up, but user wants to suppress
475 * their derived object finalizer. */
477 object_register_finalizer (obj, NULL);
481 ves_icall_System_GC_WaitForPendingFinalizers (void)
484 if (!mono_gc_pending_finalizers ())
487 if (mono_thread_internal_current () == gc_thread)
488 /* Avoid deadlocks */
492 If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
493 be the one responsible for starting it up.
495 if (gc_thread == NULL)
498 ResetEvent (pending_done_event);
499 mono_gc_finalize_notify ();
500 /* g_print ("Waiting for pending finalizers....\n"); */
501 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
502 /* g_print ("Done pending....\n"); */
507 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
510 if (!mono_gc_ephemeron_array_add (array))
511 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
516 ves_icall_System_GC_get_ephemeron_tombstone (void)
518 return mono_domain_get ()->ephemeron_tombstone;
521 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
522 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
523 static CRITICAL_SECTION allocator_section;
524 static CRITICAL_SECTION handle_section;
533 static HandleType mono_gchandle_get_type (guint32 gchandle);
536 ves_icall_System_GCHandle_GetTarget (guint32 handle)
538 return mono_gchandle_get_target (handle);
542 * if type == -1, change the target of the handle, otherwise allocate a new handle.
545 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
548 mono_gchandle_set_target (handle, obj);
549 /* the handle doesn't change */
554 return mono_gchandle_new_weakref (obj, FALSE);
555 case HANDLE_WEAK_TRACK:
556 return mono_gchandle_new_weakref (obj, TRUE);
558 return mono_gchandle_new (obj, FALSE);
560 return mono_gchandle_new (obj, TRUE);
562 g_assert_not_reached ();
568 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
570 mono_gchandle_free (handle);
574 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
578 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
580 obj = mono_gchandle_get_target (handle);
582 MonoClass *klass = mono_object_class (obj);
583 if (klass == mono_defaults.string_class) {
584 return mono_string_chars ((MonoString*)obj);
585 } else if (klass->rank) {
586 return mono_array_addr ((MonoArray*)obj, char, 0);
588 /* the C# code will check and throw the exception */
589 /* FIXME: missing !klass->blittable test, see bug #61134 */
590 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
592 return (char*)obj + sizeof (MonoObject);
603 guint slot_hint : 24; /* starting slot for search */
604 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
605 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
609 /* weak and weak-track arrays will be allocated in malloc memory
611 static HandleData gc_handles [] = {
612 {NULL, NULL, 0, HANDLE_WEAK, 0},
613 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
614 {NULL, NULL, 0, HANDLE_NORMAL, 0},
615 {NULL, NULL, 0, HANDLE_PINNED, 0}
618 #define lock_handles(handles) EnterCriticalSection (&handle_section)
619 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
622 find_first_unset (guint32 bitmap)
625 for (i = 0; i < 32; ++i) {
626 if (!(bitmap & (1 << i)))
633 make_root_descr_all_refs (int numbits, gboolean pinned)
639 return mono_gc_make_root_descr_all_refs (numbits);
643 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
647 lock_handles (handles);
648 if (!handles->size) {
650 if (handles->type > HANDLE_WEAK_TRACK) {
651 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
653 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
654 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
656 handles->bitmap = g_malloc0 (handles->size / 8);
659 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
660 if (handles->bitmap [slot] != 0xffffffff) {
661 i = find_first_unset (handles->bitmap [slot]);
662 handles->slot_hint = slot;
666 if (i == -1 && handles->slot_hint != 0) {
667 for (slot = 0; slot < handles->slot_hint; ++slot) {
668 if (handles->bitmap [slot] != 0xffffffff) {
669 i = find_first_unset (handles->bitmap [slot]);
670 handles->slot_hint = slot;
677 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
679 /* resize and copy the bitmap */
680 new_bitmap = g_malloc0 (new_size / 8);
681 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
682 g_free (handles->bitmap);
683 handles->bitmap = new_bitmap;
685 /* resize and copy the entries */
686 if (handles->type > HANDLE_WEAK_TRACK) {
689 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
690 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
692 mono_gc_free_fixed (handles->entries);
693 handles->entries = entries;
697 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
698 entries = g_malloc (sizeof (gpointer) * new_size);
699 /* we disable GC because we could lose some disappearing link updates */
701 mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
702 mono_gc_bzero (entries + handles->size, sizeof (gpointer) * handles->size);
703 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
704 for (i = 0; i < handles->size; ++i) {
705 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
706 if (handles->entries [i])
707 mono_gc_weak_link_remove (&(handles->entries [i]));
708 /*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]);*/
710 mono_gc_weak_link_add (&(entries [i]), obj, track);
713 g_free (handles->entries);
714 g_free (handles->domain_ids);
715 handles->entries = entries;
716 handles->domain_ids = domain_ids;
720 /* set i and slot to the next free position */
722 slot = (handles->size + 1) / 32;
723 handles->slot_hint = handles->size + 1;
724 handles->size = new_size;
726 handles->bitmap [slot] |= 1 << i;
727 slot = slot * 32 + i;
728 handles->entries [slot] = obj;
729 if (handles->type <= HANDLE_WEAK_TRACK) {
730 /*FIXME, what to use when obj == null?*/
731 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
733 mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
736 mono_perfcounters->gc_num_handles++;
737 unlock_handles (handles);
738 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
739 res = (slot << 3) | (handles->type + 1);
740 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
746 * @obj: managed object to get a handle for
747 * @pinned: whether the object should be pinned
749 * This returns a handle that wraps the object, this is used to keep a
750 * reference to a managed object from the unmanaged world and preventing the
751 * object from being disposed.
753 * If @pinned is false the address of the object can not be obtained, if it is
754 * true the address of the object can be obtained. This will also pin the
755 * object so it will not be possible by a moving garbage collector to move the
758 * Returns: a handle that can be used to access the object from
762 mono_gchandle_new (MonoObject *obj, gboolean pinned)
764 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
768 * mono_gchandle_new_weakref:
769 * @obj: managed object to get a handle for
770 * @pinned: whether the object should be pinned
772 * This returns a weak handle that wraps the object, this is used to
773 * keep a reference to a managed object from the unmanaged world.
774 * Unlike the mono_gchandle_new the object can be reclaimed by the
775 * garbage collector. In this case the value of the GCHandle will be
778 * If @pinned is false the address of the object can not be obtained, if it is
779 * true the address of the object can be obtained. This will also pin the
780 * object so it will not be possible by a moving garbage collector to move the
783 * Returns: a handle that can be used to access the object from
787 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
789 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
792 if (track_resurrection)
793 mono_gc_add_weak_track_handle (obj, handle);
800 mono_gchandle_get_type (guint32 gchandle)
802 guint type = (gchandle & 7) - 1;
808 * mono_gchandle_get_target:
809 * @gchandle: a GCHandle's handle.
811 * The handle was previously created by calling mono_gchandle_new or
812 * mono_gchandle_new_weakref.
814 * Returns a pointer to the MonoObject represented by the handle or
815 * NULL for a collected object if using a weakref handle.
818 mono_gchandle_get_target (guint32 gchandle)
820 guint slot = gchandle >> 3;
821 guint type = (gchandle & 7) - 1;
822 HandleData *handles = &gc_handles [type];
823 MonoObject *obj = NULL;
826 lock_handles (handles);
827 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
828 if (handles->type <= HANDLE_WEAK_TRACK) {
829 obj = mono_gc_weak_link_get (&handles->entries [slot]);
831 obj = handles->entries [slot];
834 /* print a warning? */
836 unlock_handles (handles);
837 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
842 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
844 guint slot = gchandle >> 3;
845 guint type = (gchandle & 7) - 1;
846 HandleData *handles = &gc_handles [type];
847 MonoObject *old_obj = NULL;
851 lock_handles (handles);
852 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
853 if (handles->type <= HANDLE_WEAK_TRACK) {
854 old_obj = handles->entries [slot];
855 if (handles->entries [slot])
856 mono_gc_weak_link_remove (&handles->entries [slot]);
858 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
859 /*FIXME, what to use when obj == null?*/
860 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
862 handles->entries [slot] = obj;
865 /* print a warning? */
867 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
868 unlock_handles (handles);
871 if (type == HANDLE_WEAK_TRACK)
872 mono_gc_change_weak_track_handle (old_obj, obj, gchandle);
877 * mono_gchandle_is_in_domain:
878 * @gchandle: a GCHandle's handle.
879 * @domain: An application domain.
881 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
884 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
886 guint slot = gchandle >> 3;
887 guint type = (gchandle & 7) - 1;
888 HandleData *handles = &gc_handles [type];
889 gboolean result = FALSE;
892 lock_handles (handles);
893 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
894 if (handles->type <= HANDLE_WEAK_TRACK) {
895 result = domain->domain_id == handles->domain_ids [slot];
898 obj = handles->entries [slot];
902 result = domain == mono_object_domain (obj);
905 /* print a warning? */
907 unlock_handles (handles);
912 * mono_gchandle_free:
913 * @gchandle: a GCHandle's handle.
915 * Frees the @gchandle handle. If there are no outstanding
916 * references, the garbage collector can reclaim the memory of the
920 mono_gchandle_free (guint32 gchandle)
922 guint slot = gchandle >> 3;
923 guint type = (gchandle & 7) - 1;
924 HandleData *handles = &gc_handles [type];
928 if (type == HANDLE_WEAK_TRACK)
929 mono_gc_remove_weak_track_handle (gchandle);
932 lock_handles (handles);
933 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
934 if (handles->type <= HANDLE_WEAK_TRACK) {
935 if (handles->entries [slot])
936 mono_gc_weak_link_remove (&handles->entries [slot]);
938 handles->entries [slot] = NULL;
940 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
942 /* print a warning? */
944 mono_perfcounters->gc_num_handles--;
945 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
946 unlock_handles (handles);
947 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
951 * mono_gchandle_free_domain:
952 * @domain: domain that is unloading
954 * Function used internally to cleanup any GC handle for objects belonging
955 * to the specified domain during appdomain unload.
958 mono_gchandle_free_domain (MonoDomain *domain)
962 for (type = 0; type < 3; ++type) {
964 HandleData *handles = &gc_handles [type];
965 lock_handles (handles);
966 for (slot = 0; slot < handles->size; ++slot) {
967 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
969 if (type <= HANDLE_WEAK_TRACK) {
970 if (domain->domain_id == handles->domain_ids [slot]) {
971 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
972 if (handles->entries [slot])
973 mono_gc_weak_link_remove (&handles->entries [slot]);
976 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
977 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
978 handles->entries [slot] = NULL;
982 unlock_handles (handles);
988 GCHandle_CheckCurrentDomain (guint32 gchandle)
990 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
995 #ifdef MONO_HAS_SEMAPHORES
996 static MonoSemType finalizer_sem;
998 static HANDLE finalizer_event;
999 static volatile gboolean finished=FALSE;
1002 mono_gc_finalize_notify (void)
1005 g_message ( "%s: prodding finalizer", __func__);
1008 #ifdef MONO_HAS_SEMAPHORES
1009 MONO_SEM_POST (&finalizer_sem);
1011 SetEvent (finalizer_event);
1015 #ifdef HAVE_BOEHM_GC
1018 collect_objects (gpointer key, gpointer value, gpointer user_data)
1020 GPtrArray *arr = (GPtrArray*)user_data;
1021 g_ptr_array_add (arr, key);
1027 * finalize_domain_objects:
1029 * Run the finalizers of all finalizable objects in req->domain.
1032 finalize_domain_objects (DomainFinalizationReq *req)
1034 MonoDomain *domain = req->domain;
1037 #define NUM_FOBJECTS 64
1038 MonoObject *to_finalize [NUM_FOBJECTS];
1042 /* Process finalizers which are already in the queue */
1043 mono_gc_invoke_finalizers ();
1045 #ifdef HAVE_BOEHM_GC
1046 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1050 * Since the domain is unloading, nobody is allowed to put
1051 * new entries into the hash table. But finalize_object might
1052 * remove entries from the hash table, so we make a copy.
1054 objs = g_ptr_array_new ();
1055 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1056 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1058 for (i = 0; i < objs->len; ++i) {
1059 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1060 /* FIXME: Avoid finalizing threads, etc */
1061 mono_gc_run_finalize (o, 0);
1064 g_ptr_array_free (objs, TRUE);
1066 #elif defined(HAVE_SGEN_GC)
1067 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1069 for (i = 0; i < count; ++i) {
1070 mono_gc_run_finalize (to_finalize [i], 0);
1075 /* cleanup the reference queue */
1076 reference_queue_clear_for_domain (domain);
1078 /* printf ("DONE.\n"); */
1079 SetEvent (req->done_event);
1081 /* The event is closed in mono_domain_finalize if we get here */
1086 finalizer_thread (gpointer unused)
1089 /* Wait to be notified that there's at least one
1093 g_assert (mono_domain_get () == mono_get_root_domain ());
1095 /* An alertable wait is required so this thread can be suspended on windows */
1096 #ifdef MONO_HAS_SEMAPHORES
1097 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1099 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1102 mono_threads_perform_thread_dump ();
1104 mono_console_handle_async_ops ();
1106 #ifndef DISABLE_ATTACH
1107 mono_attach_maybe_start ();
1110 if (domains_to_finalize) {
1111 mono_finalizer_lock ();
1112 if (domains_to_finalize) {
1113 DomainFinalizationReq *req = domains_to_finalize->data;
1114 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1115 mono_finalizer_unlock ();
1117 finalize_domain_objects (req);
1119 mono_finalizer_unlock ();
1123 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1124 * before the domain is unloaded.
1126 mono_gc_invoke_finalizers ();
1128 reference_queue_proccess_all ();
1130 SetEvent (pending_done_event);
1133 SetEvent (shutdown_event);
1140 InitializeCriticalSection (&handle_section);
1141 InitializeCriticalSection (&allocator_section);
1143 InitializeCriticalSection (&finalizer_mutex);
1144 InitializeCriticalSection (&reference_queue_mutex);
1146 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1147 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1149 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1150 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1151 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1152 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1154 mono_gc_base_init ();
1156 if (mono_gc_is_disabled ()) {
1161 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1162 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1163 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1164 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1165 g_assert_not_reached ();
1167 #ifdef MONO_HAS_SEMAPHORES
1168 MONO_SEM_INIT (&finalizer_sem, 0);
1171 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
1172 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1176 mono_gc_cleanup (void)
1179 g_message ("%s: cleaning up finalizer", __func__);
1183 ResetEvent (shutdown_event);
1185 if (mono_thread_internal_current () != gc_thread) {
1186 mono_gc_finalize_notify ();
1187 /* Finishing the finalizer thread, so wait a little bit... */
1188 /* MS seems to wait for about 2 seconds */
1189 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1192 /* Set a flag which the finalizer thread can check */
1193 suspend_finalizers = TRUE;
1195 /* Try to abort the thread, in the hope that it is running managed code */
1196 mono_thread_internal_stop (gc_thread);
1198 /* Wait for it to stop */
1199 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1201 if (ret == WAIT_TIMEOUT) {
1203 * The finalizer thread refused to die. There is not much we
1204 * can do here, since the runtime is shutting down so the
1205 * state the finalizer thread depends on will vanish.
1207 g_warning ("Shutting down finalizer thread timed out.");
1210 * FIXME: On unix, when the above wait returns, the thread
1211 * might still be running io-layer code, or pthreads code.
1219 #ifdef HAVE_BOEHM_GC
1220 GC_finalizer_notifier = NULL;
1224 mono_reference_queue_cleanup ();
1226 DeleteCriticalSection (&handle_section);
1227 DeleteCriticalSection (&allocator_section);
1228 DeleteCriticalSection (&finalizer_mutex);
1229 DeleteCriticalSection (&reference_queue_mutex);
1234 /* Null GC dummy functions */
1236 mono_gc_finalize_notify (void)
1240 void mono_gc_init (void)
1242 InitializeCriticalSection (&handle_section);
1245 void mono_gc_cleanup (void)
1252 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1254 return thread == gc_thread;
1258 * mono_gc_is_finalizer_thread:
1259 * @thread: the thread to test.
1261 * In Mono objects are finalized asynchronously on a separate thread.
1262 * This routine tests whether the @thread argument represents the
1263 * finalization thread.
1265 * Returns true if @thread is the finalization thread.
1268 mono_gc_is_finalizer_thread (MonoThread *thread)
1270 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1273 #if defined(__MACH__)
1274 static pthread_t mach_exception_thread;
1277 mono_gc_register_mach_exception_thread (pthread_t thread)
1279 mach_exception_thread = thread;
1283 mono_gc_get_mach_exception_thread (void)
1285 return mach_exception_thread;
1290 * mono_gc_parse_environment_string_extract_number:
1292 * @str: points to the first digit of the number
1293 * @out: pointer to the variable that will receive the value
1295 * Tries to extract a number from the passed string, taking in to account m, k
1298 * Returns true if passing was successful
1301 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1304 int len = strlen (str), shift = 0;
1306 gboolean is_suffix = FALSE;
1312 suffix = str [len - 1];
1327 if (!isdigit (suffix))
1333 val = strtol (str, &endptr, 10);
1335 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1336 || (errno != 0 && val == 0) || (endptr == str))
1342 if (val < 0) /* negative numbers cannot be suffixed */
1344 if (*(endptr + 1)) /* Invalid string. */
1347 unshifted = (gulong)val;
1349 if (val < 0) /* overflow */
1351 if (((gulong)val >> shift) != unshifted) /* value too large */
1359 #ifndef HAVE_SGEN_GC
1361 mono_gc_alloc_mature (MonoVTable *vtable)
1363 return mono_object_new_specific (vtable);
1368 static MonoReferenceQueue *ref_queues;
1371 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1374 /* Guard if head is changed concurrently. */
1375 while (*prev != element)
1376 prev = &(*prev)->next;
1377 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1381 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1383 RefQueueEntry *current;
1386 value->next = current;
1387 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1388 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1392 reference_queue_proccess (MonoReferenceQueue *queue)
1394 RefQueueEntry **iter = &queue->queue;
1395 RefQueueEntry *entry;
1396 while ((entry = *iter)) {
1398 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1399 mono_gc_weak_link_remove (&entry->dis_link);
1401 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1402 mono_gchandle_free ((guint32)entry->gchandle);
1404 ref_list_remove_element (iter, entry);
1405 queue->callback (entry->user_data);
1408 iter = &entry->next;
1414 reference_queue_proccess_all (void)
1416 MonoReferenceQueue **iter;
1417 MonoReferenceQueue *queue = ref_queues;
1418 for (; queue; queue = queue->next)
1419 reference_queue_proccess (queue);
1422 EnterCriticalSection (&reference_queue_mutex);
1423 for (iter = &ref_queues; *iter;) {
1425 if (!queue->should_be_deleted) {
1426 iter = &queue->next;
1430 LeaveCriticalSection (&reference_queue_mutex);
1431 reference_queue_proccess (queue);
1434 *iter = queue->next;
1437 LeaveCriticalSection (&reference_queue_mutex);
1441 mono_reference_queue_cleanup (void)
1443 MonoReferenceQueue *queue = ref_queues;
1444 for (; queue; queue = queue->next)
1445 queue->should_be_deleted = TRUE;
1446 reference_queue_proccess_all ();
1450 reference_queue_clear_for_domain (MonoDomain *domain)
1452 MonoReferenceQueue *queue = ref_queues;
1453 for (; queue; queue = queue->next) {
1454 RefQueueEntry **iter = &queue->queue;
1455 RefQueueEntry *entry;
1456 while ((entry = *iter)) {
1459 obj = mono_gc_weak_link_get (&entry->dis_link);
1460 if (obj && mono_object_domain (obj) == domain) {
1461 mono_gc_weak_link_remove (&entry->dis_link);
1463 obj = mono_gchandle_get_target (entry->gchandle);
1464 if (obj && mono_object_domain (obj) == domain) {
1465 mono_gchandle_free ((guint32)entry->gchandle);
1467 ref_list_remove_element (iter, entry);
1468 queue->callback (entry->user_data);
1471 iter = &entry->next;
1477 * mono_gc_reference_queue_new:
1478 * @callback callback used when processing dead entries.
1480 * Create a new reference queue used to process collected objects.
1481 * A reference queue let you queue a pair (managed object, user data)
1482 * using the mono_gc_reference_queue_add method.
1484 * Once the managed object is collected @callback will be called
1485 * in the finalizer thread with 'user data' as argument.
1487 * The callback is called without any locks held.
1490 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1492 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1493 res->callback = callback;
1495 EnterCriticalSection (&reference_queue_mutex);
1496 res->next = ref_queues;
1498 LeaveCriticalSection (&reference_queue_mutex);
1504 * mono_gc_reference_queue_add:
1505 * @queue the queue to add the reference to.
1506 * @obj the object to be watched for collection
1507 * @user_data parameter to be passed to the queue callback
1509 * Queue an object to be watched for collection, when the @obj is
1510 * collected, the callback that was registered for the @queue will
1511 * be invoked with the @obj and @user_data arguments.
1513 * @returns false if the queue is scheduled to be freed.
1516 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1518 RefQueueEntry *entry;
1519 if (queue->should_be_deleted)
1522 entry = g_new0 (RefQueueEntry, 1);
1523 entry->user_data = user_data;
1526 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1528 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1529 mono_object_register_finalizer (obj);
1532 ref_list_push (&queue->queue, entry);
1537 * mono_gc_reference_queue_free:
1538 * @queue the queue that should be deleted.
1540 * This operation signals that @queue should be deleted. This operation is deferred
1541 * as it happens on the finalizer thread.
1543 * After this call, no further objects can be queued. It's the responsibility of the
1544 * caller to make sure that no further attempt to access queue will be made.
1547 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1549 queue->should_be_deleted = TRUE;
1552 #define ptr_mask ((sizeof (void*) - 1))
1553 #define _toi(ptr) ((size_t)ptr)
1554 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1555 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1556 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1560 * @dest: address to start to clear
1561 * @size: size of the region to clear
1563 * Zero @size bytes starting at @dest.
1565 * Use this to zero memory that can hold managed pointers.
1567 * FIXME borrow faster code from some BSD libc or bionic
1570 mono_gc_bzero (void *dest, size_t size)
1572 char *p = (char*)dest;
1573 char *end = p + size;
1574 char *align_end = align_up (p);
1577 while (p < align_end)
1580 word_end = align_down (end);
1581 while (p < word_end) {
1582 *((void**)p) = NULL;
1583 p += sizeof (void*);
1593 * @dest: destination of the move
1595 * @size: size of the block to move
1597 * Move @size bytes from @src to @dest.
1598 * size MUST be a multiple of sizeof (gpointer)
1600 * FIXME borrow faster code from some BSD libc or bionic
1603 mono_gc_memmove (void *dest, const void *src, size_t size)
1606 * If dest and src are differently aligned with respect to
1607 * pointer size then it makes no sense to do aligned copying.
1608 * In fact, we would end up with unaligned loads which is
1609 * incorrect on some architectures.
1611 if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
1612 memmove (dest, src, size);
1617 * A bit of explanation on why we align only dest before doing word copies.
1618 * Pointers to managed objects must always be stored in word aligned addresses, so
1619 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1621 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
1622 char *p = (char*)dest + size;
1623 char *s = (char*)src + size;
1624 char *start = (char*)dest;
1625 char *align_end = MAX((char*)dest, (char*)align_down (p));
1628 while (p > align_end)
1631 word_start = align_up (start);
1632 while (p > word_start) {
1633 p -= sizeof (void*);
1634 s -= sizeof (void*);
1635 *((void**)p) = *((void**)s);
1641 char *p = (char*)dest;
1642 char *s = (char*)src;
1643 char *end = p + size;
1644 char *align_end = MIN ((char*)end, (char*)align_up (p));
1647 while (p < align_end)
1650 word_end = align_down (end);
1651 while (p < word_end) {
1652 *((void**)p) = *((void**)s);
1653 p += sizeof (void*);
1654 s += sizeof (void*);