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