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