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