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)
14 #include <mono/metadata/gc-internal.h>
15 #include <mono/metadata/mono-gc.h>
16 #include <mono/metadata/threads.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/exception.h>
19 #include <mono/metadata/profiler-private.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/class-internals.h>
22 #include <mono/metadata/mono-mlist.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/utils/mono-logger.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
27 #include <mono/metadata/attach.h>
29 #include <semaphore.h>
30 /* we do this only for known working systems (OSX for example
31 * has the header and functions, but they don't work at all): in other cases
32 * we fall back to the io-layer slightly slower and signal-unsafe Event.
35 #define USE_POSIX_SEM 1
39 #ifndef PLATFORM_WIN32
43 typedef struct DomainFinalizationReq {
46 } DomainFinalizationReq;
48 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
49 extern void (*__imp_GC_finalizer_notifier)(void);
50 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
51 extern int __imp_GC_finalize_on_demand;
52 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
55 static gboolean gc_disabled = FALSE;
57 static gboolean finalizing_root_domain = FALSE;
59 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
60 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
61 static CRITICAL_SECTION finalizer_mutex;
63 static GSList *domains_to_finalize= NULL;
64 static MonoMList *threads_to_finalize = NULL;
66 static MonoThread *gc_thread;
68 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
71 static HANDLE pending_done_event;
72 static HANDLE shutdown_event;
73 static HANDLE thread_started_event;
77 add_thread_to_finalize (MonoThread *thread)
79 mono_finalizer_lock ();
80 if (!threads_to_finalize)
81 MONO_GC_REGISTER_ROOT (threads_to_finalize);
82 threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
83 mono_finalizer_unlock ();
86 static gboolean suspend_finalizers = FALSE;
88 * actually, we might want to queue the finalize requests in a separate thread,
89 * but we need to be careful about the execution domain of the thread...
92 run_finalize (void *obj, void *data)
94 MonoObject *exc = NULL;
99 MonoMethod* finalizer = NULL;
100 o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
102 if (suspend_finalizers)
106 mono_domain_lock (o->vtable->domain);
108 o2 = g_hash_table_lookup (o->vtable->domain->finalizable_objects_hash, o);
110 mono_domain_unlock (o->vtable->domain);
113 /* Already finalized somehow */
117 /* make sure the finalizer is not called again if the object is resurrected */
118 object_register_finalizer (obj, NULL);
120 if (o->vtable->klass == mono_get_thread_class ()) {
121 MonoThread *t = (MonoThread*)o;
123 if (mono_gc_is_finalizer_thread (t))
124 /* Avoid finalizing ourselves */
127 if (t->threadpool_thread && finalizing_root_domain) {
128 /* Don't finalize threadpool threads when
129 shutting down - they're finalized when the
130 threadpool shuts down. */
131 add_thread_to_finalize (t);
136 if (mono_runtime_get_no_exec ())
139 /* speedup later... and use a timeout */
140 /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
142 /* Use _internal here, since this thread can enter a doomed appdomain */
143 mono_domain_set_internal (mono_object_domain (o));
145 /* delegates that have a native function pointer allocated are
146 * registered for finalization, but they don't have a Finalize
147 * method, because in most cases it's not needed and it's just a waste.
149 if (o->vtable->klass->delegate) {
150 MonoDelegate* del = (MonoDelegate*)o;
151 if (del->delegate_trampoline)
152 mono_delegate_free_ftnptr ((MonoDelegate*)o);
156 finalizer = mono_class_get_finalizer (o->vtable->klass);
159 /* If object has a CCW but has no finalizer, it was only
160 * registered for finalization in order to free the CCW.
161 * Else it needs the regular finalizer run.
162 * FIXME: what to do about ressurection and suppression
163 * of finalizer on object with CCW.
165 if (mono_marshal_free_ccw (o) && !finalizer)
169 mono_runtime_invoke (finalizer, o, NULL, &exc);
172 /* fixme: do something useful */
177 mono_gc_finalize_threadpool_threads (void)
179 while (threads_to_finalize) {
180 MonoThread *thread = (MonoThread*) mono_mlist_get_data (threads_to_finalize);
182 /* Force finalization of the thread. */
183 thread->threadpool_thread = FALSE;
184 mono_object_register_finalizer ((MonoObject*)thread);
186 run_finalize (thread, NULL);
188 threads_to_finalize = mono_mlist_next (threads_to_finalize);
193 mono_gc_out_of_memory (size_t size)
196 * we could allocate at program startup some memory that we could release
197 * back to the system at this point if we're really low on memory (ie, size is
198 * lower than the memory we set apart)
200 mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
206 * Some of our objects may point to a different address than the address returned by GC_malloc()
207 * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
208 * This also means that in the callback we need to adjust the pointer to get back the real
210 * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer,
211 * since that, too, can cause the underlying pointer to be offset.
214 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
218 MonoDomain *domain = obj->vtable->domain;
221 /* This assertion is not valid when GC_DEBUG is defined */
222 g_assert (GC_base (obj) == (char*)obj - offset);
225 if (mono_domain_is_unloading (domain) && (callback != NULL))
227 * Can't register finalizers in a dying appdomain, since they
228 * could be invoked after the appdomain has been unloaded.
232 mono_domain_lock (domain);
235 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
237 g_hash_table_remove (domain->finalizable_objects_hash, obj);
239 mono_domain_unlock (domain);
241 GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
242 #elif defined(HAVE_SGEN_GC)
243 mono_gc_register_for_finalization (obj, callback);
248 * mono_object_register_finalizer:
249 * @obj: object to register
251 * Records that object @obj has a finalizer, this will call the
252 * Finalize method when the garbage collector disposes the object.
256 mono_object_register_finalizer (MonoObject *obj)
258 /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
259 object_register_finalizer (obj, run_finalize);
263 * mono_domain_finalize:
264 * @domain: the domain to finalize
265 * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
267 * Request finalization of all finalizable objects inside @domain. Wait
268 * @timeout msecs for the finalization to complete.
270 * Returns: TRUE if succeeded, FALSE if there was a timeout
274 mono_domain_finalize (MonoDomain *domain, guint32 timeout)
276 DomainFinalizationReq *req;
280 if (mono_thread_current () == gc_thread)
281 /* We are called from inside a finalizer, not much we can do here */
285 * No need to create another thread 'cause the finalizer thread
286 * is still working and will take care of running the finalizers
293 mono_gc_collect (mono_gc_max_generation ());
295 done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
296 if (done_event == NULL) {
300 req = g_new0 (DomainFinalizationReq, 1);
301 req->domain = domain;
302 req->done_event = done_event;
304 if (domain == mono_get_root_domain ())
305 finalizing_root_domain = TRUE;
307 mono_finalizer_lock ();
309 domains_to_finalize = g_slist_append (domains_to_finalize, req);
311 mono_finalizer_unlock ();
313 /* Tell the finalizer thread to finalize this appdomain */
314 mono_gc_finalize_notify ();
319 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
321 /* printf ("WAIT RES: %d.\n", res); */
322 if (res == WAIT_TIMEOUT) {
323 /* We leak the handle here */
327 CloseHandle (done_event);
329 if (domain == mono_get_root_domain ()) {
330 mono_thread_pool_cleanup ();
331 mono_gc_finalize_threadpool_threads ();
336 /* We don't support domain finalization without a GC */
342 ves_icall_System_GC_InternalCollect (int generation)
344 mono_gc_collect (generation);
348 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
353 mono_gc_collect (mono_gc_max_generation ());
354 return mono_gc_get_used_size ();
358 ves_icall_System_GC_KeepAlive (MonoObject *obj)
368 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
372 object_register_finalizer (obj, run_finalize);
376 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
380 /* delegates have no finalizers, but we register them to deal with the
381 * unmanaged->managed trampoline. We don't let the user suppress it
382 * otherwise we'd leak it.
384 if (obj->vtable->klass->delegate)
387 /* FIXME: Need to handle case where obj has COM Callable Wrapper
388 * generated for it that needs cleaned up, but user wants to suppress
389 * their derived object finalizer. */
391 object_register_finalizer (obj, NULL);
395 ves_icall_System_GC_WaitForPendingFinalizers (void)
398 if (!mono_gc_pending_finalizers ())
401 if (mono_thread_current () == gc_thread)
402 /* Avoid deadlocks */
405 ResetEvent (pending_done_event);
406 mono_gc_finalize_notify ();
407 /* g_print ("Waiting for pending finalizers....\n"); */
408 WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
409 /* g_print ("Done pending....\n"); */
413 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
414 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
415 static CRITICAL_SECTION allocator_section;
416 static CRITICAL_SECTION handle_section;
425 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
427 static HandleType mono_gchandle_get_type (guint32 gchandle);
430 ves_icall_System_GCHandle_GetTarget (guint32 handle)
432 return mono_gchandle_get_target (handle);
436 * if type == -1, change the target of the handle, otherwise allocate a new handle.
439 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
442 mono_gchandle_set_target (handle, obj);
443 /* the handle doesn't change */
448 return mono_gchandle_new_weakref (obj, FALSE);
449 case HANDLE_WEAK_TRACK:
450 return mono_gchandle_new_weakref (obj, TRUE);
452 return mono_gchandle_new (obj, FALSE);
454 return mono_gchandle_new (obj, TRUE);
456 g_assert_not_reached ();
462 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
464 mono_gchandle_free (handle);
468 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
472 if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
474 obj = mono_gchandle_get_target (handle);
476 MonoClass *klass = mono_object_class (obj);
477 if (klass == mono_defaults.string_class) {
478 return mono_string_chars ((MonoString*)obj);
479 } else if (klass->rank) {
480 return mono_array_addr ((MonoArray*)obj, char, 0);
482 /* the C# code will check and throw the exception */
483 /* FIXME: missing !klass->blittable test, see bug #61134 */
484 if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
486 return (char*)obj + sizeof (MonoObject);
497 guint slot_hint : 24; /* starting slot for search */
498 /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
499 /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
503 /* weak and weak-track arrays will be allocated in malloc memory
505 static HandleData gc_handles [] = {
506 {NULL, NULL, 0, HANDLE_WEAK, 0},
507 {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
508 {NULL, NULL, 0, HANDLE_NORMAL, 0},
509 {NULL, NULL, 0, HANDLE_PINNED, 0}
512 #define lock_handles(handles) EnterCriticalSection (&handle_section)
513 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
516 find_first_unset (guint32 bitmap)
519 for (i = 0; i < 32; ++i) {
520 if (!(bitmap & (1 << i)))
527 alloc_handle (HandleData *handles, MonoObject *obj)
530 lock_handles (handles);
531 if (!handles->size) {
533 if (handles->type > HANDLE_WEAK_TRACK) {
534 handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, NULL);
536 handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
537 handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
539 handles->bitmap = g_malloc0 (handles->size / 8);
542 for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
543 if (handles->bitmap [slot] != 0xffffffff) {
544 i = find_first_unset (handles->bitmap [slot]);
545 handles->slot_hint = slot;
549 if (i == -1 && handles->slot_hint != 0) {
550 for (slot = 0; slot < handles->slot_hint; ++slot) {
551 if (handles->bitmap [slot] != 0xffffffff) {
552 i = find_first_unset (handles->bitmap [slot]);
553 handles->slot_hint = slot;
560 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
562 /* resize and copy the bitmap */
563 new_bitmap = g_malloc0 (new_size / 8);
564 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
565 g_free (handles->bitmap);
566 handles->bitmap = new_bitmap;
568 /* resize and copy the entries */
569 if (handles->type > HANDLE_WEAK_TRACK) {
571 entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, NULL);
572 memcpy (entries, handles->entries, sizeof (gpointer) * handles->size);
573 handles->entries = entries;
577 domain_ids = g_malloc0 (sizeof (guint16) * new_size);
578 entries = g_malloc (sizeof (gpointer) * new_size);
579 /* we disable GC because we could lose some disappearing link updates */
581 memcpy (entries, handles->entries, sizeof (gpointer) * handles->size);
582 memset (entries + handles->size, 0, sizeof (gpointer) * handles->size);
583 memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
584 for (i = 0; i < handles->size; ++i) {
585 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
586 if (handles->entries [i])
587 mono_gc_weak_link_remove (&(handles->entries [i]));
588 /*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]);*/
590 mono_gc_weak_link_add (&(entries [i]), obj);
593 g_free (handles->entries);
594 g_free (handles->domain_ids);
595 handles->entries = entries;
596 handles->domain_ids = domain_ids;
600 /* set i and slot to the next free position */
602 slot = (handles->size + 1) / 32;
603 handles->slot_hint = handles->size + 1;
604 handles->size = new_size;
606 handles->bitmap [slot] |= 1 << i;
607 slot = slot * 32 + i;
608 handles->entries [slot] = obj;
609 if (handles->type <= HANDLE_WEAK_TRACK) {
611 mono_gc_weak_link_add (&(handles->entries [slot]), obj);
614 mono_perfcounters->gc_num_handles++;
615 unlock_handles (handles);
616 /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
617 return (slot << 3) | (handles->type + 1);
622 * @obj: managed object to get a handle for
623 * @pinned: whether the object should be pinned
625 * This returns a handle that wraps the object, this is used to keep a
626 * reference to a managed object from the unmanaged world and preventing the
627 * object from being disposed.
629 * If @pinned is false the address of the object can not be obtained, if it is
630 * true the address of the object can be obtained. This will also pin the
631 * object so it will not be possible by a moving garbage collector to move the
634 * Returns: a handle that can be used to access the object from
638 mono_gchandle_new (MonoObject *obj, gboolean pinned)
640 return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj);
644 * mono_gchandle_new_weakref:
645 * @obj: managed object to get a handle for
646 * @pinned: whether the object should be pinned
648 * This returns a weak handle that wraps the object, this is used to
649 * keep a reference to a managed object from the unmanaged world.
650 * Unlike the mono_gchandle_new the object can be reclaimed by the
651 * garbage collector. In this case the value of the GCHandle will be
654 * If @pinned is false the address of the object can not be obtained, if it is
655 * true the address of the object can be obtained. This will also pin the
656 * object so it will not be possible by a moving garbage collector to move the
659 * Returns: a handle that can be used to access the object from
663 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
665 return alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj);
669 mono_gchandle_get_type (guint32 gchandle)
671 guint type = (gchandle & 7) - 1;
677 * mono_gchandle_get_target:
678 * @gchandle: a GCHandle's handle.
680 * The handle was previously created by calling mono_gchandle_new or
681 * mono_gchandle_new_weakref.
683 * Returns a pointer to the MonoObject represented by the handle or
684 * NULL for a collected object if using a weakref handle.
687 mono_gchandle_get_target (guint32 gchandle)
689 guint slot = gchandle >> 3;
690 guint type = (gchandle & 7) - 1;
691 HandleData *handles = &gc_handles [type];
692 MonoObject *obj = NULL;
695 lock_handles (handles);
696 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
697 if (handles->type <= HANDLE_WEAK_TRACK) {
698 obj = mono_gc_weak_link_get (&handles->entries [slot]);
700 obj = handles->entries [slot];
703 /* print a warning? */
705 unlock_handles (handles);
706 /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
711 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
713 guint slot = gchandle >> 3;
714 guint type = (gchandle & 7) - 1;
715 HandleData *handles = &gc_handles [type];
718 lock_handles (handles);
719 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
720 if (handles->type <= HANDLE_WEAK_TRACK) {
721 if (handles->entries [slot])
722 mono_gc_weak_link_remove (&handles->entries [slot]);
724 mono_gc_weak_link_add (&handles->entries [slot], obj);
726 handles->entries [slot] = obj;
729 /* print a warning? */
731 /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
732 unlock_handles (handles);
736 * mono_gchandle_is_in_domain:
737 * @gchandle: a GCHandle's handle.
738 * @domain: An application domain.
740 * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
743 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
745 guint slot = gchandle >> 3;
746 guint type = (gchandle & 7) - 1;
747 HandleData *handles = &gc_handles [type];
748 gboolean result = FALSE;
751 lock_handles (handles);
752 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
753 if (handles->type <= HANDLE_WEAK_TRACK) {
754 result = domain->domain_id == handles->domain_ids [slot];
757 obj = handles->entries [slot];
761 result = domain == mono_object_domain (obj);
764 /* print a warning? */
766 unlock_handles (handles);
771 * mono_gchandle_free:
772 * @gchandle: a GCHandle's handle.
774 * Frees the @gchandle handle. If there are no outstanding
775 * references, the garbage collector can reclaim the memory of the
779 mono_gchandle_free (guint32 gchandle)
781 guint slot = gchandle >> 3;
782 guint type = (gchandle & 7) - 1;
783 HandleData *handles = &gc_handles [type];
786 lock_handles (handles);
787 if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
788 if (handles->type <= HANDLE_WEAK_TRACK) {
789 if (handles->entries [slot])
790 mono_gc_weak_link_remove (&handles->entries [slot]);
792 handles->entries [slot] = NULL;
794 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
796 /* print a warning? */
798 mono_perfcounters->gc_num_handles--;
799 /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
800 unlock_handles (handles);
804 * mono_gchandle_free_domain:
805 * @domain: domain that is unloading
807 * Function used internally to cleanup any GC handle for objects belonging
808 * to the specified domain during appdomain unload.
811 mono_gchandle_free_domain (MonoDomain *domain)
815 for (type = 0; type < 3; ++type) {
817 HandleData *handles = &gc_handles [type];
818 lock_handles (handles);
819 for (slot = 0; slot < handles->size; ++slot) {
820 if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
822 if (type <= HANDLE_WEAK_TRACK) {
823 if (domain->domain_id == handles->domain_ids [slot]) {
824 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
825 if (handles->entries [slot])
826 mono_gc_weak_link_remove (&handles->entries [slot]);
829 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
830 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
831 handles->entries [slot] = NULL;
835 unlock_handles (handles);
843 static sem_t finalizer_sem;
845 static HANDLE finalizer_event;
846 static volatile gboolean finished=FALSE;
849 mono_gc_finalize_notify (void)
852 g_message (G_GNUC_PRETTY_FUNCTION ": prodding finalizer");
856 sem_post (&finalizer_sem);
858 SetEvent (finalizer_event);
865 collect_objects (gpointer key, gpointer value, gpointer user_data)
867 GPtrArray *arr = (GPtrArray*)user_data;
868 g_ptr_array_add (arr, key);
874 * finalize_domain_objects:
876 * Run the finalizers of all finalizable objects in req->domain.
879 finalize_domain_objects (DomainFinalizationReq *req)
881 MonoDomain *domain = req->domain;
884 while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
888 * Since the domain is unloading, nobody is allowed to put
889 * new entries into the hash table. But finalize_object might
890 * remove entries from the hash table, so we make a copy.
892 objs = g_ptr_array_new ();
893 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
894 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
896 for (i = 0; i < objs->len; ++i) {
897 MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
898 /* FIXME: Avoid finalizing threads, etc */
902 g_ptr_array_free (objs, TRUE);
904 #elif defined(HAVE_SGEN_GC)
905 #define NUM_FOBJECTS 64
906 MonoObject *to_finalize [NUM_FOBJECTS];
908 while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
910 for (i = 0; i < count; ++i) {
911 run_finalize (to_finalize [i], 0);
916 /* Process finalizers which are already in the queue */
917 mono_gc_invoke_finalizers ();
919 /* printf ("DONE.\n"); */
920 SetEvent (req->done_event);
922 /* The event is closed in mono_domain_finalize if we get here */
927 finalizer_thread (gpointer unused)
929 gc_thread = mono_thread_current ();
931 SetEvent (thread_started_event);
934 /* Wait to be notified that there's at least one
938 sem_wait (&finalizer_sem);
940 /* Use alertable=FALSE since we will be asked to exit using the event too */
941 WaitForSingleObjectEx (finalizer_event, INFINITE, FALSE);
944 #ifndef DISABLE_ATTACH
945 mono_attach_maybe_start ();
948 if (domains_to_finalize) {
949 mono_finalizer_lock ();
950 if (domains_to_finalize) {
951 DomainFinalizationReq *req = domains_to_finalize->data;
952 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
953 mono_finalizer_unlock ();
955 finalize_domain_objects (req);
957 mono_finalizer_unlock ();
961 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
962 * before the domain is unloaded.
964 mono_gc_invoke_finalizers ();
966 SetEvent (pending_done_event);
969 SetEvent (shutdown_event);
976 InitializeCriticalSection (&handle_section);
977 InitializeCriticalSection (&allocator_section);
979 InitializeCriticalSection (&finalizer_mutex);
981 MONO_GC_REGISTER_ROOT (gc_handles [HANDLE_NORMAL].entries);
982 MONO_GC_REGISTER_ROOT (gc_handles [HANDLE_PINNED].entries);
984 mono_gc_base_init ();
986 if (g_getenv ("GC_DONT_GC")) {
991 finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
992 pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
993 shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
994 thread_started_event = CreateEvent (NULL, TRUE, FALSE, NULL);
995 if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL || thread_started_event == NULL) {
996 g_assert_not_reached ();
999 sem_init (&finalizer_sem, 0, 0);
1002 mono_thread_create (mono_domain_get (), finalizer_thread, NULL);
1005 * Wait until the finalizer thread sets gc_thread since its value is needed
1006 * by mono_thread_attach ()
1008 * FIXME: Eliminate this as to avoid some deadlocks on windows.
1009 * Waiting for a new thread should result in a deadlock when the runtime is
1010 * initialized from _CorDllMain that is called while the OS loader lock is
1011 * held by LoadLibrary.
1013 WaitForSingleObjectEx (thread_started_event, INFINITE, FALSE);
1017 mono_gc_cleanup (void)
1020 g_message (G_GNUC_PRETTY_FUNCTION ": cleaning up finalizer");
1024 ResetEvent (shutdown_event);
1026 if (mono_thread_current () != gc_thread) {
1027 mono_gc_finalize_notify ();
1028 /* Finishing the finalizer thread, so wait a little bit... */
1029 /* MS seems to wait for about 2 seconds */
1030 if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1033 /* Set a flag which the finalizer thread can check */
1034 suspend_finalizers = TRUE;
1036 /* Try to abort the thread, in the hope that it is running managed code */
1037 mono_thread_stop (gc_thread);
1039 /* Wait for it to stop */
1040 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1042 if (ret == WAIT_TIMEOUT) {
1044 * The finalizer thread refused to die. There is not much we
1045 * can do here, since the runtime is shutting down so the
1046 * state the finalizer thread depends on will vanish.
1048 g_warning ("Shutting down finalizer thread timed out.");
1051 * FIXME: On unix, when the above wait returns, the thread
1052 * might still be running io-layer code, or pthreads code.
1060 #ifdef HAVE_BOEHM_GC
1061 GC_finalizer_notifier = NULL;
1065 DeleteCriticalSection (&handle_section);
1066 DeleteCriticalSection (&allocator_section);
1067 DeleteCriticalSection (&finalizer_mutex);
1072 /* Null GC dummy functions */
1074 mono_gc_finalize_notify (void)
1078 void mono_gc_init (void)
1080 InitializeCriticalSection (&handle_section);
1083 void mono_gc_cleanup (void)
1090 * mono_gc_is_finalizer_thread:
1091 * @thread: the thread to test.
1093 * In Mono objects are finalized asynchronously on a separate thread.
1094 * This routine tests whether the @thread argument represents the
1095 * finalization thread.
1097 * Returns true if @thread is the finalization thread.
1100 mono_gc_is_finalizer_thread (MonoThread *thread)
1102 return thread == gc_thread;