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 #ifndef DISABLE_PERFCOUNTERS
737 mono_perfcounters->gc_num_handles++;
739 unlock_handles (handles);
740 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
741 res = (slot << 3) | (handles->type + 1);
742 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
748 * @obj: managed object to get a handle for
749 * @pinned: whether the object should be pinned
751 * This returns a handle that wraps the object, this is used to keep a
752 * reference to a managed object from the unmanaged world and preventing the
753 * object from being disposed.
755 * If @pinned is false the address of the object can not be obtained, if it is
756 * true the address of the object can be obtained. This will also pin the
757 * object so it will not be possible by a moving garbage collector to move the
760 * Returns: a handle that can be used to access the object from
764 mono_gchandle_new (MonoObject *obj, gboolean pinned)
766 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
770 * mono_gchandle_new_weakref:
771 * @obj: managed object to get a handle for
772 * @pinned: whether the object should be pinned
774 * This returns a weak handle that wraps the object, this is used to
775 * keep a reference to a managed object from the unmanaged world.
776 * Unlike the mono_gchandle_new the object can be reclaimed by the
777 * garbage collector. In this case the value of the GCHandle will be
780 * If @pinned is false the address of the object can not be obtained, if it is
781 * true the address of the object can be obtained. This will also pin the
782 * object so it will not be possible by a moving garbage collector to move the
785 * Returns: a handle that can be used to access the object from
789 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
791 guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
794 if (track_resurrection)
795 mono_gc_add_weak_track_handle (obj, handle);
802 mono_gchandle_get_type (guint32 gchandle)
804 guint type = (gchandle & 7) - 1;
810 * mono_gchandle_get_target:
811 * @gchandle: a GCHandle's handle.
813 * The handle was previously created by calling mono_gchandle_new or
814 * mono_gchandle_new_weakref.
816 * Returns a pointer to the MonoObject represented by the handle or
817 * NULL for a collected object if using a weakref handle.
820 mono_gchandle_get_target (guint32 gchandle)
822 guint slot = gchandle >> 3;
823 guint type = (gchandle & 7) - 1;
824 HandleData *handles = &gc_handles [type];
825 MonoObject *obj = NULL;
828 lock_handles (handles);
829 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
830 if (handles->type <= HANDLE_WEAK_TRACK) {
831 obj = mono_gc_weak_link_get (&handles->entries [slot]);
833 obj = handles->entries [slot];
836 /* print a warning? */
838 unlock_handles (handles);
839 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
844 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
846 guint slot = gchandle >> 3;
847 guint type = (gchandle & 7) - 1;
848 HandleData *handles = &gc_handles [type];
849 MonoObject *old_obj = NULL;
853 lock_handles (handles);
854 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
855 if (handles->type <= HANDLE_WEAK_TRACK) {
856 old_obj = handles->entries [slot];
857 if (handles->entries [slot])
858 mono_gc_weak_link_remove (&handles->entries [slot]);
860 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
861 /*FIXME, what to use when obj == null?*/
862 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
864 handles->entries [slot] = obj;
867 /* print a warning? */
869 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
870 unlock_handles (handles);
873 if (type == HANDLE_WEAK_TRACK)
874 mono_gc_change_weak_track_handle (old_obj, obj, gchandle);
879 * mono_gchandle_is_in_domain:
880 * @gchandle: a GCHandle's handle.
881 * @domain: An application domain.
883 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
886 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
888 guint slot = gchandle >> 3;
889 guint type = (gchandle & 7) - 1;
890 HandleData *handles = &gc_handles [type];
891 gboolean result = FALSE;
894 lock_handles (handles);
895 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
896 if (handles->type <= HANDLE_WEAK_TRACK) {
897 result = domain->domain_id == handles->domain_ids [slot];
900 obj = handles->entries [slot];
904 result = domain == mono_object_domain (obj);
907 /* print a warning? */
909 unlock_handles (handles);
914 * mono_gchandle_free:
915 * @gchandle: a GCHandle's handle.
917 * Frees the @gchandle handle. If there are no outstanding
918 * references, the garbage collector can reclaim the memory of the
922 mono_gchandle_free (guint32 gchandle)
924 guint slot = gchandle >> 3;
925 guint type = (gchandle & 7) - 1;
926 HandleData *handles = &gc_handles [type];
930 if (type == HANDLE_WEAK_TRACK)
931 mono_gc_remove_weak_track_handle (gchandle);
934 lock_handles (handles);
935 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
936 if (handles->type <= HANDLE_WEAK_TRACK) {
937 if (handles->entries [slot])
938 mono_gc_weak_link_remove (&handles->entries [slot]);
940 handles->entries [slot] = NULL;
942 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
944 /* print a warning? */
946 #ifndef DISABLE_PERFCOUNTERS
947 mono_perfcounters->gc_num_handles--;
949 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
950 unlock_handles (handles);
951 mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
955 * mono_gchandle_free_domain:
956 * @domain: domain that is unloading
958 * Function used internally to cleanup any GC handle for objects belonging
959 * to the specified domain during appdomain unload.
962 mono_gchandle_free_domain (MonoDomain *domain)
966 for (type = 0; type < 3; ++type) {
968 HandleData *handles = &gc_handles [type];
969 lock_handles (handles);
970 for (slot = 0; slot < handles->size; ++slot) {
971 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
973 if (type <= HANDLE_WEAK_TRACK) {
974 if (domain->domain_id == handles->domain_ids [slot]) {
975 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
976 if (handles->entries [slot])
977 mono_gc_weak_link_remove (&handles->entries [slot]);
980 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
981 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
982 handles->entries [slot] = NULL;
986 unlock_handles (handles);
992 GCHandle_CheckCurrentDomain (guint32 gchandle)
994 return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
999 #ifdef MONO_HAS_SEMAPHORES
1000 static MonoSemType finalizer_sem;
1002 static HANDLE finalizer_event;
1003 static volatile gboolean finished=FALSE;
1006 mono_gc_finalize_notify (void)
1009 g_message ( "%s: prodding finalizer", __func__);
1012 #ifdef MONO_HAS_SEMAPHORES
1013 MONO_SEM_POST (&finalizer_sem);
1015 SetEvent (finalizer_event);
1019 #ifdef HAVE_BOEHM_GC
1022 collect_objects (gpointer key, gpointer value, gpointer user_data)
1024 GPtrArray *arr = (GPtrArray*)user_data;
1025 g_ptr_array_add (arr, key);
1031 * finalize_domain_objects:
1033 * Run the finalizers of all finalizable objects in req->domain.
1036 finalize_domain_objects (DomainFinalizationReq *req)
1038 MonoDomain *domain = req->domain;
1041 #define NUM_FOBJECTS 64
1042 MonoObject *to_finalize [NUM_FOBJECTS];
1046 /* Process finalizers which are already in the queue */
1047 mono_gc_invoke_finalizers ();
1049 #ifdef HAVE_BOEHM_GC
1050 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1054 * Since the domain is unloading, nobody is allowed to put
1055 * new entries into the hash table. But finalize_object might
1056 * remove entries from the hash table, so we make a copy.
1058 objs = g_ptr_array_new ();
1059 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1060 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1062 for (i = 0; i < objs->len; ++i) {
1063 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1064 /* FIXME: Avoid finalizing threads, etc */
1065 mono_gc_run_finalize (o, 0);
1068 g_ptr_array_free (objs, TRUE);
1070 #elif defined(HAVE_SGEN_GC)
1071 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1073 for (i = 0; i < count; ++i) {
1074 mono_gc_run_finalize (to_finalize [i], 0);
1079 /* cleanup the reference queue */
1080 reference_queue_clear_for_domain (domain);
1082 /* printf ("DONE.\n"); */
1083 SetEvent (req->done_event);
1085 /* The event is closed in mono_domain_finalize if we get here */
1090 finalizer_thread (gpointer unused)
1093 /* Wait to be notified that there's at least one
1097 g_assert (mono_domain_get () == mono_get_root_domain ());
1099 /* An alertable wait is required so this thread can be suspended on windows */
1100 #ifdef MONO_HAS_SEMAPHORES
1101 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1103 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1106 mono_threads_perform_thread_dump ();
1108 mono_console_handle_async_ops ();
1110 #ifndef DISABLE_ATTACH
1111 mono_attach_maybe_start ();
1114 if (domains_to_finalize) {
1115 mono_finalizer_lock ();
1116 if (domains_to_finalize) {
1117 DomainFinalizationReq *req = domains_to_finalize->data;
1118 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1119 mono_finalizer_unlock ();
1121 finalize_domain_objects (req);
1123 mono_finalizer_unlock ();
1127 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1128 * before the domain is unloaded.
1130 mono_gc_invoke_finalizers ();
1132 reference_queue_proccess_all ();
1134 SetEvent (pending_done_event);
1137 SetEvent (shutdown_event);
1141 #ifndef LAZY_GC_THREAD_CREATION
1145 mono_gc_init_finalizer_thread (void)
1147 gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
1148 ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1154 InitializeCriticalSection (&handle_section);
1155 InitializeCriticalSection (&allocator_section);
1157 InitializeCriticalSection (&finalizer_mutex);
1158 InitializeCriticalSection (&reference_queue_mutex);
1160 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1161 MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1163 mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1164 mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1165 mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1166 mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1168 mono_gc_base_init ();
1170 if (mono_gc_is_disabled ()) {
1175 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1176 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1177 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1178 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1179 g_assert_not_reached ();
1181 #ifdef MONO_HAS_SEMAPHORES
1182 MONO_SEM_INIT (&finalizer_sem, 0);
1185 #ifndef LAZY_GC_THREAD_CREATION
1186 mono_gc_init_finalizer_thread ();
1191 mono_gc_cleanup (void)
1194 g_message ("%s: cleaning up finalizer", __func__);
1198 ResetEvent (shutdown_event);
1200 if (mono_thread_internal_current () != gc_thread) {
1201 mono_gc_finalize_notify ();
1202 /* Finishing the finalizer thread, so wait a little bit... */
1203 /* MS seems to wait for about 2 seconds */
1204 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1207 /* Set a flag which the finalizer thread can check */
1208 suspend_finalizers = TRUE;
1210 /* Try to abort the thread, in the hope that it is running managed code */
1211 mono_thread_internal_stop (gc_thread);
1213 /* Wait for it to stop */
1214 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1216 if (ret == WAIT_TIMEOUT) {
1218 * The finalizer thread refused to die. There is not much we
1219 * can do here, since the runtime is shutting down so the
1220 * state the finalizer thread depends on will vanish.
1222 g_warning ("Shutting down finalizer thread timed out.");
1225 * FIXME: On unix, when the above wait returns, the thread
1226 * might still be running io-layer code, or pthreads code.
1234 #ifdef HAVE_BOEHM_GC
1235 GC_finalizer_notifier = NULL;
1239 mono_reference_queue_cleanup ();
1241 DeleteCriticalSection (&handle_section);
1242 DeleteCriticalSection (&allocator_section);
1243 DeleteCriticalSection (&finalizer_mutex);
1244 DeleteCriticalSection (&reference_queue_mutex);
1249 /* Null GC dummy functions */
1251 mono_gc_finalize_notify (void)
1255 void mono_gc_init (void)
1257 InitializeCriticalSection (&handle_section);
1260 void mono_gc_cleanup (void)
1267 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1269 return thread == gc_thread;
1273 * mono_gc_is_finalizer_thread:
1274 * @thread: the thread to test.
1276 * In Mono objects are finalized asynchronously on a separate thread.
1277 * This routine tests whether the @thread argument represents the
1278 * finalization thread.
1280 * Returns true if @thread is the finalization thread.
1283 mono_gc_is_finalizer_thread (MonoThread *thread)
1285 return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1288 #if defined(__MACH__)
1289 static pthread_t mach_exception_thread;
1292 mono_gc_register_mach_exception_thread (pthread_t thread)
1294 mach_exception_thread = thread;
1298 mono_gc_get_mach_exception_thread (void)
1300 return mach_exception_thread;
1305 * mono_gc_parse_environment_string_extract_number:
1307 * @str: points to the first digit of the number
1308 * @out: pointer to the variable that will receive the value
1310 * Tries to extract a number from the passed string, taking in to account m, k
1313 * Returns true if passing was successful
1316 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1319 int len = strlen (str), shift = 0;
1321 gboolean is_suffix = FALSE;
1327 suffix = str [len - 1];
1342 if (!isdigit (suffix))
1348 val = strtol (str, &endptr, 10);
1350 if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1351 || (errno != 0 && val == 0) || (endptr == str))
1357 if (val < 0) /* negative numbers cannot be suffixed */
1359 if (*(endptr + 1)) /* Invalid string. */
1362 unshifted = (gulong)val;
1364 if (val < 0) /* overflow */
1366 if (((gulong)val >> shift) != unshifted) /* value too large */
1374 #ifndef HAVE_SGEN_GC
1376 mono_gc_alloc_mature (MonoVTable *vtable)
1378 return mono_object_new_specific (vtable);
1383 static MonoReferenceQueue *ref_queues;
1386 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1389 /* Guard if head is changed concurrently. */
1390 while (*prev != element)
1391 prev = &(*prev)->next;
1392 } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1396 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1398 RefQueueEntry *current;
1401 value->next = current;
1402 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1403 } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1407 reference_queue_proccess (MonoReferenceQueue *queue)
1409 RefQueueEntry **iter = &queue->queue;
1410 RefQueueEntry *entry;
1411 while ((entry = *iter)) {
1413 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1414 mono_gc_weak_link_remove (&entry->dis_link);
1416 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1417 mono_gchandle_free ((guint32)entry->gchandle);
1419 ref_list_remove_element (iter, entry);
1420 queue->callback (entry->user_data);
1423 iter = &entry->next;
1429 reference_queue_proccess_all (void)
1431 MonoReferenceQueue **iter;
1432 MonoReferenceQueue *queue = ref_queues;
1433 for (; queue; queue = queue->next)
1434 reference_queue_proccess (queue);
1437 EnterCriticalSection (&reference_queue_mutex);
1438 for (iter = &ref_queues; *iter;) {
1440 if (!queue->should_be_deleted) {
1441 iter = &queue->next;
1445 LeaveCriticalSection (&reference_queue_mutex);
1446 reference_queue_proccess (queue);
1449 *iter = queue->next;
1452 LeaveCriticalSection (&reference_queue_mutex);
1456 mono_reference_queue_cleanup (void)
1458 MonoReferenceQueue *queue = ref_queues;
1459 for (; queue; queue = queue->next)
1460 queue->should_be_deleted = TRUE;
1461 reference_queue_proccess_all ();
1465 reference_queue_clear_for_domain (MonoDomain *domain)
1467 MonoReferenceQueue *queue = ref_queues;
1468 for (; queue; queue = queue->next) {
1469 RefQueueEntry **iter = &queue->queue;
1470 RefQueueEntry *entry;
1471 while ((entry = *iter)) {
1474 obj = mono_gc_weak_link_get (&entry->dis_link);
1475 if (obj && mono_object_domain (obj) == domain) {
1476 mono_gc_weak_link_remove (&entry->dis_link);
1478 obj = mono_gchandle_get_target (entry->gchandle);
1479 if (obj && mono_object_domain (obj) == domain) {
1480 mono_gchandle_free ((guint32)entry->gchandle);
1482 ref_list_remove_element (iter, entry);
1483 queue->callback (entry->user_data);
1486 iter = &entry->next;
1492 * mono_gc_reference_queue_new:
1493 * @callback callback used when processing dead entries.
1495 * Create a new reference queue used to process collected objects.
1496 * A reference queue let you queue a pair (managed object, user data)
1497 * using the mono_gc_reference_queue_add method.
1499 * Once the managed object is collected @callback will be called
1500 * in the finalizer thread with 'user data' as argument.
1502 * The callback is called without any locks held.
1505 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1507 MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1508 res->callback = callback;
1510 EnterCriticalSection (&reference_queue_mutex);
1511 res->next = ref_queues;
1513 LeaveCriticalSection (&reference_queue_mutex);
1519 * mono_gc_reference_queue_add:
1520 * @queue the queue to add the reference to.
1521 * @obj the object to be watched for collection
1522 * @user_data parameter to be passed to the queue callback
1524 * Queue an object to be watched for collection, when the @obj is
1525 * collected, the callback that was registered for the @queue will
1526 * be invoked with the @obj and @user_data arguments.
1528 * @returns false if the queue is scheduled to be freed.
1531 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1533 RefQueueEntry *entry;
1534 if (queue->should_be_deleted)
1537 entry = g_new0 (RefQueueEntry, 1);
1538 entry->user_data = user_data;
1541 mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1543 entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1544 mono_object_register_finalizer (obj);
1547 ref_list_push (&queue->queue, entry);
1552 * mono_gc_reference_queue_free:
1553 * @queue the queue that should be deleted.
1555 * This operation signals that @queue should be deleted. This operation is deferred
1556 * as it happens on the finalizer thread.
1558 * After this call, no further objects can be queued. It's the responsibility of the
1559 * caller to make sure that no further attempt to access queue will be made.
1562 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1564 queue->should_be_deleted = TRUE;
1567 #define ptr_mask ((sizeof (void*) - 1))
1568 #define _toi(ptr) ((size_t)ptr)
1569 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1570 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1571 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1575 * @dest: address to start to clear
1576 * @size: size of the region to clear
1578 * Zero @size bytes starting at @dest.
1580 * Use this to zero memory that can hold managed pointers.
1582 * FIXME borrow faster code from some BSD libc or bionic
1585 mono_gc_bzero (void *dest, size_t size)
1587 char *p = (char*)dest;
1588 char *end = p + size;
1589 char *align_end = align_up (p);
1592 while (p < align_end)
1595 word_end = align_down (end);
1596 while (p < word_end) {
1597 *((void**)p) = NULL;
1598 p += sizeof (void*);
1608 * @dest: destination of the move
1610 * @size: size of the block to move
1612 * Move @size bytes from @src to @dest.
1613 * size MUST be a multiple of sizeof (gpointer)
1615 * FIXME borrow faster code from some BSD libc or bionic
1618 mono_gc_memmove (void *dest, const void *src, size_t size)
1621 * If dest and src are differently aligned with respect to
1622 * pointer size then it makes no sense to do aligned copying.
1623 * In fact, we would end up with unaligned loads which is
1624 * incorrect on some architectures.
1626 if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
1627 memmove (dest, src, size);
1632 * A bit of explanation on why we align only dest before doing word copies.
1633 * Pointers to managed objects must always be stored in word aligned addresses, so
1634 * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1636 if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
1637 char *p = (char*)dest + size;
1638 char *s = (char*)src + size;
1639 char *start = (char*)dest;
1640 char *align_end = MAX((char*)dest, (char*)align_down (p));
1643 while (p > align_end)
1646 word_start = align_up (start);
1647 while (p > word_start) {
1648 p -= sizeof (void*);
1649 s -= sizeof (void*);
1650 *((void**)p) = *((void**)s);
1656 char *p = (char*)dest;
1657 char *s = (char*)src;
1658 char *end = p + size;
1659 char *align_end = MIN ((char*)end, (char*)align_up (p));
1662 while (p < align_end)
1665 word_end = align_down (end);
1666 while (p < word_end) {
1667 *((void**)p) = *((void**)s);
1668 p += sizeof (void*);
1669 s += sizeof (void*);