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