update .sln too.
[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  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <string.h>
14 #include <errno.h>
15
16 #include <mono/metadata/gc-internal.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/threadpool.h>
27 #include <mono/metadata/threadpool-internals.h>
28 #include <mono/metadata/threads-types.h>
29 #include <mono/utils/mono-logger-internal.h>
30 #include <mono/metadata/gc-internal.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-semaphore.h>
35 #include <mono/utils/mono-memory-model.h>
36 #include <mono/utils/mono-counters.h>
37 #include <mono/utils/dtrace.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/atomic.h>
40
41 #ifndef HOST_WIN32
42 #include <pthread.h>
43 #endif
44
45 typedef struct DomainFinalizationReq {
46         MonoDomain *domain;
47         HANDLE done_event;
48 } DomainFinalizationReq;
49
50 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
51 extern void (*__imp_GC_finalizer_notifier)(void);
52 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
53 extern int __imp_GC_finalize_on_demand;
54 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
55 #endif
56
57 static gboolean gc_disabled = FALSE;
58
59 static gboolean finalizing_root_domain = FALSE;
60
61 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
62 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
63 static CRITICAL_SECTION finalizer_mutex;
64 static CRITICAL_SECTION reference_queue_mutex;
65
66 static GSList *domains_to_finalize= NULL;
67 static MonoMList *threads_to_finalize = NULL;
68
69 static MonoInternalThread *gc_thread;
70
71 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
72
73 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
74
75 static void reference_queue_proccess_all (void);
76 static void mono_reference_queue_cleanup (void);
77 static void reference_queue_clear_for_domain (MonoDomain *domain);
78 #ifndef HAVE_NULL_GC
79 static HANDLE pending_done_event;
80 static HANDLE shutdown_event;
81 #endif
82
83 GCStats gc_stats;
84
85 static void
86 add_thread_to_finalize (MonoInternalThread *thread)
87 {
88         mono_finalizer_lock ();
89         if (!threads_to_finalize)
90                 MONO_GC_REGISTER_ROOT_SINGLE (threads_to_finalize);
91         threads_to_finalize = mono_mlist_append (threads_to_finalize, (MonoObject*)thread);
92         mono_finalizer_unlock ();
93 }
94
95 static gboolean suspend_finalizers = FALSE;
96 /* 
97  * actually, we might want to queue the finalize requests in a separate thread,
98  * but we need to be careful about the execution domain of the thread...
99  */
100 void
101 mono_gc_run_finalize (void *obj, void *data)
102 {
103         MonoObject *exc = NULL;
104         MonoObject *o;
105 #ifndef HAVE_SGEN_GC
106         MonoObject *o2;
107 #endif
108         MonoMethod* finalizer = NULL;
109         MonoDomain *caller_domain = mono_domain_get ();
110         MonoDomain *domain;
111         RuntimeInvokeFunction runtime_invoke;
112
113         o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
114
115         if (suspend_finalizers)
116                 return;
117
118         domain = o->vtable->domain;
119
120 #ifndef HAVE_SGEN_GC
121         mono_domain_finalizers_lock (domain);
122
123         o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
124
125         mono_domain_finalizers_unlock (domain);
126
127         if (!o2)
128                 /* Already finalized somehow */
129                 return;
130 #endif
131
132         /* make sure the finalizer is not called again if the object is resurrected */
133         object_register_finalizer (obj, NULL);
134
135         if (o->vtable->klass == mono_defaults.internal_thread_class) {
136                 MonoInternalThread *t = (MonoInternalThread*)o;
137
138                 if (mono_gc_is_finalizer_internal_thread (t))
139                         /* Avoid finalizing ourselves */
140                         return;
141
142                 if (t->threadpool_thread && finalizing_root_domain) {
143                         /* Don't finalize threadpool threads when
144                            shutting down - they're finalized when the
145                            threadpool shuts down. */
146                         add_thread_to_finalize (t);
147                         return;
148                 }
149         }
150
151         if (o->vtable->klass->image == mono_defaults.corlib && !strcmp (o->vtable->klass->name, "DynamicMethod") && finalizing_root_domain) {
152                 /*
153                  * These can't be finalized during unloading/shutdown, since that would
154                  * free the native code which can still be referenced by other
155                  * finalizers.
156                  * FIXME: This is not perfect, objects dying at the same time as 
157                  * dynamic methods can still reference them even when !shutdown.
158                  */
159                 return;
160         }
161
162         if (mono_runtime_get_no_exec ())
163                 return;
164
165         /* speedup later... and use a timeout */
166         /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
167
168         /* Use _internal here, since this thread can enter a doomed appdomain */
169         mono_domain_set_internal (mono_object_domain (o));
170
171         /* delegates that have a native function pointer allocated are
172          * registered for finalization, but they don't have a Finalize
173          * method, because in most cases it's not needed and it's just a waste.
174          */
175         if (o->vtable->klass->delegate) {
176                 MonoDelegate* del = (MonoDelegate*)o;
177                 if (del->delegate_trampoline)
178                         mono_delegate_free_ftnptr ((MonoDelegate*)o);
179                 mono_domain_set_internal (caller_domain);
180                 return;
181         }
182
183         finalizer = mono_class_get_finalizer (o->vtable->klass);
184
185 #ifndef DISABLE_COM
186         /* If object has a CCW but has no finalizer, it was only
187          * registered for finalization in order to free the CCW.
188          * Else it needs the regular finalizer run.
189          * FIXME: what to do about ressurection and suppression
190          * of finalizer on object with CCW.
191          */
192         if (mono_marshal_free_ccw (o) && !finalizer) {
193                 mono_domain_set_internal (caller_domain);
194                 return;
195         }
196 #endif
197
198         /* 
199          * To avoid the locking plus the other overhead of mono_runtime_invoke (),
200          * create and precompile a wrapper which calls the finalize method using
201          * a CALLVIRT.
202          */
203         if (!domain->finalize_runtime_invoke) {
204                 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
205
206                 domain->finalize_runtime_invoke = mono_compile_method (invoke);
207         }
208
209         runtime_invoke = domain->finalize_runtime_invoke;
210
211         mono_runtime_class_init (o->vtable);
212
213         if (G_UNLIKELY (MONO_GC_FINALIZE_INVOKE_ENABLED ())) {
214                 MONO_GC_FINALIZE_INVOKE ((unsigned long)o, mono_object_get_size (o),
215                                 o->vtable->klass->name_space, o->vtable->klass->name);
216         }
217
218         runtime_invoke (o, NULL, &exc, NULL);
219
220         if (exc)
221                 mono_internal_thread_unhandled_exception (exc);
222
223         mono_domain_set_internal (caller_domain);
224 }
225
226 void
227 mono_gc_finalize_threadpool_threads (void)
228 {
229         while (threads_to_finalize) {
230                 MonoInternalThread *thread = (MonoInternalThread*) mono_mlist_get_data (threads_to_finalize);
231
232                 /* Force finalization of the thread. */
233                 thread->threadpool_thread = FALSE;
234                 mono_object_register_finalizer ((MonoObject*)thread);
235
236                 mono_gc_run_finalize (thread, NULL);
237
238                 threads_to_finalize = mono_mlist_next (threads_to_finalize);
239         }
240 }
241
242 gpointer
243 mono_gc_out_of_memory (size_t size)
244 {
245         /* 
246          * we could allocate at program startup some memory that we could release 
247          * back to the system at this point if we're really low on memory (ie, size is
248          * lower than the memory we set apart)
249          */
250         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
251
252         return NULL;
253 }
254
255 /*
256  * Some of our objects may point to a different address than the address returned by GC_malloc()
257  * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
258  * This also means that in the callback we need to adjust the pointer to get back the real
259  * MonoObject*.
260  * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
261  * since that, too, can cause the underlying pointer to be offset.
262  */
263 static void
264 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
265 {
266         MonoDomain *domain;
267
268         if (obj == NULL)
269                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
270
271         domain = obj->vtable->domain;
272
273 #if HAVE_BOEHM_GC
274         if (mono_domain_is_unloading (domain) && (callback != NULL))
275                 /*
276                  * Can't register finalizers in a dying appdomain, since they
277                  * could be invoked after the appdomain has been unloaded.
278                  */
279                 return;
280
281         mono_domain_finalizers_lock (domain);
282
283         if (callback)
284                 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
285         else
286                 g_hash_table_remove (domain->finalizable_objects_hash, obj);
287
288         mono_domain_finalizers_unlock (domain);
289
290         mono_gc_register_for_finalization (obj, callback);
291 #elif defined(HAVE_SGEN_GC)
292         /*
293          * If we register finalizers for domains that are unloading we might
294          * end up running them while or after the domain is being cleared, so
295          * the objects will not be valid anymore.
296          */
297         if (!mono_domain_is_unloading (domain))
298                 mono_gc_register_for_finalization (obj, callback);
299 #endif
300 }
301
302 /**
303  * mono_object_register_finalizer:
304  * @obj: object to register
305  *
306  * Records that object @obj has a finalizer, this will call the
307  * Finalize method when the garbage collector disposes the object.
308  * 
309  */
310 void
311 mono_object_register_finalizer (MonoObject *obj)
312 {
313         /* g_print ("Registered finalizer on %p %s.%s\n", obj, mono_object_class (obj)->name_space, mono_object_class (obj)->name); */
314         object_register_finalizer (obj, mono_gc_run_finalize);
315 }
316
317 /**
318  * mono_domain_finalize:
319  * @domain: the domain to finalize
320  * @timeout: msects to wait for the finalization to complete, -1 to wait indefinitely
321  *
322  *  Request finalization of all finalizable objects inside @domain. Wait
323  * @timeout msecs for the finalization to complete.
324  *
325  * Returns: TRUE if succeeded, FALSE if there was a timeout
326  */
327
328 gboolean
329 mono_domain_finalize (MonoDomain *domain, guint32 timeout) 
330 {
331         DomainFinalizationReq *req;
332         guint32 res;
333         HANDLE done_event;
334         MonoInternalThread *thread = mono_thread_internal_current ();
335
336 #if defined(__native_client__)
337         return FALSE;
338 #endif
339
340         if (mono_thread_internal_current () == gc_thread)
341                 /* We are called from inside a finalizer, not much we can do here */
342                 return FALSE;
343
344         /* 
345          * No need to create another thread 'cause the finalizer thread
346          * is still working and will take care of running the finalizers
347          */ 
348         
349 #ifndef HAVE_NULL_GC
350         if (gc_disabled)
351                 return TRUE;
352
353         mono_gc_collect (mono_gc_max_generation ());
354
355         done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
356         if (done_event == NULL) {
357                 return FALSE;
358         }
359
360         req = g_new0 (DomainFinalizationReq, 1);
361         req->domain = domain;
362         req->done_event = done_event;
363
364         if (domain == mono_get_root_domain ())
365                 finalizing_root_domain = TRUE;
366         
367         mono_finalizer_lock ();
368
369         domains_to_finalize = g_slist_append (domains_to_finalize, req);
370
371         mono_finalizer_unlock ();
372
373         /* Tell the finalizer thread to finalize this appdomain */
374         mono_gc_finalize_notify ();
375
376         if (timeout == -1)
377                 timeout = INFINITE;
378
379         while (TRUE) {
380                 res = WaitForSingleObjectEx (done_event, timeout, TRUE);
381                 /* printf ("WAIT RES: %d.\n", res); */
382
383                 if (res == WAIT_IO_COMPLETION) {
384                         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
385                                 return FALSE;
386                 } else if (res == WAIT_TIMEOUT) {
387                         /* We leak the handle here */
388                         return FALSE;
389                 } else {
390                         break;
391                 }
392         }
393
394         CloseHandle (done_event);
395
396         if (domain == mono_get_root_domain ()) {
397                 mono_thread_pool_cleanup ();
398                 mono_gc_finalize_threadpool_threads ();
399         }
400
401         return TRUE;
402 #else
403         /* We don't support domain finalization without a GC */
404         return FALSE;
405 #endif
406 }
407
408 void
409 ves_icall_System_GC_InternalCollect (int generation)
410 {
411         mono_gc_collect (generation);
412 }
413
414 gint64
415 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
416 {
417         MONO_ARCH_SAVE_REGS;
418
419         if (forceCollection)
420                 mono_gc_collect (mono_gc_max_generation ());
421         return mono_gc_get_used_size ();
422 }
423
424 void
425 ves_icall_System_GC_KeepAlive (MonoObject *obj)
426 {
427         MONO_ARCH_SAVE_REGS;
428
429         /*
430          * Does nothing.
431          */
432 }
433
434 void
435 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
436 {
437         if (!obj)
438                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
439
440         object_register_finalizer (obj, mono_gc_run_finalize);
441 }
442
443 void
444 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
445 {
446         if (!obj)
447                 mono_raise_exception (mono_get_exception_argument_null ("obj"));
448
449         /* delegates have no finalizers, but we register them to deal with the
450          * unmanaged->managed trampoline. We don't let the user suppress it
451          * otherwise we'd leak it.
452          */
453         if (obj->vtable->klass->delegate)
454                 return;
455
456         /* FIXME: Need to handle case where obj has COM Callable Wrapper
457          * generated for it that needs cleaned up, but user wants to suppress
458          * their derived object finalizer. */
459
460         object_register_finalizer (obj, NULL);
461 }
462
463 void
464 ves_icall_System_GC_WaitForPendingFinalizers (void)
465 {
466 #ifndef HAVE_NULL_GC
467         if (!mono_gc_pending_finalizers ())
468                 return;
469
470         if (mono_thread_internal_current () == gc_thread)
471                 /* Avoid deadlocks */
472                 return;
473
474         /*
475         If the finalizer thread is not live, lets pretend no finalizers are pending since the current thread might
476         be the one responsible for starting it up.
477         */
478         if (gc_thread == NULL)
479                 return;
480
481         ResetEvent (pending_done_event);
482         mono_gc_finalize_notify ();
483         /* g_print ("Waiting for pending finalizers....\n"); */
484         WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
485         /* g_print ("Done pending....\n"); */
486 #endif
487 }
488
489 void
490 ves_icall_System_GC_register_ephemeron_array (MonoObject *array)
491 {
492 #ifdef HAVE_SGEN_GC
493         if (!mono_gc_ephemeron_array_add (array))
494                 mono_raise_exception (mono_object_domain (array)->out_of_memory_ex);
495 #endif
496 }
497
498 MonoObject*
499 ves_icall_System_GC_get_ephemeron_tombstone (void)
500 {
501         return mono_domain_get ()->ephemeron_tombstone;
502 }
503
504 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
505 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
506 static CRITICAL_SECTION allocator_section;
507 static CRITICAL_SECTION handle_section;
508
509 typedef enum {
510         HANDLE_WEAK,
511         HANDLE_WEAK_TRACK,
512         HANDLE_NORMAL,
513         HANDLE_PINNED
514 } HandleType;
515
516 static HandleType mono_gchandle_get_type (guint32 gchandle);
517
518 MonoObject *
519 ves_icall_System_GCHandle_GetTarget (guint32 handle)
520 {
521         return mono_gchandle_get_target (handle);
522 }
523
524 /*
525  * if type == -1, change the target of the handle, otherwise allocate a new handle.
526  */
527 guint32
528 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
529 {
530         if (type == -1) {
531                 mono_gchandle_set_target (handle, obj);
532                 /* the handle doesn't change */
533                 return handle;
534         }
535         switch (type) {
536         case HANDLE_WEAK:
537                 return mono_gchandle_new_weakref (obj, FALSE);
538         case HANDLE_WEAK_TRACK:
539                 return mono_gchandle_new_weakref (obj, TRUE);
540         case HANDLE_NORMAL:
541                 return mono_gchandle_new (obj, FALSE);
542         case HANDLE_PINNED:
543                 return mono_gchandle_new (obj, TRUE);
544         default:
545                 g_assert_not_reached ();
546         }
547         return 0;
548 }
549
550 void
551 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
552 {
553         mono_gchandle_free (handle);
554 }
555
556 gpointer
557 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
558 {
559         MonoObject *obj;
560
561         if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
562                 return (gpointer)-2;
563         obj = mono_gchandle_get_target (handle);
564         if (obj) {
565                 MonoClass *klass = mono_object_class (obj);
566                 if (klass == mono_defaults.string_class) {
567                         return mono_string_chars ((MonoString*)obj);
568                 } else if (klass->rank) {
569                         return mono_array_addr ((MonoArray*)obj, char, 0);
570                 } else {
571                         /* the C# code will check and throw the exception */
572                         /* FIXME: missing !klass->blittable test, see bug #61134 */
573                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
574                                 return (gpointer)-1;
575                         return (char*)obj + sizeof (MonoObject);
576                 }
577         }
578         return NULL;
579 }
580
581 MonoBoolean
582 ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
583 {
584         return mono_gc_set_allow_synchronous_major (flag);
585 }
586
587 typedef struct {
588         guint32  *bitmap;
589         gpointer *entries;
590         guint32   size;
591         guint8    type;
592         guint     slot_hint : 24; /* starting slot for search */
593         /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
594         /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
595         guint16  *domain_ids;
596 } HandleData;
597
598 /* weak and weak-track arrays will be allocated in malloc memory 
599  */
600 static HandleData gc_handles [] = {
601         {NULL, NULL, 0, HANDLE_WEAK, 0},
602         {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
603         {NULL, NULL, 0, HANDLE_NORMAL, 0},
604         {NULL, NULL, 0, HANDLE_PINNED, 0}
605 };
606
607 #define lock_handles(handles) EnterCriticalSection (&handle_section)
608 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
609
610 static int
611 find_first_unset (guint32 bitmap)
612 {
613         int i;
614         for (i = 0; i < 32; ++i) {
615                 if (!(bitmap & (1 << i)))
616                         return i;
617         }
618         return -1;
619 }
620
621 static void*
622 make_root_descr_all_refs (int numbits, gboolean pinned)
623 {
624 #ifdef HAVE_SGEN_GC
625         if (pinned)
626                 return NULL;
627 #endif
628         return mono_gc_make_root_descr_all_refs (numbits);
629 }
630
631 static guint32
632 alloc_handle (HandleData *handles, MonoObject *obj, gboolean track)
633 {
634         gint slot, i;
635         guint32 res;
636         lock_handles (handles);
637         if (!handles->size) {
638                 handles->size = 32;
639                 if (handles->type > HANDLE_WEAK_TRACK) {
640                         handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, make_root_descr_all_refs (handles->size, handles->type == HANDLE_PINNED));
641                 } else {
642                         handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
643                         handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
644                 }
645                 handles->bitmap = g_malloc0 (handles->size / 8);
646         }
647         i = -1;
648         for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
649                 if (handles->bitmap [slot] != 0xffffffff) {
650                         i = find_first_unset (handles->bitmap [slot]);
651                         handles->slot_hint = slot;
652                         break;
653                 }
654         }
655         if (i == -1 && handles->slot_hint != 0) {
656                 for (slot = 0; slot < handles->slot_hint; ++slot) {
657                         if (handles->bitmap [slot] != 0xffffffff) {
658                                 i = find_first_unset (handles->bitmap [slot]);
659                                 handles->slot_hint = slot;
660                                 break;
661                         }
662                 }
663         }
664         if (i == -1) {
665                 guint32 *new_bitmap;
666                 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
667
668                 /* resize and copy the bitmap */
669                 new_bitmap = g_malloc0 (new_size / 8);
670                 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
671                 g_free (handles->bitmap);
672                 handles->bitmap = new_bitmap;
673
674                 /* resize and copy the entries */
675                 if (handles->type > HANDLE_WEAK_TRACK) {
676                         gpointer *entries;
677
678                         entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, make_root_descr_all_refs (new_size, handles->type == HANDLE_PINNED));
679                         mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
680
681                         mono_gc_free_fixed (handles->entries);
682                         handles->entries = entries;
683                 } else {
684                         gpointer *entries;
685                         guint16 *domain_ids;
686                         domain_ids = g_malloc0 (sizeof (guint16) * new_size);
687                         entries = g_malloc0 (sizeof (gpointer) * new_size);
688                         memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
689                         for (i = 0; i < handles->size; ++i) {
690                                 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
691                                 if (obj) {
692                                         mono_gc_weak_link_add (&(entries [i]), obj, track);
693                                         mono_gc_weak_link_remove (&(handles->entries [i]), track);
694                                 } else {
695                                         g_assert (!handles->entries [i]);
696                                 }
697                         }
698                         g_free (handles->entries);
699                         g_free (handles->domain_ids);
700                         handles->entries = entries;
701                         handles->domain_ids = domain_ids;
702                 }
703
704                 /* set i and slot to the next free position */
705                 i = 0;
706                 slot = (handles->size + 1) / 32;
707                 handles->slot_hint = handles->size + 1;
708                 handles->size = new_size;
709         }
710         handles->bitmap [slot] |= 1 << i;
711         slot = slot * 32 + i;
712         handles->entries [slot] = NULL;
713         if (handles->type <= HANDLE_WEAK_TRACK) {
714                 /*FIXME, what to use when obj == null?*/
715                 handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
716                 if (obj)
717                         mono_gc_weak_link_add (&(handles->entries [slot]), obj, track);
718         } else {
719                 handles->entries [slot] = obj;
720         }
721
722 #ifndef DISABLE_PERFCOUNTERS
723         mono_perfcounters->gc_num_handles++;
724 #endif
725         unlock_handles (handles);
726         /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
727         res = (slot << 3) | (handles->type + 1);
728         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj);
729         return res;
730 }
731
732 /**
733  * mono_gchandle_new:
734  * @obj: managed object to get a handle for
735  * @pinned: whether the object should be pinned
736  *
737  * This returns a handle that wraps the object, this is used to keep a
738  * reference to a managed object from the unmanaged world and preventing the
739  * object from being disposed.
740  * 
741  * If @pinned is false the address of the object can not be obtained, if it is
742  * true the address of the object can be obtained.  This will also pin the
743  * object so it will not be possible by a moving garbage collector to move the
744  * object. 
745  * 
746  * Returns: a handle that can be used to access the object from
747  * unmanaged code.
748  */
749 guint32
750 mono_gchandle_new (MonoObject *obj, gboolean pinned)
751 {
752         return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj, FALSE);
753 }
754
755 /**
756  * mono_gchandle_new_weakref:
757  * @obj: managed object to get a handle for
758  * @pinned: whether the object should be pinned
759  *
760  * This returns a weak handle that wraps the object, this is used to
761  * keep a reference to a managed object from the unmanaged world.
762  * Unlike the mono_gchandle_new the object can be reclaimed by the
763  * garbage collector.  In this case the value of the GCHandle will be
764  * set to zero.
765  * 
766  * If @pinned is false the address of the object can not be obtained, if it is
767  * true the address of the object can be obtained.  This will also pin the
768  * object so it will not be possible by a moving garbage collector to move the
769  * object. 
770  * 
771  * Returns: a handle that can be used to access the object from
772  * unmanaged code.
773  */
774 guint32
775 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
776 {
777         guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
778
779         return handle;
780 }
781
782 static HandleType
783 mono_gchandle_get_type (guint32 gchandle)
784 {
785         guint type = (gchandle & 7) - 1;
786
787         return type;
788 }
789
790 /**
791  * mono_gchandle_get_target:
792  * @gchandle: a GCHandle's handle.
793  *
794  * The handle was previously created by calling mono_gchandle_new or
795  * mono_gchandle_new_weakref. 
796  *
797  * Returns a pointer to the MonoObject represented by the handle or
798  * NULL for a collected object if using a weakref handle.
799  */
800 MonoObject*
801 mono_gchandle_get_target (guint32 gchandle)
802 {
803         guint slot = gchandle >> 3;
804         guint type = (gchandle & 7) - 1;
805         HandleData *handles = &gc_handles [type];
806         MonoObject *obj = NULL;
807         if (type > 3)
808                 return NULL;
809         lock_handles (handles);
810         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
811                 if (handles->type <= HANDLE_WEAK_TRACK) {
812                         obj = mono_gc_weak_link_get (&handles->entries [slot]);
813                 } else {
814                         obj = handles->entries [slot];
815                 }
816         } else {
817                 /* print a warning? */
818         }
819         unlock_handles (handles);
820         /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
821         return obj;
822 }
823
824 static void
825 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
826 {
827         guint slot = gchandle >> 3;
828         guint type = (gchandle & 7) - 1;
829         HandleData *handles = &gc_handles [type];
830         MonoObject *old_obj = NULL;
831
832         if (type > 3)
833                 return;
834         lock_handles (handles);
835         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
836                 if (handles->type <= HANDLE_WEAK_TRACK) {
837                         old_obj = handles->entries [slot];
838                         if (handles->entries [slot])
839                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
840                         if (obj)
841                                 mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
842                         /*FIXME, what to use when obj == null?*/
843                         handles->domain_ids [slot] = (obj ? mono_object_get_domain (obj) : mono_domain_get ())->domain_id;
844                 } else {
845                         handles->entries [slot] = obj;
846                 }
847         } else {
848                 /* print a warning? */
849         }
850         /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
851         unlock_handles (handles);
852 }
853
854 /**
855  * mono_gchandle_is_in_domain:
856  * @gchandle: a GCHandle's handle.
857  * @domain: An application domain.
858  *
859  * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
860  */
861 gboolean
862 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
863 {
864         guint slot = gchandle >> 3;
865         guint type = (gchandle & 7) - 1;
866         HandleData *handles = &gc_handles [type];
867         gboolean result = FALSE;
868         if (type > 3)
869                 return FALSE;
870         lock_handles (handles);
871         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
872                 if (handles->type <= HANDLE_WEAK_TRACK) {
873                         result = domain->domain_id == handles->domain_ids [slot];
874                 } else {
875                         MonoObject *obj;
876                         obj = handles->entries [slot];
877                         if (obj == NULL)
878                                 result = TRUE;
879                         else
880                                 result = domain == mono_object_domain (obj);
881                 }
882         } else {
883                 /* print a warning? */
884         }
885         unlock_handles (handles);
886         return result;
887 }
888
889 /**
890  * mono_gchandle_free:
891  * @gchandle: a GCHandle's handle.
892  *
893  * Frees the @gchandle handle.  If there are no outstanding
894  * references, the garbage collector can reclaim the memory of the
895  * object wrapped. 
896  */
897 void
898 mono_gchandle_free (guint32 gchandle)
899 {
900         guint slot = gchandle >> 3;
901         guint type = (gchandle & 7) - 1;
902         HandleData *handles = &gc_handles [type];
903         if (type > 3)
904                 return;
905
906         lock_handles (handles);
907         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
908                 if (handles->type <= HANDLE_WEAK_TRACK) {
909                         if (handles->entries [slot])
910                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
911                 } else {
912                         handles->entries [slot] = NULL;
913                 }
914                 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
915         } else {
916                 /* print a warning? */
917         }
918 #ifndef DISABLE_PERFCOUNTERS
919         mono_perfcounters->gc_num_handles--;
920 #endif
921         /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
922         unlock_handles (handles);
923         mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL);
924 }
925
926 /**
927  * mono_gchandle_free_domain:
928  * @domain: domain that is unloading
929  *
930  * Function used internally to cleanup any GC handle for objects belonging
931  * to the specified domain during appdomain unload.
932  */
933 void
934 mono_gchandle_free_domain (MonoDomain *domain)
935 {
936         guint type;
937
938         for (type = 0; type < 3; ++type) {
939                 guint slot;
940                 HandleData *handles = &gc_handles [type];
941                 lock_handles (handles);
942                 for (slot = 0; slot < handles->size; ++slot) {
943                         if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
944                                 continue;
945                         if (type <= HANDLE_WEAK_TRACK) {
946                                 if (domain->domain_id == handles->domain_ids [slot]) {
947                                         handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
948                                         if (handles->entries [slot])
949                                                 mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
950                                 }
951                         } else {
952                                 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
953                                         handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
954                                         handles->entries [slot] = NULL;
955                                 }
956                         }
957                 }
958                 unlock_handles (handles);
959         }
960
961 }
962
963 MonoBoolean
964 GCHandle_CheckCurrentDomain (guint32 gchandle)
965 {
966         return mono_gchandle_is_in_domain (gchandle, mono_domain_get ());
967 }
968
969 #ifndef HAVE_NULL_GC
970
971 #ifdef MONO_HAS_SEMAPHORES
972 static MonoSemType finalizer_sem;
973 #endif
974 static HANDLE finalizer_event;
975 static volatile gboolean finished=FALSE;
976
977 void
978 mono_gc_finalize_notify (void)
979 {
980 #ifdef DEBUG
981         g_message ( "%s: prodding finalizer", __func__);
982 #endif
983
984 #ifdef MONO_HAS_SEMAPHORES
985         MONO_SEM_POST (&finalizer_sem);
986 #else
987         SetEvent (finalizer_event);
988 #endif
989 }
990
991 #ifdef HAVE_BOEHM_GC
992
993 static void
994 collect_objects (gpointer key, gpointer value, gpointer user_data)
995 {
996         GPtrArray *arr = (GPtrArray*)user_data;
997         g_ptr_array_add (arr, key);
998 }
999
1000 #endif
1001
1002 /*
1003  * finalize_domain_objects:
1004  *
1005  *  Run the finalizers of all finalizable objects in req->domain.
1006  */
1007 static void
1008 finalize_domain_objects (DomainFinalizationReq *req)
1009 {
1010         MonoDomain *domain = req->domain;
1011
1012 #if HAVE_SGEN_GC
1013 #define NUM_FOBJECTS 64
1014         MonoObject *to_finalize [NUM_FOBJECTS];
1015         int count;
1016 #endif
1017
1018         /* Process finalizers which are already in the queue */
1019         mono_gc_invoke_finalizers ();
1020
1021 #ifdef HAVE_BOEHM_GC
1022         while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1023                 int i;
1024                 GPtrArray *objs;
1025                 /* 
1026                  * Since the domain is unloading, nobody is allowed to put
1027                  * new entries into the hash table. But finalize_object might
1028                  * remove entries from the hash table, so we make a copy.
1029                  */
1030                 objs = g_ptr_array_new ();
1031                 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1032                 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1033
1034                 for (i = 0; i < objs->len; ++i) {
1035                         MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1036                         /* FIXME: Avoid finalizing threads, etc */
1037                         mono_gc_run_finalize (o, 0);
1038                 }
1039
1040                 g_ptr_array_free (objs, TRUE);
1041         }
1042 #elif defined(HAVE_SGEN_GC)
1043         while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1044                 int i;
1045                 for (i = 0; i < count; ++i) {
1046                         mono_gc_run_finalize (to_finalize [i], 0);
1047                 }
1048         }
1049 #endif
1050
1051         /* cleanup the reference queue */
1052         reference_queue_clear_for_domain (domain);
1053         
1054         /* printf ("DONE.\n"); */
1055         SetEvent (req->done_event);
1056
1057         /* The event is closed in mono_domain_finalize if we get here */
1058         g_free (req);
1059 }
1060
1061 static guint32
1062 finalizer_thread (gpointer unused)
1063 {
1064         while (!finished) {
1065                 /* Wait to be notified that there's at least one
1066                  * finaliser to run
1067                  */
1068
1069                 g_assert (mono_domain_get () == mono_get_root_domain ());
1070
1071                 /* An alertable wait is required so this thread can be suspended on windows */
1072 #ifdef MONO_HAS_SEMAPHORES
1073                 MONO_SEM_WAIT_ALERTABLE (&finalizer_sem, TRUE);
1074 #else
1075                 WaitForSingleObjectEx (finalizer_event, INFINITE, TRUE);
1076 #endif
1077
1078                 mono_threads_perform_thread_dump ();
1079
1080                 mono_console_handle_async_ops ();
1081
1082 #ifndef DISABLE_ATTACH
1083                 mono_attach_maybe_start ();
1084 #endif
1085
1086                 if (domains_to_finalize) {
1087                         mono_finalizer_lock ();
1088                         if (domains_to_finalize) {
1089                                 DomainFinalizationReq *req = domains_to_finalize->data;
1090                                 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1091                                 mono_finalizer_unlock ();
1092
1093                                 finalize_domain_objects (req);
1094                         } else {
1095                                 mono_finalizer_unlock ();
1096                         }
1097                 }                               
1098
1099                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1100                  * before the domain is unloaded.
1101                  */
1102                 mono_gc_invoke_finalizers ();
1103
1104                 reference_queue_proccess_all ();
1105
1106                 SetEvent (pending_done_event);
1107         }
1108
1109         SetEvent (shutdown_event);
1110         return 0;
1111 }
1112
1113 #ifndef LAZY_GC_THREAD_CREATION
1114 static
1115 #endif
1116 void
1117 mono_gc_init_finalizer_thread (void)
1118 {
1119         gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
1120         ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
1121 }
1122
1123 void
1124 mono_gc_init (void)
1125 {
1126         InitializeCriticalSection (&handle_section);
1127         InitializeCriticalSection (&allocator_section);
1128
1129         InitializeCriticalSection (&finalizer_mutex);
1130         InitializeCriticalSection (&reference_queue_mutex);
1131
1132         MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
1133         MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
1134
1135         mono_counters_register ("Created object count", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &mono_stats.new_object_count);
1136         mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
1137         mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
1138         mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
1139         mono_counters_register ("Major GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.major_gc_time_usecs);
1140
1141         mono_gc_base_init ();
1142
1143         if (mono_gc_is_disabled ()) {
1144                 gc_disabled = TRUE;
1145                 return;
1146         }
1147         
1148         finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1149         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1150         shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1151         if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL) {
1152                 g_assert_not_reached ();
1153         }
1154 #ifdef MONO_HAS_SEMAPHORES
1155         MONO_SEM_INIT (&finalizer_sem, 0);
1156 #endif
1157
1158 #ifndef LAZY_GC_THREAD_CREATION
1159         mono_gc_init_finalizer_thread ();
1160 #endif
1161 }
1162
1163 void
1164 mono_gc_cleanup (void)
1165 {
1166 #ifdef DEBUG
1167         g_message ("%s: cleaning up finalizer", __func__);
1168 #endif
1169
1170         if (!gc_disabled) {
1171                 ResetEvent (shutdown_event);
1172                 finished = TRUE;
1173                 if (mono_thread_internal_current () != gc_thread) {
1174                         mono_gc_finalize_notify ();
1175                         /* Finishing the finalizer thread, so wait a little bit... */
1176                         /* MS seems to wait for about 2 seconds */
1177                         if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1178                                 int ret;
1179
1180                                 /* Set a flag which the finalizer thread can check */
1181                                 suspend_finalizers = TRUE;
1182
1183                                 /* Try to abort the thread, in the hope that it is running managed code */
1184                                 mono_thread_internal_stop (gc_thread);
1185
1186                                 /* Wait for it to stop */
1187                                 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1188
1189                                 if (ret == WAIT_TIMEOUT) {
1190                                         /* 
1191                                          * The finalizer thread refused to die. There is not much we 
1192                                          * can do here, since the runtime is shutting down so the 
1193                                          * state the finalizer thread depends on will vanish.
1194                                          */
1195                                         g_warning ("Shutting down finalizer thread timed out.");
1196                                 } else {
1197                                         /*
1198                                          * FIXME: On unix, when the above wait returns, the thread 
1199                                          * might still be running io-layer code, or pthreads code.
1200                                          */
1201                                         Sleep (100);
1202                                 }
1203                         } else {
1204                                 int ret;
1205
1206                                 /* Wait for the thread to actually exit */
1207                                 ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
1208                                 g_assert (ret == WAIT_OBJECT_0);
1209
1210 #ifndef HOST_WIN32
1211                                 /*
1212                                  * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
1213                                  * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
1214                                  */
1215                                 ret = pthread_join ((MonoNativeThreadId)(gpointer)(gsize)gc_thread->tid, NULL);
1216                                 g_assert (ret == 0);
1217 #endif
1218                         }
1219                 }
1220                 gc_thread = NULL;
1221 #ifdef HAVE_BOEHM_GC
1222                 GC_finalizer_notifier = NULL;
1223 #endif
1224         }
1225
1226         mono_reference_queue_cleanup ();
1227
1228         DeleteCriticalSection (&handle_section);
1229         DeleteCriticalSection (&allocator_section);
1230         DeleteCriticalSection (&finalizer_mutex);
1231         DeleteCriticalSection (&reference_queue_mutex);
1232 }
1233
1234 #else
1235
1236 /* Null GC dummy functions */
1237 void
1238 mono_gc_finalize_notify (void)
1239 {
1240 }
1241
1242 void mono_gc_init (void)
1243 {
1244         InitializeCriticalSection (&handle_section);
1245 }
1246
1247 void mono_gc_cleanup (void)
1248 {
1249 }
1250
1251 #endif
1252
1253 gboolean
1254 mono_gc_is_finalizer_internal_thread (MonoInternalThread *thread)
1255 {
1256         return thread == gc_thread;
1257 }
1258
1259 /**
1260  * mono_gc_is_finalizer_thread:
1261  * @thread: the thread to test.
1262  *
1263  * In Mono objects are finalized asynchronously on a separate thread.
1264  * This routine tests whether the @thread argument represents the
1265  * finalization thread.
1266  * 
1267  * Returns true if @thread is the finalization thread.
1268  */
1269 gboolean
1270 mono_gc_is_finalizer_thread (MonoThread *thread)
1271 {
1272         return mono_gc_is_finalizer_internal_thread (thread->internal_thread);
1273 }
1274
1275 #if defined(__MACH__)
1276 static pthread_t mach_exception_thread;
1277
1278 void
1279 mono_gc_register_mach_exception_thread (pthread_t thread)
1280 {
1281         mach_exception_thread = thread;
1282 }
1283
1284 pthread_t
1285 mono_gc_get_mach_exception_thread (void)
1286 {
1287         return mach_exception_thread;
1288 }
1289 #endif
1290
1291 /**
1292  * mono_gc_parse_environment_string_extract_number:
1293  *
1294  * @str: points to the first digit of the number
1295  * @out: pointer to the variable that will receive the value
1296  *
1297  * Tries to extract a number from the passed string, taking in to account m, k
1298  * and g suffixes
1299  *
1300  * Returns true if passing was successful
1301  */
1302 gboolean
1303 mono_gc_parse_environment_string_extract_number (const char *str, glong *out)
1304 {
1305         char *endptr;
1306         int len = strlen (str), shift = 0;
1307         glong val;
1308         gboolean is_suffix = FALSE;
1309         char suffix;
1310
1311         if (!len)
1312                 return FALSE;
1313
1314         suffix = str [len - 1];
1315
1316         switch (suffix) {
1317                 case 'g':
1318                 case 'G':
1319                         shift += 10;
1320                 case 'm':
1321                 case 'M':
1322                         shift += 10;
1323                 case 'k':
1324                 case 'K':
1325                         shift += 10;
1326                         is_suffix = TRUE;
1327                         break;
1328                 default:
1329                         if (!isdigit (suffix))
1330                                 return FALSE;
1331                         break;
1332         }
1333
1334         errno = 0;
1335         val = strtol (str, &endptr, 10);
1336
1337         if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
1338                         || (errno != 0 && val == 0) || (endptr == str))
1339                 return FALSE;
1340
1341         if (is_suffix) {
1342                 gulong unshifted;
1343
1344                 if (val < 0)    /* negative numbers cannot be suffixed */
1345                         return FALSE;
1346                 if (*(endptr + 1)) /* Invalid string. */
1347                         return FALSE;
1348
1349                 unshifted = (gulong)val;
1350                 val <<= shift;
1351                 if (val < 0)    /* overflow */
1352                         return FALSE;
1353                 if (((gulong)val >> shift) != unshifted) /* value too large */
1354                         return FALSE;
1355         }
1356
1357         *out = val;
1358         return TRUE;
1359 }
1360
1361 #ifndef HAVE_SGEN_GC
1362 void*
1363 mono_gc_alloc_mature (MonoVTable *vtable)
1364 {
1365         return mono_object_new_specific (vtable);
1366 }
1367 #endif
1368
1369
1370 static MonoReferenceQueue *ref_queues;
1371
1372 static void
1373 ref_list_remove_element (RefQueueEntry **prev, RefQueueEntry *element)
1374 {
1375         do {
1376                 /* Guard if head is changed concurrently. */
1377                 while (*prev != element)
1378                         prev = &(*prev)->next;
1379         } while (prev && InterlockedCompareExchangePointer ((void*)prev, element->next, element) != element);
1380 }
1381
1382 static void
1383 ref_list_push (RefQueueEntry **head, RefQueueEntry *value)
1384 {
1385         RefQueueEntry *current;
1386         do {
1387                 current = *head;
1388                 value->next = current;
1389                 STORE_STORE_FENCE; /*Must make sure the previous store is visible before the CAS. */
1390         } while (InterlockedCompareExchangePointer ((void*)head, value, current) != current);
1391 }
1392
1393 static void
1394 reference_queue_proccess (MonoReferenceQueue *queue)
1395 {
1396         RefQueueEntry **iter = &queue->queue;
1397         RefQueueEntry *entry;
1398         while ((entry = *iter)) {
1399 #ifdef HAVE_SGEN_GC
1400                 if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
1401                         mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1402 #else
1403                 if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
1404                         mono_gchandle_free ((guint32)entry->gchandle);
1405 #endif
1406                         ref_list_remove_element (iter, entry);
1407                         queue->callback (entry->user_data);
1408                         g_free (entry);
1409                 } else {
1410                         iter = &entry->next;
1411                 }
1412         }
1413 }
1414
1415 static void
1416 reference_queue_proccess_all (void)
1417 {
1418         MonoReferenceQueue **iter;
1419         MonoReferenceQueue *queue = ref_queues;
1420         for (; queue; queue = queue->next)
1421                 reference_queue_proccess (queue);
1422
1423 restart:
1424         EnterCriticalSection (&reference_queue_mutex);
1425         for (iter = &ref_queues; *iter;) {
1426                 queue = *iter;
1427                 if (!queue->should_be_deleted) {
1428                         iter = &queue->next;
1429                         continue;
1430                 }
1431                 if (queue->queue) {
1432                         LeaveCriticalSection (&reference_queue_mutex);
1433                         reference_queue_proccess (queue);
1434                         goto restart;
1435                 }
1436                 *iter = queue->next;
1437                 g_free (queue);
1438         }
1439         LeaveCriticalSection (&reference_queue_mutex);
1440 }
1441
1442 static void
1443 mono_reference_queue_cleanup (void)
1444 {
1445         MonoReferenceQueue *queue = ref_queues;
1446         for (; queue; queue = queue->next)
1447                 queue->should_be_deleted = TRUE;
1448         reference_queue_proccess_all ();
1449 }
1450
1451 static void
1452 reference_queue_clear_for_domain (MonoDomain *domain)
1453 {
1454         MonoReferenceQueue *queue = ref_queues;
1455         for (; queue; queue = queue->next) {
1456                 RefQueueEntry **iter = &queue->queue;
1457                 RefQueueEntry *entry;
1458                 while ((entry = *iter)) {
1459                         if (entry->domain == domain) {
1460 #ifdef HAVE_SGEN_GC
1461                                 mono_gc_weak_link_remove (&entry->dis_link, TRUE);
1462 #else
1463                                 mono_gchandle_free ((guint32)entry->gchandle);
1464 #endif
1465                                 ref_list_remove_element (iter, entry);
1466                                 queue->callback (entry->user_data);
1467                                 g_free (entry);
1468                         } else {
1469                                 iter = &entry->next;
1470                         }
1471                 }
1472         }
1473 }
1474 /**
1475  * mono_gc_reference_queue_new:
1476  * @callback callback used when processing collected entries.
1477  *
1478  * Create a new reference queue used to process collected objects.
1479  * A reference queue let you add a pair of (managed object, user data)
1480  * using the mono_gc_reference_queue_add method.
1481  *
1482  * Once the managed object is collected @callback will be called
1483  * in the finalizer thread with 'user data' as argument.
1484  *
1485  * The callback is called from the finalizer thread without any locks held.
1486  * When a AppDomain is unloaded, all callbacks for objects belonging to it
1487  * will be invoked.
1488  *
1489  * @returns the new queue.
1490  */
1491 MonoReferenceQueue*
1492 mono_gc_reference_queue_new (mono_reference_queue_callback callback)
1493 {
1494         MonoReferenceQueue *res = g_new0 (MonoReferenceQueue, 1);
1495         res->callback = callback;
1496
1497         EnterCriticalSection (&reference_queue_mutex);
1498         res->next = ref_queues;
1499         ref_queues = res;
1500         LeaveCriticalSection (&reference_queue_mutex);
1501
1502         return res;
1503 }
1504
1505 /**
1506  * mono_gc_reference_queue_add:
1507  * @queue the queue to add the reference to.
1508  * @obj the object to be watched for collection
1509  * @user_data parameter to be passed to the queue callback
1510  *
1511  * Queue an object to be watched for collection, when the @obj is
1512  * collected, the callback that was registered for the @queue will
1513  * be invoked with @user_data as argument.
1514  *
1515  * @returns false if the queue is scheduled to be freed.
1516  */
1517 gboolean
1518 mono_gc_reference_queue_add (MonoReferenceQueue *queue, MonoObject *obj, void *user_data)
1519 {
1520         RefQueueEntry *entry;
1521         if (queue->should_be_deleted)
1522                 return FALSE;
1523
1524         entry = g_new0 (RefQueueEntry, 1);
1525         entry->user_data = user_data;
1526         entry->domain = mono_object_domain (obj);
1527
1528 #ifdef HAVE_SGEN_GC
1529         mono_gc_weak_link_add (&entry->dis_link, obj, TRUE);
1530 #else
1531         entry->gchandle = mono_gchandle_new_weakref (obj, TRUE);
1532         mono_object_register_finalizer (obj);
1533 #endif
1534
1535         ref_list_push (&queue->queue, entry);
1536         return TRUE;
1537 }
1538
1539 /**
1540  * mono_gc_reference_queue_free:
1541  * @queue the queue that should be freed.
1542  *
1543  * This operation signals that @queue should be freed. This operation is deferred
1544  * as it happens on the finalizer thread.
1545  *
1546  * After this call, no further objects can be queued. It's the responsibility of the
1547  * caller to make sure that no further attempt to access queue will be made.
1548  */
1549 void
1550 mono_gc_reference_queue_free (MonoReferenceQueue *queue)
1551 {
1552         queue->should_be_deleted = TRUE;
1553 }
1554
1555 #define ptr_mask ((sizeof (void*) - 1))
1556 #define _toi(ptr) ((size_t)ptr)
1557 #define unaligned_bytes(ptr) (_toi(ptr) & ptr_mask)
1558 #define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
1559 #define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
1560
1561 #define BZERO_WORDS(dest,words) do {    \
1562         int __i;        \
1563         for (__i = 0; __i < (words); ++__i)     \
1564                 ((void **)(dest))[__i] = 0;     \
1565 } while (0)
1566
1567 /**
1568  * mono_gc_bzero:
1569  * @dest: address to start to clear
1570  * @size: size of the region to clear
1571  *
1572  * Zero @size bytes starting at @dest.
1573  *
1574  * Use this to zero memory that can hold managed pointers.
1575  *
1576  * FIXME borrow faster code from some BSD libc or bionic
1577  */
1578 void
1579 mono_gc_bzero (void *dest, size_t size)
1580 {
1581         char *d = (char*)dest;
1582         size_t tail_bytes, word_bytes;
1583
1584         /*
1585         If we're copying less than a word, just use memset.
1586
1587         We cannot bail out early if both are aligned because some implementations
1588         use byte copying for sizes smaller than 16. OSX, on this case.
1589         */
1590         if (size < sizeof(void*)) {
1591                 memset (dest, 0, size);
1592                 return;
1593         }
1594
1595         /*align to word boundary */
1596         while (unaligned_bytes (d) && size) {
1597                 *d++ = 0;
1598                 --size;
1599         }
1600
1601         /* copy all words with memmove */
1602         word_bytes = (size_t)align_down (size);
1603         switch (word_bytes) {
1604         case sizeof (void*) * 1:
1605                 BZERO_WORDS (d, 1);
1606                 break;
1607         case sizeof (void*) * 2:
1608                 BZERO_WORDS (d, 2);
1609                 break;
1610         case sizeof (void*) * 3:
1611                 BZERO_WORDS (d, 3);
1612                 break;
1613         case sizeof (void*) * 4:
1614                 BZERO_WORDS (d, 4);
1615                 break;
1616         default:
1617                 memset (d, 0, word_bytes);
1618         }
1619
1620         tail_bytes = unaligned_bytes (size);
1621         if (tail_bytes) {
1622                 d += word_bytes;
1623                 do {
1624                         *d++ = 0;
1625                 } while (--tail_bytes);
1626         }
1627 }
1628
1629 /**
1630  * mono_gc_memmove:
1631  * @dest: destination of the move
1632  * @src: source
1633  * @size: size of the block to move
1634  *
1635  * Move @size bytes from @src to @dest.
1636  * size MUST be a multiple of sizeof (gpointer)
1637  *
1638  */
1639 void
1640 mono_gc_memmove (void *dest, const void *src, size_t size)
1641 {
1642         /*
1643         If we're copying less than a word we don't need to worry about word tearing
1644         so we bailout to memmove early.
1645
1646         If both dest is aligned and size is a multiple of word size, we can go straigh
1647         to memmove.
1648
1649         */
1650         if (size < sizeof(void*) || !((_toi (dest) | (size)) & sizeof (void*))) {
1651                 memmove (dest, src, size);
1652                 return;
1653         }
1654
1655         /*
1656          * A bit of explanation on why we align only dest before doing word copies.
1657          * Pointers to managed objects must always be stored in word aligned addresses, so
1658          * even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
1659          *
1660          * We don't need to case when source and destination have different alignments since we only do word stores
1661          * using memmove, which must handle it.
1662          */
1663         if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
1664                 char *p = (char*)dest + size;
1665                         char *s = (char*)src + size;
1666                         char *start = (char*)dest;
1667                         char *align_end = MAX((char*)dest, (char*)align_down (p));
1668                         char *word_start;
1669                         size_t bytes_to_memmove;
1670
1671                         while (p > align_end)
1672                                 *--p = *--s;
1673
1674                         word_start = align_up (start);
1675                         bytes_to_memmove = p - word_start;
1676                         p -= bytes_to_memmove;
1677                         s -= bytes_to_memmove;
1678                         memmove (p, s, bytes_to_memmove);
1679
1680                         while (p > start)
1681                                 *--p = *--s;
1682         } else {
1683                 char *d = (char*)dest;
1684                 const char *s = (const char*)src;
1685                 size_t tail_bytes;
1686
1687                 /*align to word boundary */
1688                 while (unaligned_bytes (d)) {
1689                         *d++ = *s++;
1690                         --size;
1691                 }
1692
1693                 /* copy all words with memmove */
1694                 memmove (d, s, (size_t)align_down (size));
1695
1696                 tail_bytes = unaligned_bytes (size);
1697                 if (tail_bytes) {
1698                         d += (size_t)align_down (size);
1699                         s += (size_t)align_down (size);
1700                         do {
1701                                 *d++ = *s++;
1702                         } while (--tail_bytes);
1703                 }
1704         }
1705 }
1706
1707