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