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