Merge pull request #3037 from mono/system_io_compression_datetime
[mono.git] / mono / metadata / gc.c
1 /*
2  * metadata/gc.c: GC icalls.
3  *
4  * Author: Paolo Molaro <lupus@ximian.com>
5  *
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)
9  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #include <config.h>
13 #include <glib.h>
14 #include <string.h>
15
16 #include <mono/metadata/gc-internals.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/threads-types.h>
27 #include <mono/metadata/threadpool-ms.h>
28 #include <mono/sgen/sgen-conf.h>
29 #include <mono/sgen/sgen-gc.h>
30 #include <mono/utils/mono-logger-internals.h>
31 #include <mono/metadata/gc-internals.h>
32 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
33 #include <mono/metadata/attach.h>
34 #include <mono/metadata/console-io.h>
35 #include <mono/utils/mono-os-semaphore.h>
36 #include <mono/utils/mono-memory-model.h>
37 #include <mono/utils/mono-counters.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/dtrace.h>
40 #include <mono/utils/mono-threads.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-coop-semaphore.h>
43 #include <mono/utils/hazard-pointer.h>
44
45 #ifndef HOST_WIN32
46 #include <pthread.h>
47 #endif
48
49 typedef struct DomainFinalizationReq {
50         MonoDomain *domain;
51         HANDLE done_event;
52 } DomainFinalizationReq;
53
54 static gboolean gc_disabled = FALSE;
55
56 static gboolean finalizing_root_domain = FALSE;
57
58 gboolean log_finalizers = FALSE;
59 gboolean mono_do_not_finalize = FALSE;
60 gchar **mono_do_not_finalize_class_names = NULL;
61
62 #define mono_finalizer_lock() mono_coop_mutex_lock (&finalizer_mutex)
63 #define mono_finalizer_unlock() mono_coop_mutex_unlock (&finalizer_mutex)
64 static MonoCoopMutex finalizer_mutex;
65 static MonoCoopMutex reference_queue_mutex;
66
67 static GSList *domains_to_finalize= NULL;
68 static MonoMList *threads_to_finalize = NULL;
69
70 static gboolean finalizer_thread_exited;
71 /* Uses finalizer_mutex */
72 static MonoCoopCond exited_cond;
73
74 static MonoInternalThread *gc_thread;
75
76 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
77
78 static void reference_queue_proccess_all (void);
79 static void mono_reference_queue_cleanup (void);
80 static void reference_queue_clear_for_domain (MonoDomain *domain);
81 static HANDLE pending_done_event;
82
83 static guint32
84 guarded_wait (HANDLE handle, guint32 timeout, gboolean alertable)
85 {
86         guint32 result;
87
88         MONO_ENTER_GC_SAFE;
89         result = WaitForSingleObjectEx (handle, timeout, alertable);
90         MONO_EXIT_GC_SAFE;
91
92         return result;
93 }
94
95 static gboolean
96 add_thread_to_finalize (MonoInternalThread *thread, MonoError *error)
97 {
98         mono_error_init (error);
99         mono_finalizer_lock ();
100         if (!threads_to_finalize)
101                 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize, MONO_ROOT_SOURCE_FINALIZER_QUEUE, "finalizable threads list");
102         threads_to_finalize = mono_mlist_append_checked (threads_to_finalize, (MonoObject*)thread, error);
103         mono_finalizer_unlock ();
104         return is_ok (error);
105 }
106
107 static gboolean suspend_finalizers = FALSE;
108 /* 
109  * actually, we might want to queue the finalize requests in a separate thread,
110  * but we need to be careful about the execution domain of the thread...
111  */
112 void
113 mono_gc_run_finalize (void *obj, void *data)
114 {
115         MonoError error;
116         MonoObject *exc = NULL;
117         MonoObject *o;
118 #ifndef HAVE_SGEN_GC
119         MonoObject *o2;
120 #endif
121         MonoMethod* finalizer = NULL;
122         MonoDomain *caller_domain = mono_domain_get ();
123         MonoDomain *domain;
124         RuntimeInvokeFunction runtime_invoke;
125
126         // This function is called from the innards of the GC, so our best alternative for now is to do polling here
127         mono_threads_safepoint ();
128
129         o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
130
131         if (mono_do_not_finalize) {
132                 if (!mono_do_not_finalize_class_names)
133                         return;
134
135                 size_t namespace_len = strlen (o->vtable->klass->name_space);
136                 for (int i = 0; mono_do_not_finalize_class_names [i]; ++i) {
137                         const char *name = mono_do_not_finalize_class_names [i];
138                         if (strncmp (name, o->vtable->klass->name_space, namespace_len))
139                                 break;
140                         if (name [namespace_len] != '.')
141                                 break;
142                         if (strcmp (name + namespace_len + 1, o->vtable->klass->name))
143                                 break;
144                         return;
145                 }
146         }
147
148         if (log_finalizers)
149                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_DEBUG, "<%s at %p> Starting finalizer checks.", o->vtable->klass->name, o);
150
151         if (suspend_finalizers)
152                 return;
153
154         domain = o->vtable->domain;
155
156 #ifndef HAVE_SGEN_GC
157         mono_domain_finalizers_lock (domain);
158
159         o2 = (MonoObject *)g_hash_table_lookup (domain->finalizable_objects_hash, o);
160
161         mono_domain_finalizers_unlock (domain);
162
163         if (!o2)
164                 /* Already finalized somehow */
165                 return;
166 #endif
167
168         /* make sure the finalizer is not called again if the object is resurrected */
169         object_register_finalizer ((MonoObject *)obj, NULL);
170
171         if (log_finalizers)
172                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Registered finalizer as processed.", o->vtable->klass->name, o);
173
174         if (o->vtable->klass == mono_defaults.internal_thread_class) {
175                 MonoInternalThread *t = (MonoInternalThread*)o;
176
177                 if (mono_gc_is_finalizer_internal_thread (t))
178                         /* Avoid finalizing ourselves */
179                         return;
180
181                 if (t->threadpool_thread && finalizing_root_domain) {
182                         /* Don't finalize threadpool threads when
183                            shutting down - they're finalized when the
184                            threadpool shuts down. */
185                         if (!add_thread_to_finalize (t, &error))
186                                 goto unhandled_error;
187                         return;
188                 }
189         }
190
191         if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
192                 /*
193                  * These can't be finalized during unloading/shutdown, since that would
194                  * free the native code which can still be referenced by other
195                  * finalizers.
196                  * FIXME: This is not perfect, objects dying at the same time as 
197                  * dynamic methods can still reference them even when !shutdown.
198                  */
199                 return;
200         }
201
202         if (mono_runtime_get_no_exec ())
203                 return;
204
205         /* speedup later... and use a timeout */
206         /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
207
208         /* Use _internal here, since this thread can enter a doomed appdomain */
209         mono_domain_set_internal (mono_object_domain (o));
210
211         /* delegates that have a native function pointer allocated are
212          * registered for finalization, but they don't have a Finalize
213          * method, because in most cases it's not needed and it's just a waste.
214          */
215         if (o->vtable->klass->delegate) {
216                 MonoDelegate* del = (MonoDelegate*)o;
217                 if (del->delegate_trampoline)
218                         mono_delegate_free_ftnptr ((MonoDelegate*)o);
219                 mono_domain_set_internal (caller_domain);
220                 return;
221         }
222
223         finalizer = mono_class_get_finalizer (o->vtable->klass);
224
225         /* If object has a CCW but has no finalizer, it was only
226          * registered for finalization in order to free the CCW.
227          * Else it needs the regular finalizer run.
228          * FIXME: what to do about ressurection and suppression
229          * of finalizer on object with CCW.
230          */
231         if (mono_marshal_free_ccw (o) && !finalizer) {
232                 mono_domain_set_internal (caller_domain);
233                 return;
234         }
235
236         /* 
237          * To avoid the locking plus the other overhead of mono_runtime_invoke_checked (),
238          * create and precompile a wrapper which calls the finalize method using
239          * a CALLVIRT.
240          */
241         if (log_finalizers)
242                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Compiling finalizer.", o->vtable->klass->name, o);
243
244         if (!domain->finalize_runtime_invoke) {
245                 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
246
247                 domain->finalize_runtime_invoke = mono_compile_method_checked (invoke, &error);
248                 mono_error_assert_ok (&error); /* expect this not to fail */
249         }
250
251         runtime_invoke = (RuntimeInvokeFunction)domain->finalize_runtime_invoke;
252
253         mono_runtime_class_init_full (o->vtable, &error);
254         if (!is_ok (&error))
255                 goto unhandled_error;
256
257         if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
258                 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
259                                 o->vtable->klass->name_space, o->vtable->klass->name);
260         }
261
262         if (log_finalizers)
263                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o->vtable->klass->name, o);
264
265         runtime_invoke (o, NULL, &exc, NULL);
266
267         if (log_finalizers)
268                 g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o);
269
270 unhandled_error:
271         if (!is_ok (&error))
272                 exc = (MonoObject*)mono_error_convert_to_exception (&error);
273         if (exc)
274                 mono_thread_internal_unhandled_exception (exc);
275
276         mono_domain_set_internal (caller_domain);
277 }
278
279 void
280 mono_gc_finalize_threadpool_threads (void)
281 {
282         while (threads_to_finalize) {
283                 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
284
285                 /* Force finalization of the thread. */
286                 thread->threadpool_thread = FALSE;
287                 mono_object_register_finalizer ((MonoObject*)thread);
288
289                 mono_gc_run_finalize (thread, NULL);
290
291                 threads_to_finalize = mono_mlist_next (threads_to_finalize);
292         }
293 }
294
295 gpointer
296 mono_gc_out_of_memory (size_t size)
297 {
298         /* 
299          * we could allocate at program startup some memory that we could release 
300          * back to the system at this point if we're really low on memory (ie, size is
301          * lower than the memory we set apart)
302          */
303         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
304
305         return NULL;
306 }
307
308 /*
309  * Some of our objects may point to a different address than the address returned by GC_malloc()
310  * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
311  * This also means that in the callback we need to adjust the pointer to get back the real
312  * MonoObject*.
313  * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
314  * since that, too, can cause the underlying pointer to be offset.
315  */
316 static void
317 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
318 {
319         MonoDomain *domain;
320
321         g_assert (obj != NULL);
322
323         domain = obj->vtable->domain;
324
325 #if HAVE_BOEHM_GC
326         if (mono_domain_is_unloading (domain) && (callback != NULL))
327                 /*
328                  * Can't register finalizers in a dying appdomain, since they
329                  * could be invoked after the appdomain has been unloaded.
330                  */
331                 return;
332
333         mono_domain_finalizers_lock (domain);
334
335         if (callback)
336                 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
337         else
338                 g_hash_table_remove (domain->finalizable_objects_hash, obj);
339
340         mono_domain_finalizers_unlock (domain);
341
342         mono_gc_register_for_finalization (obj, callback);
343 #elif defined(HAVE_SGEN_GC)
344         /*
345          * If we register finalizers for domains that are unloading we might
346          * end up running them while or after the domain is being cleared, so
347          * the objects will not be valid anymore.
348          */
349         if (!mono_domain_is_unloading (domain))
350                 mono_gc_register_for_finalization (obj, callback);
351 #endif
352 }
353
354 /**
355  * mono_object_register_finalizer:
356  * @obj: object to register
357  *
358  * Records that object @obj has a finalizer, this will call the
359  * Finalize method when the garbage collector disposes the object.
360  * 
361  */
362 void
363 mono_object_register_finalizer (MonoObject *obj)
364 {
365         /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
366         object_register_finalizer (obj, mono_gc_run_finalize);
367 }
368
369 /**
370  * mono_domain_finalize:
371  * @domain: the domain to finalize
372  * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
373  *
374  *  Request finalization of all finalizable objects inside @domain. Wait
375  * @timeout msecs for the finalization to complete.
376  *
377  * Returns: TRUE if succeeded, FALSE if there was a timeout
378  */
379
380 gboolean
381 mono_domain_finalize (MonoDomain *domain, guint32 timeout) 
382 {
383         DomainFinalizationReq *req;
384         guint32 res;
385         HANDLE done_event;
386         MonoInternalThread *thread = mono_thread_internal_current ();
387
388 #if defined(__native_client__)
389         return FALSE;
390 #endif
391
392         if (mono_thread_internal_current () == gc_thread)
393                 /* We are called from inside a finalizer, not much we can do here */
394                 return FALSE;
395
396         /* 
397          * No need to create another thread 'cause the finalizer thread
398          * is still working and will take care of running the finalizers
399          */ 
400         
401         if (gc_disabled)
402                 return TRUE;
403
404         /* We don't support domain finalization without a GC */
405         if (mono_gc_is_null ())
406                 return FALSE;
407
408         mono_gc_collect (mono_gc_max_generation ());
409
410         done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
411         if (done_event == NULL) {
412                 return FALSE;
413         }
414
415         req = g_new0 (DomainFinalizationReq, 1);
416         req->domain = domain;
417         req->done_event = done_event;
418
419         if (domain == mono_get_root_domain ())
420                 finalizing_root_domain = TRUE;
421         
422         mono_finalizer_lock ();
423
424         domains_to_finalize = g_slist_append (domains_to_finalize, req);
425
426         mono_finalizer_unlock ();
427
428         /* Tell the finalizer thread to finalize this appdomain */
429         mono_gc_finalize_notify ();
430
431         if (timeout == -1)
432                 timeout = INFINITE;
433
434         while (TRUE) {
435                 res = guarded_wait (done_event, timeout, TRUE);
436                 /* printf ("WAIT RES: %d.\n", res); */
437
438                 if (res == WAIT_IO_COMPLETION) {
439                         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
440                                 return FALSE;
441                 } else if (res == WAIT_TIMEOUT) {
442                         /* We leak the handle here */
443                         return FALSE;
444                 } else {
445                         break;
446                 }
447         }
448
449         CloseHandle (done_event);
450
451         if (domain == mono_get_root_domain ()) {
452                 mono_threadpool_ms_cleanup ();
453                 mono_gc_finalize_threadpool_threads ();
454         }
455
456         mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
457
458         return TRUE;
459 }
460
461 void
462 ves_icall_System_GC_InternalCollect (int generation)
463 {
464         mono_gc_collect (generation);
465 }
466
467 gint64
468 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
469 {
470         if (forceCollection)
471                 mono_gc_collect (mono_gc_max_generation ());
472         return mono_gc_get_used_size ();
473 }
474
475 void
476 ves_icall_System_GC_KeepAlive (MonoObject *obj)
477 {
478         /*
479          * Does nothing.
480          */
481 }
482
483 void
484 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
485 {
486         MONO_CHECK_ARG_NULL (obj,);
487
488         object_register_finalizer (obj, mono_gc_run_finalize);
489 }
490
491 void
492 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
493 {
494         MONO_CHECK_ARG_NULL (obj,);
495
496         /* delegates have no finalizers, but we register them to deal with the
497          * unmanaged->managed trampoline. We don't let the user suppress it
498          * otherwise we'd leak it.
499          */
500         if (obj->vtable->klass->delegate)
501                 return;
502
503         /* FIXME: Need to handle case where obj has COM Callable Wrapper
504          * generated for it that needs cleaned up, but user wants to suppress
505          * their derived object finalizer. */
506
507         object_register_finalizer (obj, NULL);
508 }
509
510 void
511 ves_icall_System_GC_WaitForPendingFinalizers (void)
512 {
513         if (mono_gc_is_null ())
514                 return;
515
516         if (!mono_gc_pending_finalizers ())
517                 return;
518
519         if (mono_thread_internal_current () == gc_thread)
520                 /* Avoid deadlocks */
521                 return;
522
523         /*
524         If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
525         be the one responsible for starting it up.
526         */
527         if (gc_thread == NULL)
528                 return;
529
530         ResetEvent (pending_done_event);
531         mono_gc_finalize_notify ();
532         /* g_print ("Waiting for pending finalizers....\n"); */
533         guarded_wait (pending_done_event, INFINITE, TRUE);
534         /* g_print ("Done pending....\n"); */
535 }
536
537 void
538 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
539 {
540 #ifdef HAVE_SGEN_GC
541         if (!mono_gc_ephemeron_array_add (array)) {
542                 mono_set_pending_exception (mono_object_domain (array)->out_of_memory_ex);
543                 return;
544         }
545 #endif
546 }
547
548 MonoObject*
549 ves_icall_System_GC_get_ephemeron_tombstone (void)
550 {
551         return mono_domain_get ()->ephemeron_tombstone;
552 }
553
554 MonoObject *
555 ves_icall_System_GCHandle_GetTarget (guint32 handle)
556 {
557         return mono_gchandle_get_target (handle);
558 }
559
560 /*
561  * if type == -1, change the target of the handle, otherwise allocate a new handle.
562  */
563 guint32
564 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
565 {
566         if (type == -1) {
567                 mono_gchandle_set_target (handle, obj);
568                 /* the handle doesn't change */
569                 return handle;
570         }
571         switch (type) {
572         case HANDLE_WEAK:
573                 return mono_gchandle_new_weakref (obj, FALSE);
574         case HANDLE_WEAK_TRACK:
575                 return mono_gchandle_new_weakref (obj, TRUE);
576         case HANDLE_NORMAL:
577                 return mono_gchandle_new (obj, FALSE);
578         case HANDLE_PINNED:
579                 return mono_gchandle_new (obj, TRUE);
580         default:
581                 g_assert_not_reached ();
582         }
583         return 0;
584 }
585
586 void
587 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
588 {
589         mono_gchandle_free (handle);
590 }
591
592 gpointer
593 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
594 {
595         MonoObject *obj;
596
597         if (MONO_GC_HANDLE_TYPE (handle) != HANDLE_PINNED)
598                 return (gpointer)-2;
599         obj = mono_gchandle_get_target (handle);
600         if (obj) {
601                 MonoClass *klass = mono_object_class (obj);
602                 if (klass == mono_defaults.string_class) {
603                         return mono_string_chars ((MonoString*)obj);
604                 } else if (klass->rank) {
605                         return mono_array_addr ((MonoArray*)obj, char, 0);
606                 } else {
607                         /* the C# code will check and throw the exception */
608                         /* FIXME: missing !klass->blittable test, see bug #61134 */
609                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
610                                 return (gpointer)-1;
611                         return (char*)obj + sizeof (MonoObject);
612                 }
613         }
614         return NULL;
615 }
616
617 MonoBoolean
618 mono_gc_GCHandle_CheckCurrentDomain (guint32 gchandle)
619 {
620         return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
621 }
622
623 static MonoCoopSem finalizer_sem;
624 static volatile gboolean finished=FALSE;
625
626 void
627 mono_gc_finalize_notify (void)
628 {
629 #ifdef DEBUG
630         g_message ( "%s: prodding finalizer", __func__);
631 #endif
632
633         if (mono_gc_is_null ())
634                 return;
635
636         mono_coop_sem_post (&finalizer_sem);
637 }
638
639 /*
640 This is the number of entries allowed in the hazard free queue before
641 we explicitly cycle the finalizer thread to trigger pumping the queue.
642
643 It was picked empirically by running the corlib test suite in a stress
644 scenario where all hazard entries are queued.
645
646 In this extreme scenario we double the number of times we cycle the finalizer
647 thread compared to just GC calls.
648
649 Entries are usually in the order of 100's of bytes each, so we're limiting
650 floating garbage to be in the order of a dozen kb.
651 */
652 static gboolean finalizer_thread_pulsed;
653 #define HAZARD_QUEUE_OVERFLOW_SIZE 20
654
655 static void
656 hazard_free_queue_is_too_big (size_t size)
657 {
658         if (size < HAZARD_QUEUE_OVERFLOW_SIZE)
659                 return;
660
661         if (finalizer_thread_pulsed || InterlockedCompareExchange (&finalizer_thread_pulsed, TRUE, FALSE))
662                 return;
663
664         mono_gc_finalize_notify ();
665 }
666
667 static void
668 hazard_free_queue_pump (void)
669 {
670         mono_thread_hazardous_try_free_all ();
671         finalizer_thread_pulsed = FALSE;
672 }
673
674 #ifdef HAVE_BOEHM_GC
675
676 static void
677 collect_objects (gpointer key, gpointer value, gpointer user_data)
678 {
679         GPtrArray *arr = (GPtrArray*)user_data;
680         g_ptr_array_add (arr, key);
681 }
682
683 #endif
684
685 /*
686  * finalize_domain_objects:
687  *
688  *  Run the finalizers of all finalizable objects in req->domain.
689  */
690 static void
691 finalize_domain_objects (DomainFinalizationReq *req)
692 {
693         MonoDomain *domain = req->domain;
694
695 #if HAVE_SGEN_GC
696 #define NUM_FOBJECTS 64
697         MonoObject *to_finalize [NUM_FOBJECTS];
698         int count;
699 #endif
700
701         /* Process finalizers which are already in the queue */
702         mono_gc_invoke_finalizers ();
703
704 #ifdef HAVE_BOEHM_GC
705         while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
706                 int i;
707                 GPtrArray *objs;
708                 /* 
709                  * Since the domain is unloading, nobody is allowed to put
710                  * new entries into the hash table. But finalize_object might
711                  * remove entries from the hash table, so we make a copy.
712                  */
713                 objs = g_ptr_array_new ();
714                 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
715                 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
716
717                 for (i = 0; i < objs->len; ++i) {
718                         MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
719                         /* FIXME: Avoid finalizing threads, etc */
720                         mono_gc_run_finalize (o, 0);
721                 }
722
723                 g_ptr_array_free (objs, TRUE);
724         }
725 #elif defined(HAVE_SGEN_GC)
726         while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
727                 int i;
728                 for (i = 0; i < count; ++i) {
729                         mono_gc_run_finalize (to_finalize [i], 0);
730                 }
731         }
732 #endif
733
734         /* cleanup the reference queue */
735         reference_queue_clear_for_domain (domain);
736         
737         /* printf ("DONE.\n"); */
738         SetEvent (req->done_event);
739
740         /* The event is closed in mono_domain_finalize if we get here */
741         g_free (req);
742 }
743
744 static guint32
745 finalizer_thread (gpointer unused)
746 {
747         MonoError error;
748         mono_thread_set_name_internal (mono_thread_internal_current (), mono_string_new (mono_get_root_domain (), "Finalizer"), FALSE, &error);
749         mono_error_assert_ok (&error);
750
751         gboolean wait = TRUE;
752
753         /* Register a hazard free queue pump callback */
754         mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);
755
756         while (!finished) {
757                 /* Wait to be notified that there's at least one
758                  * finaliser to run
759                  */
760
761                 g_assert (mono_domain_get () == mono_get_root_domain ());
762                 mono_gc_set_skip_thread (TRUE);
763
764                 if (wait) {
765                         /* An alertable wait is required so this thread can be suspended on windows */
766                         mono_coop_sem_wait (&finalizer_sem, MONO_SEM_FLAGS_ALERTABLE);
767                 }
768                 wait = TRUE;
769
770                 mono_gc_set_skip_thread (FALSE);
771
772                 mono_threads_perform_thread_dump ();
773
774                 mono_console_handle_async_ops ();
775
776                 mono_attach_maybe_start ();
777
778                 if (domains_to_finalize) {
779                         mono_finalizer_lock ();
780                         if (domains_to_finalize) {
781                                 DomainFinalizationReq *req = (DomainFinalizationReq *)domains_to_finalize->data;
782                                 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
783                                 mono_finalizer_unlock ();
784
785                                 finalize_domain_objects (req);
786                         } else {
787                                 mono_finalizer_unlock ();
788                         }
789                 }                               
790
791                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
792                  * before the domain is unloaded.
793                  */
794                 mono_gc_invoke_finalizers ();
795
796                 mono_threads_join_threads ();
797
798                 reference_queue_proccess_all ();
799
800                 hazard_free_queue_pump ();
801
802                 /* Avoid posting the pending done event until there are pending finalizers */
803                 if (mono_coop_sem_timedwait (&finalizer_sem, 0, MONO_SEM_FLAGS_NONE) == 0) {
804                         /* Don't wait again at the start of the loop */
805                         wait = FALSE;
806                 } else {
807                         SetEvent (pending_done_event);
808                 }
809         }
810
811         mono_finalizer_lock ();
812         finalizer_thread_exited = TRUE;
813         mono_coop_cond_signal (&exited_cond);
814         mono_finalizer_unlock ();
815
816         return 0;
817 }
818
819 #ifndef LAZY_GC_THREAD_CREATION
820 static
821 #endif
822 void
823 mono_gc_init_finalizer_thread (void)
824 {
825         MonoError error;
826         gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0, &error);
827         mono_error_assert_ok (&error);
828 }
829
830 void
831 mono_gc_init (void)
832 {
833         mono_coop_mutex_init_recursive (&finalizer_mutex);
834         mono_coop_mutex_init_recursive (&reference_queue_mutex);
835
836         mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.minor_gc_count);
837         mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_UINT, &gc_stats.major_gc_count);
838         mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.minor_gc_time);
839         mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time);
840         mono_counters_register ("Major GC time concurrent", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &gc_stats.major_gc_time_concurrent);
841
842         mono_gc_base_init ();
843
844         if (mono_gc_is_disabled ()) {
845                 gc_disabled = TRUE;
846                 return;
847         }
848
849         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
850         g_assert (pending_done_event);
851         mono_coop_cond_init (&exited_cond);
852         mono_coop_sem_init (&finalizer_sem, 0);
853
854 #ifndef LAZY_GC_THREAD_CREATION
855         mono_gc_init_finalizer_thread ();
856 #endif
857 }
858
859 void
860 mono_gc_cleanup (void)
861 {
862 #ifdef DEBUG
863         g_message ("%s: cleaning up finalizer", __func__);
864 #endif
865
866         if (mono_gc_is_null ())
867                 return;
868
869         if (!gc_disabled) {
870                 finished = TRUE;
871                 if (mono_thread_internal_current () != gc_thread) {
872                         gboolean timed_out = FALSE;
873                         gint64 start_ticks = mono_msec_ticks ();
874                         gint64 end_ticks = start_ticks + 2000;
875
876                         mono_gc_finalize_notify ();
877                         /* Finishing the finalizer thread, so wait a little bit... */
878                         /* MS seems to wait for about 2 seconds */
879                         while (!finalizer_thread_exited) {
880                                 gint64 current_ticks = mono_msec_ticks ();
881                                 guint32 timeout;
882
883                                 if (current_ticks >= end_ticks)
884                                         break;
885                                 else
886                                         timeout = end_ticks - current_ticks;
887                                 mono_finalizer_lock ();
888                                 if (!finalizer_thread_exited)
889                                         mono_coop_cond_timedwait (&exited_cond, &finalizer_mutex, timeout);
890                                 mono_finalizer_unlock ();
891                         }
892
893                         if (!finalizer_thread_exited) {
894                                 int ret;
895
896                                 /* Set a flag which the finalizer thread can check */
897                                 suspend_finalizers = TRUE;
898
899                                 /* Try to abort the thread, in the hope that it is running managed code */
900                                 mono_thread_internal_stop (gc_thread);
901
902                                 /* Wait for it to stop */
903                                 ret = guarded_wait (gc_thread->handle, 100, TRUE);
904
905                                 if (ret == WAIT_TIMEOUT) {
906                                         /* 
907                                          * The finalizer thread refused to die. There is not much we 
908                                          * can do here, since the runtime is shutting down so the 
909                                          * state the finalizer thread depends on will vanish.
910                                          */
911                                         g_warning ("Shutting down finalizer thread timed out.");
912                                         timed_out = TRUE;
913                                 }
914                         }
915
916                         if (!timed_out) {
917                                 int ret;
918
919                                 /* Wait for the thread to actually exit */
920                                 ret = guarded_wait (gc_thread->handle, INFINITE, TRUE);
921                                 g_assert (ret == WAIT_OBJECT_0);
922
923                                 mono_thread_join (GUINT_TO_POINTER (gc_thread->tid));
924                         }
925                         g_assert (finalizer_thread_exited);
926                 }
927                 gc_thread = NULL;
928                 mono_gc_base_cleanup ();
929         }
930
931         mono_reference_queue_cleanup ();
932
933         mono_coop_mutex_destroy (&finalizer_mutex);
934         mono_coop_mutex_destroy (&reference_queue_mutex);
935 }
936
937 gboolean
938 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
939 {
940         return thread == gc_thread;
941 }
942
943 /**
944  * mono_gc_is_finalizer_thread:
945  * @thread: the thread to test.
946  *
947  * In Mono objects are finalized asynchronously on a separate thread.
948  * This routine tests whether the @thread argument represents the
949  * finalization thread.
950  * 
951  * Returns: TRUE if @thread is the finalization thread.
952  */
953 gboolean
954 mono_gc_is_finalizer_thread (MonoThread *thread)
955 {
956         return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
957 }
958
959 #if defined(__MACH__)
960 static pthread_t mach_exception_thread;
961
962 void
963 mono_gc_register_mach_exception_thread (pthread_t thread)
964 {
965         mach_exception_thread = thread;
966 }
967
968 pthread_t
969 mono_gc_get_mach_exception_thread (void)
970 {
971         return mach_exception_thread;
972 }
973 #endif
974
975 static MonoReferenceQueue *ref_queues;
976
977 static void
978 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
979 {
980         do {
981                 /* Guard if head is changed concurrently. */
982                 while (*prev != element)
983                         prev = &(*prev)->next;
984         } while (prev && InterlockedCompareExchangePointer ((volatile gpointer *)prev, element->next, element) != element);
985 }
986
987 static void
988 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
989 {
990         RefQueueEntry *current;
991         do {
992                 current = *head;
993                 value->next = current;
994                 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
995         } while (InterlockedCompareExchangePointer ((volatile gpointer *)head, value, current) != current);
996 }
997
998 static void
999 reference_queue_proccess (MonoReferenceQueue *queue)
1000 {
1001         RefQueueEntry **iter = &queue->queue;
1002         RefQueueEntry *entry;
1003         while ((entry = *iter)) {
1004                 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1005                         mono_gchandle_free ((guint32)entry->gchandle);
1006                         ref_list_remove_element (iter, entry);
1007                         queue->callback (entry->user_data);
1008                         g_free (entry);
1009                 } else {
1010                         iter = &entry->next;
1011                 }
1012         }
1013 }
1014
1015 static void
1016 reference_queue_proccess_all (void)
1017 {
1018         MonoReferenceQueue **iter;
1019         MonoReferenceQueue *queue = ref_queues;
1020         for (; queue; queue = queue->next)
1021                 reference_queue_proccess (queue);
1022
1023 restart:
1024         mono_coop_mutex_lock (&reference_queue_mutex);
1025         for (iter = &ref_queues; *iter;) {
1026                 queue = *iter;
1027                 if (!queue->should_be_deleted) {
1028                         iter = &queue->next;
1029                         continue;
1030                 }
1031                 if (queue->queue) {
1032                         mono_coop_mutex_unlock (&reference_queue_mutex);
1033                         reference_queue_proccess (queue);
1034                         goto restart;
1035                 }
1036                 *iter = queue->next;
1037                 g_free (queue);
1038         }
1039         mono_coop_mutex_unlock (&reference_queue_mutex);
1040 }
1041
1042 static void
1043 mono_reference_queue_cleanup (void)
1044 {
1045         MonoReferenceQueue *queue = ref_queues;
1046         for (; queue; queue = queue->next)
1047                 queue->should_be_deleted = TRUE;
1048         reference_queue_proccess_all ();
1049 }
1050
1051 static void
1052 reference_queue_clear_for_domain (MonoDomain *domain)
1053 {
1054         MonoReferenceQueue *queue = ref_queues;
1055         for (; queue; queue = queue->next) {
1056                 RefQueueEntry **iter = &queue->queue;
1057                 RefQueueEntry *entry;
1058                 while ((entry = *iter)) {
1059                         if (entry->domain == domain) {
1060                                 mono_gchandle_free ((guint32)entry->gchandle);
1061                                 ref_list_remove_element (iter, entry);
1062                                 queue->callback (entry->user_data);
1063                                 g_free (entry);
1064                         } else {
1065                                 iter = &entry->next;
1066                         }
1067                 }
1068         }
1069 }
1070 /**
1071  * mono_gc_reference_queue_new:
1072  * @callback callback used when processing collected entries.
1073  *
1074  * Create a new reference queue used to process collected objects.
1075  * A reference queue let you add a pair of (managed object, user data)
1076  * using the mono_gc_reference_queue_add method.
1077  *
1078  * Once the managed object is collected @callback will be called
1079  * in the finalizer thread with 'user data' as argument.
1080  *
1081  * The callback is called from the finalizer thread without any locks held.
1082  * When a AppDomain is unloaded, all callbacks for objects belonging to it
1083  * will be invoked.
1084  *
1085  * @returns the new queue.
1086  */
1087 MonoReferenceQueue*
1088 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1089 {
1090         MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1091         res->callback = callback;
1092
1093         mono_coop_mutex_lock (&reference_queue_mutex);
1094         res->next = ref_queues;
1095         ref_queues = res;
1096         mono_coop_mutex_unlock (&reference_queue_mutex);
1097
1098         return res;
1099 }
1100
1101 /**
1102  * mono_gc_reference_queue_add:
1103  * @queue the queue to add the reference to.
1104  * @obj the object to be watched for collection
1105  * @user_data parameter to be passed to the queue callback
1106  *
1107  * Queue an object to be watched for collection, when the @obj is
1108  * collected, the callback that was registered for the @queue will
1109  * be invoked with @user_data as argument.
1110  *
1111  * @returns false if the queue is scheduled to be freed.
1112  */
1113 gboolean
1114 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1115 {
1116         RefQueueEntry *entry;
1117         if (queue->should_be_deleted)
1118                 return FALSE;
1119
1120         g_assert (obj != NULL);
1121
1122         entry = g_new0 (RefQueueEntry, 1);
1123         entry->user_data = user_data;
1124         entry->domain = mono_object_domain (obj);
1125
1126         entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1127         mono_object_register_finalizer (obj);
1128
1129         ref_list_push (&queue->queue, entry);
1130         return TRUE;
1131 }
1132
1133 /**
1134  * mono_gc_reference_queue_free:
1135  * @queue the queue that should be freed.
1136  *
1137  * This operation signals that @queue should be freed. This operation is deferred
1138  * as it happens on the finalizer thread.
1139  *
1140  * After this call, no further objects can be queued. It's the responsibility of the
1141  * caller to make sure that no further attempt to access queue will be made.
1142  */
1143 void
1144 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1145 {
1146         queue->should_be_deleted = TRUE;
1147 }