2009-04-13 Zoltan Varga <vargaz@gmail.com>
[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  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <string.h>
13
14 #include <mono/metadata/gc-internal.h>
15 #include <mono/metadata/mono-gc.h>
16 #include <mono/metadata/threads.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/exception.h>
19 #include <mono/metadata/profiler-private.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/class-internals.h>
22 #include <mono/metadata/metadata-internals.h>
23 #include <mono/metadata/mono-mlist.h>
24 #include <mono/metadata/threadpool.h>
25 #include <mono/utils/mono-logger.h>
26 #include <mono/metadata/gc-internal.h>
27 #include <mono/metadata/marshal.h> /* for mono_delegate_free_ftnptr () */
28 #include <mono/metadata/attach.h>
29 #if HAVE_SEMAPHORE_H
30 #include <semaphore.h>
31 /* we do this only for known working systems (OSX for example
32  * has the header and functions, but they don't work at all): in other cases
33  * we fall back to the io-layer slightly slower and signal-unsafe Event.
34  */
35 #ifdef __linux__
36 #define USE_POSIX_SEM 1
37 #endif
38 #endif
39
40 #ifndef PLATFORM_WIN32
41 #include <pthread.h>
42 #endif
43
44 typedef struct DomainFinalizationReq {
45         MonoDomain *domain;
46         HANDLE done_event;
47 } DomainFinalizationReq;
48
49 #ifdef PLATFORM_WINCE /* FIXME: add accessors to gc.dll API */
50 extern void (*__imp_GC_finalizer_notifier)(void);
51 #define GC_finalizer_notifier __imp_GC_finalizer_notifier
52 extern int __imp_GC_finalize_on_demand;
53 #define GC_finalize_on_demand __imp_GC_finalize_on_demand
54 #endif
55
56 static gboolean gc_disabled = FALSE;
57
58 static gboolean finalizing_root_domain = FALSE;
59
60 #define mono_finalizer_lock() EnterCriticalSection (&finalizer_mutex)
61 #define mono_finalizer_unlock() LeaveCriticalSection (&finalizer_mutex)
62 static CRITICAL_SECTION finalizer_mutex;
63
64 static GSList *domains_to_finalize= NULL;
65 static MonoMList *threads_to_finalize = NULL;
66
67 static MonoThread *gc_thread;
68
69 static void object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*));
70
71 static void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
72
73 #ifndef HAVE_NULL_GC
74 static HANDLE pending_done_event;
75 static HANDLE shutdown_event;
76 static HANDLE thread_started_event;
77 #endif
78
79 #define domain_finalizers_lock(domain) EnterCriticalSection (&(domain)->finalizable_objects_hash_lock);
80 #define domain_finalizers_unlock(domain) LeaveCriticalSection (&(domain)->finalizable_objects_hash_lock);
81
82 static void
83 add_thread_to_finalize (MonoThread *thread)
84 {
85         mono_finalizer_lock ();
86         if (!threads_to_finalize)
87                 MONO_GC_REGISTER_ROOT (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 *domain;
107         RuntimeInvokeFunction runtime_invoke;
108         GSList *l, *refs = NULL;
109
110         o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
111
112         if (suspend_finalizers)
113                 return;
114
115         domain = o->vtable->domain;
116
117 #ifndef HAVE_SGEN_GC
118         domain_finalizers_lock (domain);
119
120         o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
121
122         if (domain->track_resurrection_objects_hash) {
123                 refs = g_hash_table_lookup (domain->track_resurrection_objects_hash, o);
124
125                 if (refs)
126                         /* 
127                          * Since we don't run finalizers again for resurrected objects, 
128                          * no need to keep these around.
129                          */
130                         g_hash_table_remove (domain->track_resurrection_objects_hash, o);
131         }
132
133         domain_finalizers_unlock (domain);
134
135         if (!o2)
136                 /* Already finalized somehow */
137                 return;
138 #endif
139
140         if (refs) {
141                 /*
142                  * Support for GCHandles of type WeakTrackResurrection:
143                  *
144                  *   Its not exactly clear how these are supposed to work, or how their
145                  * semantics can be implemented. We only implement one crucial thing:
146                  * these handles are only cleared after the finalizer has ran.
147                  */
148                 for (l = refs; l; l = l->next) {
149                         guint32 gchandle = GPOINTER_TO_UINT (l->data);
150
151                         mono_gchandle_set_target (gchandle, o);
152                 }
153
154                 g_slist_free (refs);
155         }
156                 
157         /* make sure the finalizer is not called again if the object is resurrected */
158         object_register_finalizer (obj, NULL);
159
160         if (o->vtable->klass == mono_get_thread_class ()) {
161                 MonoThread *t = (MonoThread*)o;
162
163                 if (mono_gc_is_finalizer_thread (t))
164                         /* Avoid finalizing ourselves */
165                         return;
166
167                 if (t->threadpool_thread && finalizing_root_domain) {
168                         /* Don't finalize threadpool threads when
169                            shutting down - they're finalized when the
170                            threadpool shuts down. */
171                         add_thread_to_finalize (t);
172                         return;
173                 }
174         }
175
176         if (mono_runtime_get_no_exec ())
177                 return;
178
179         /* speedup later... and use a timeout */
180         /* g_print ("Finalize run on %p %s.%s\n", o, mono_object_class (o)->name_space, mono_object_class (o)->name); */
181
182         /* Use _internal here, since this thread can enter a doomed appdomain */
183         mono_domain_set_internal (mono_object_domain (o));              
184
185         /* delegates that have a native function pointer allocated are
186          * registered for finalization, but they don't have a Finalize
187          * method, because in most cases it's not needed and it's just a waste.
188          */
189         if (o->vtable->klass->delegate) {
190                 MonoDelegate* del = (MonoDelegate*)o;
191                 if (del->delegate_trampoline)
192                         mono_delegate_free_ftnptr ((MonoDelegate*)o);
193                 return;
194         }
195
196         finalizer = mono_class_get_finalizer (o->vtable->klass);
197
198 #ifndef DISABLE_COM
199         /* If object has a CCW but has no finalizer, it was only
200          * registered for finalization in order to free the CCW.
201          * Else it needs the regular finalizer run.
202          * FIXME: what to do about ressurection and suppression
203          * of finalizer on object with CCW.
204          */
205         if (mono_marshal_free_ccw (o) && !finalizer)
206                 return;
207 #endif
208
209         /* 
210          * To avoid the locking plus the other overhead of mono_runtime_invoke (),
211          * create and precompile a wrapper which calls the finalize method using
212          * a CALLVIRT.
213          */
214         if (!domain->finalize_runtime_invoke) {
215                 MonoMethod *invoke = mono_marshal_get_runtime_invoke (mono_class_get_method_from_name_flags (mono_defaults.object_class, "Finalize", 0, 0), TRUE);
216
217                 domain->finalize_runtime_invoke = mono_compile_method (invoke);
218         }
219
220         runtime_invoke = domain->finalize_runtime_invoke;
221
222         mono_runtime_class_init (o->vtable);
223
224         runtime_invoke (o, NULL, &exc, NULL);
225
226         if (exc) {
227                 /* fixme: do something useful */
228         }
229 }
230
231 void
232 mono_gc_finalize_threadpool_threads (void)
233 {
234         while (threads_to_finalize) {
235                 MonoThread *thread = (MonoThread*) mono_mlist_get_data (threads_to_finalize);
236
237                 /* Force finalization of the thread. */
238                 thread->threadpool_thread = FALSE;
239                 mono_object_register_finalizer ((MonoObject*)thread);
240
241                 mono_gc_run_finalize (thread, NULL);
242
243                 threads_to_finalize = mono_mlist_next (threads_to_finalize);
244         }
245 }
246
247 gpointer
248 mono_gc_out_of_memory (size_t size)
249 {
250         /* 
251          * we could allocate at program startup some memory that we could release 
252          * back to the system at this point if we're really low on memory (ie, size is
253          * lower than the memory we set apart)
254          */
255         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
256
257         return NULL;
258 }
259
260 /*
261  * Some of our objects may point to a different address than the address returned by GC_malloc()
262  * (because of the GetHashCode hack), but we need to pass the real address to register_finalizer.
263  * This also means that in the callback we need to adjust the pointer to get back the real
264  * MonoObject*.
265  * We also need to be consistent in the use of the GC_debug* variants of malloc and register_finalizer, 
266  * since that, too, can cause the underlying pointer to be offset.
267  */
268 static void
269 object_register_finalizer (MonoObject *obj, void (*callback)(void *, void*))
270 {
271 #if HAVE_BOEHM_GC
272         guint offset = 0;
273         MonoDomain *domain = obj->vtable->domain;
274
275 #ifndef GC_DEBUG
276         /* This assertion is not valid when GC_DEBUG is defined */
277         g_assert (GC_base (obj) == (char*)obj - offset);
278 #endif
279
280         if (mono_domain_is_unloading (domain) && (callback != NULL))
281                 /*
282                  * Can't register finalizers in a dying appdomain, since they
283                  * could be invoked after the appdomain has been unloaded.
284                  */
285                 return;
286
287         domain_finalizers_lock (domain);
288
289         if (callback)
290                 g_hash_table_insert (domain->finalizable_objects_hash, obj, obj);
291         else
292                 g_hash_table_remove (domain->finalizable_objects_hash, obj);
293
294         domain_finalizers_unlock (domain);
295
296         GC_REGISTER_FINALIZER_NO_ORDER ((char*)obj - offset, callback, GUINT_TO_POINTER (offset), NULL, NULL);
297 #elif defined(HAVE_SGEN_GC)
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
335         if (mono_thread_current () == gc_thread)
336                 /* We are called from inside a finalizer, not much we can do here */
337                 return FALSE;
338
339         /* 
340          * No need to create another thread 'cause the finalizer thread
341          * is still working and will take care of running the finalizers
342          */ 
343         
344 #ifndef HAVE_NULL_GC
345         if (gc_disabled)
346                 return TRUE;
347
348         mono_gc_collect (mono_gc_max_generation ());
349
350         done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
351         if (done_event == NULL) {
352                 return FALSE;
353         }
354
355         req = g_new0 (DomainFinalizationReq, 1);
356         req->domain = domain;
357         req->done_event = done_event;
358
359         if (domain == mono_get_root_domain ())
360                 finalizing_root_domain = TRUE;
361         
362         mono_finalizer_lock ();
363
364         domains_to_finalize = g_slist_append (domains_to_finalize, req);
365
366         mono_finalizer_unlock ();
367
368         /* Tell the finalizer thread to finalize this appdomain */
369         mono_gc_finalize_notify ();
370
371         if (timeout == -1)
372                 timeout = INFINITE;
373
374         res = WaitForSingleObjectEx (done_event, timeout, TRUE);
375
376         /* printf ("WAIT RES: %d.\n", res); */
377         if (res == WAIT_TIMEOUT) {
378                 /* We leak the handle here */
379                 return FALSE;
380         }
381
382         CloseHandle (done_event);
383
384         if (domain == mono_get_root_domain ()) {
385                 mono_thread_pool_cleanup ();
386                 mono_gc_finalize_threadpool_threads ();
387         }
388
389         return TRUE;
390 #else
391         /* We don't support domain finalization without a GC */
392         return FALSE;
393 #endif
394 }
395
396 void
397 ves_icall_System_GC_InternalCollect (int generation)
398 {
399         mono_gc_collect (generation);
400 }
401
402 gint64
403 ves_icall_System_GC_GetTotalMemory (MonoBoolean forceCollection)
404 {
405         MONO_ARCH_SAVE_REGS;
406
407         if (forceCollection)
408                 mono_gc_collect (mono_gc_max_generation ());
409         return mono_gc_get_used_size ();
410 }
411
412 void
413 ves_icall_System_GC_KeepAlive (MonoObject *obj)
414 {
415         MONO_ARCH_SAVE_REGS;
416
417         /*
418          * Does nothing.
419          */
420 }
421
422 void
423 ves_icall_System_GC_ReRegisterForFinalize (MonoObject *obj)
424 {
425         MONO_ARCH_SAVE_REGS;
426
427         object_register_finalizer (obj, mono_gc_run_finalize);
428 }
429
430 void
431 ves_icall_System_GC_SuppressFinalize (MonoObject *obj)
432 {
433         MONO_ARCH_SAVE_REGS;
434
435         /* delegates have no finalizers, but we register them to deal with the
436          * unmanaged->managed trampoline. We don't let the user suppress it
437          * otherwise we'd leak it.
438          */
439         if (obj->vtable->klass->delegate)
440                 return;
441
442         /* FIXME: Need to handle case where obj has COM Callable Wrapper
443          * generated for it that needs cleaned up, but user wants to suppress
444          * their derived object finalizer. */
445
446         object_register_finalizer (obj, NULL);
447 }
448
449 void
450 ves_icall_System_GC_WaitForPendingFinalizers (void)
451 {
452 #ifndef HAVE_NULL_GC
453         if (!mono_gc_pending_finalizers ())
454                 return;
455
456         if (mono_thread_current () == gc_thread)
457                 /* Avoid deadlocks */
458                 return;
459
460         ResetEvent (pending_done_event);
461         mono_gc_finalize_notify ();
462         /* g_print ("Waiting for pending finalizers....\n"); */
463         WaitForSingleObjectEx (pending_done_event, INFINITE, TRUE);
464         /* g_print ("Done pending....\n"); */
465 #endif
466 }
467
468 #define mono_allocator_lock() EnterCriticalSection (&allocator_section)
469 #define mono_allocator_unlock() LeaveCriticalSection (&allocator_section)
470 static CRITICAL_SECTION allocator_section;
471 static CRITICAL_SECTION handle_section;
472
473 typedef enum {
474         HANDLE_WEAK,
475         HANDLE_WEAK_TRACK,
476         HANDLE_NORMAL,
477         HANDLE_PINNED
478 } HandleType;
479
480 static HandleType mono_gchandle_get_type (guint32 gchandle);
481
482 MonoObject *
483 ves_icall_System_GCHandle_GetTarget (guint32 handle)
484 {
485         return mono_gchandle_get_target (handle);
486 }
487
488 /*
489  * if type == -1, change the target of the handle, otherwise allocate a new handle.
490  */
491 guint32
492 ves_icall_System_GCHandle_GetTargetHandle (MonoObject *obj, guint32 handle, gint32 type)
493 {
494         if (type == -1) {
495                 mono_gchandle_set_target (handle, obj);
496                 /* the handle doesn't change */
497                 return handle;
498         }
499         switch (type) {
500         case HANDLE_WEAK:
501                 return mono_gchandle_new_weakref (obj, FALSE);
502         case HANDLE_WEAK_TRACK:
503                 return mono_gchandle_new_weakref (obj, TRUE);
504         case HANDLE_NORMAL:
505                 return mono_gchandle_new (obj, FALSE);
506         case HANDLE_PINNED:
507                 return mono_gchandle_new (obj, TRUE);
508         default:
509                 g_assert_not_reached ();
510         }
511         return 0;
512 }
513
514 void
515 ves_icall_System_GCHandle_FreeHandle (guint32 handle)
516 {
517         mono_gchandle_free (handle);
518 }
519
520 gpointer
521 ves_icall_System_GCHandle_GetAddrOfPinnedObject (guint32 handle)
522 {
523         MonoObject *obj;
524
525         if (mono_gchandle_get_type (handle) != HANDLE_PINNED)
526                 return (gpointer)-2;
527         obj = mono_gchandle_get_target (handle);
528         if (obj) {
529                 MonoClass *klass = mono_object_class (obj);
530                 if (klass == mono_defaults.string_class) {
531                         return mono_string_chars ((MonoString*)obj);
532                 } else if (klass->rank) {
533                         return mono_array_addr ((MonoArray*)obj, char, 0);
534                 } else {
535                         /* the C# code will check and throw the exception */
536                         /* FIXME: missing !klass->blittable test, see bug #61134 */
537                         if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
538                                 return (gpointer)-1;
539                         return (char*)obj + sizeof (MonoObject);
540                 }
541         }
542         return NULL;
543 }
544
545 typedef struct {
546         guint32  *bitmap;
547         gpointer *entries;
548         guint32   size;
549         guint8    type;
550         guint     slot_hint : 24; /* starting slot for search */
551         /* 2^16 appdomains should be enough for everyone (though I know I'll regret this in 20 years) */
552         /* we alloc this only for weak refs, since we can get the domain directly in the other cases */
553         guint16  *domain_ids;
554 } HandleData;
555
556 /* weak and weak-track arrays will be allocated in malloc memory 
557  */
558 static HandleData gc_handles [] = {
559         {NULL, NULL, 0, HANDLE_WEAK, 0},
560         {NULL, NULL, 0, HANDLE_WEAK_TRACK, 0},
561         {NULL, NULL, 0, HANDLE_NORMAL, 0},
562         {NULL, NULL, 0, HANDLE_PINNED, 0}
563 };
564
565 #define lock_handles(handles) EnterCriticalSection (&handle_section)
566 #define unlock_handles(handles) LeaveCriticalSection (&handle_section)
567
568 static int
569 find_first_unset (guint32 bitmap)
570 {
571         int i;
572         for (i = 0; i < 32; ++i) {
573                 if (!(bitmap & (1 << i)))
574                         return i;
575         }
576         return -1;
577 }
578
579 static guint32
580 alloc_handle (HandleData *handles, MonoObject *obj)
581 {
582         gint slot, i;
583         lock_handles (handles);
584         if (!handles->size) {
585                 handles->size = 32;
586                 if (handles->type > HANDLE_WEAK_TRACK) {
587                         handles->entries = mono_gc_alloc_fixed (sizeof (gpointer) * handles->size, NULL);
588                 } else {
589                         handles->entries = g_malloc0 (sizeof (gpointer) * handles->size);
590                         handles->domain_ids = g_malloc0 (sizeof (guint16) * handles->size);
591                 }
592                 handles->bitmap = g_malloc0 (handles->size / 8);
593         }
594         i = -1;
595         for (slot = handles->slot_hint; slot < handles->size / 32; ++slot) {
596                 if (handles->bitmap [slot] != 0xffffffff) {
597                         i = find_first_unset (handles->bitmap [slot]);
598                         handles->slot_hint = slot;
599                         break;
600                 }
601         }
602         if (i == -1 && handles->slot_hint != 0) {
603                 for (slot = 0; slot < handles->slot_hint; ++slot) {
604                         if (handles->bitmap [slot] != 0xffffffff) {
605                                 i = find_first_unset (handles->bitmap [slot]);
606                                 handles->slot_hint = slot;
607                                 break;
608                         }
609                 }
610         }
611         if (i == -1) {
612                 guint32 *new_bitmap;
613                 guint32 new_size = handles->size * 2; /* always double: we memset to 0 based on this below */
614
615                 /* resize and copy the bitmap */
616                 new_bitmap = g_malloc0 (new_size / 8);
617                 memcpy (new_bitmap, handles->bitmap, handles->size / 8);
618                 g_free (handles->bitmap);
619                 handles->bitmap = new_bitmap;
620
621                 /* resize and copy the entries */
622                 if (handles->type > HANDLE_WEAK_TRACK) {
623                         gpointer *entries;
624                         entries = mono_gc_alloc_fixed (sizeof (gpointer) * new_size, NULL);
625                         memcpy (entries, handles->entries, sizeof (gpointer) * handles->size);
626                         handles->entries = entries;
627                 } else {
628                         gpointer *entries;
629                         guint16 *domain_ids;
630                         domain_ids = g_malloc0 (sizeof (guint16) * new_size);
631                         entries = g_malloc (sizeof (gpointer) * new_size);
632                         /* we disable GC because we could lose some disappearing link updates */
633                         mono_gc_disable ();
634                         memcpy (entries, handles->entries, sizeof (gpointer) * handles->size);
635                         memset (entries + handles->size, 0, sizeof (gpointer) * handles->size);
636                         memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
637                         for (i = 0; i < handles->size; ++i) {
638                                 MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
639                                 if (handles->entries [i])
640                                         mono_gc_weak_link_remove (&(handles->entries [i]));
641                                 /*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]);*/
642                                 if (obj) {
643                                         mono_gc_weak_link_add (&(entries [i]), obj);
644                                 }
645                         }
646                         g_free (handles->entries);
647                         g_free (handles->domain_ids);
648                         handles->entries = entries;
649                         handles->domain_ids = domain_ids;
650                         mono_gc_enable ();
651                 }
652
653                 /* set i and slot to the next free position */
654                 i = 0;
655                 slot = (handles->size + 1) / 32;
656                 handles->slot_hint = handles->size + 1;
657                 handles->size = new_size;
658         }
659         handles->bitmap [slot] |= 1 << i;
660         slot = slot * 32 + i;
661         handles->entries [slot] = obj;
662         if (handles->type <= HANDLE_WEAK_TRACK) {
663                 if (obj)
664                         mono_gc_weak_link_add (&(handles->entries [slot]), obj);
665         }
666
667         mono_perfcounters->gc_num_handles++;
668         unlock_handles (handles);
669         /*g_print ("allocated entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
670         return (slot << 3) | (handles->type + 1);
671 }
672
673 /**
674  * mono_gchandle_new:
675  * @obj: managed object to get a handle for
676  * @pinned: whether the object should be pinned
677  *
678  * This returns a handle that wraps the object, this is used to keep a
679  * reference to a managed object from the unmanaged world and preventing the
680  * object from being disposed.
681  * 
682  * If @pinned is false the address of the object can not be obtained, if it is
683  * true the address of the object can be obtained.  This will also pin the
684  * object so it will not be possible by a moving garbage collector to move the
685  * object. 
686  * 
687  * Returns: a handle that can be used to access the object from
688  * unmanaged code.
689  */
690 guint32
691 mono_gchandle_new (MonoObject *obj, gboolean pinned)
692 {
693         return alloc_handle (&gc_handles [pinned? HANDLE_PINNED: HANDLE_NORMAL], obj);
694 }
695
696 /*
697  * LOCKING: Assumes the domain_finalizers lock is held.
698  */
699 static void
700 add_weak_track_handle (MonoDomain *domain, MonoObject *obj, guint32 gchandle)
701 {
702         GSList *refs;
703
704         if (!domain->track_resurrection_objects_hash)
705                 domain->track_resurrection_objects_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
706
707         refs = g_hash_table_lookup (domain->track_resurrection_objects_hash, obj);
708         refs = g_slist_prepend (refs, GUINT_TO_POINTER (gchandle));
709         g_hash_table_insert (domain->track_resurrection_objects_hash, obj, refs);
710 }
711
712 /*
713  * LOCKING: Assumes the domain_finalizers lock is held.
714  */
715 static void
716 remove_weak_track_handle (MonoDomain *domain, MonoObject *obj, guint32 gchandle)
717 {
718         GSList *refs;
719
720         if (!domain->track_resurrection_objects_hash)
721                 return;
722
723         refs = g_hash_table_lookup (domain->track_resurrection_objects_hash, obj);
724         refs = g_slist_remove (refs, GUINT_TO_POINTER (gchandle));
725         g_hash_table_insert (domain->track_resurrection_objects_hash, obj, refs);
726 }
727
728 /**
729  * mono_gchandle_new_weakref:
730  * @obj: managed object to get a handle for
731  * @pinned: whether the object should be pinned
732  *
733  * This returns a weak handle that wraps the object, this is used to
734  * keep a reference to a managed object from the unmanaged world.
735  * Unlike the mono_gchandle_new the object can be reclaimed by the
736  * garbage collector.  In this case the value of the GCHandle will be
737  * set to zero.
738  * 
739  * If @pinned is false the address of the object can not be obtained, if it is
740  * true the address of the object can be obtained.  This will also pin the
741  * object so it will not be possible by a moving garbage collector to move the
742  * object. 
743  * 
744  * Returns: a handle that can be used to access the object from
745  * unmanaged code.
746  */
747 guint32
748 mono_gchandle_new_weakref (MonoObject *obj, gboolean track_resurrection)
749 {
750         guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj);
751
752         if (track_resurrection) {
753                 MonoDomain *domain = mono_domain_get ();
754
755                 domain_finalizers_lock (domain);
756
757                 add_weak_track_handle (domain, obj, handle);
758
759                 g_hash_table_insert (domain->track_resurrection_handles_hash, GUINT_TO_POINTER (handle), obj);
760
761                 domain_finalizers_unlock (domain);
762
763 #ifdef HAVE_SGEN_GC
764                 // FIXME: The hash table entries need to be remapped during GC
765                 g_assert_not_reached ();
766 #endif
767         }
768
769         return handle;
770 }
771
772 static HandleType
773 mono_gchandle_get_type (guint32 gchandle)
774 {
775         guint type = (gchandle & 7) - 1;
776
777         return type;
778 }
779
780 /**
781  * mono_gchandle_get_target:
782  * @gchandle: a GCHandle's handle.
783  *
784  * The handle was previously created by calling mono_gchandle_new or
785  * mono_gchandle_new_weakref. 
786  *
787  * Returns a pointer to the MonoObject represented by the handle or
788  * NULL for a collected object if using a weakref handle.
789  */
790 MonoObject*
791 mono_gchandle_get_target (guint32 gchandle)
792 {
793         guint slot = gchandle >> 3;
794         guint type = (gchandle & 7) - 1;
795         HandleData *handles = &gc_handles [type];
796         MonoObject *obj = NULL;
797         if (type > 3)
798                 return NULL;
799         lock_handles (handles);
800         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
801                 if (handles->type <= HANDLE_WEAK_TRACK) {
802                         obj = mono_gc_weak_link_get (&handles->entries [slot]);
803                 } else {
804                         obj = handles->entries [slot];
805                 }
806         } else {
807                 /* print a warning? */
808         }
809         unlock_handles (handles);
810         /*g_print ("get target of entry %d of type %d: %p\n", slot, handles->type, obj);*/
811         return obj;
812 }
813
814 static void
815 mono_gchandle_set_target (guint32 gchandle, MonoObject *obj)
816 {
817         guint slot = gchandle >> 3;
818         guint type = (gchandle & 7) - 1;
819         HandleData *handles = &gc_handles [type];
820         MonoObject *old_obj = NULL;
821
822         if (type > 3)
823                 return;
824         lock_handles (handles);
825         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
826                 if (handles->type <= HANDLE_WEAK_TRACK) {
827                         old_obj = handles->entries [slot];
828                         if (handles->entries [slot])
829                                 mono_gc_weak_link_remove (&handles->entries [slot]);
830                         if (obj)
831                                 mono_gc_weak_link_add (&handles->entries [slot], obj);
832                 } else {
833                         handles->entries [slot] = obj;
834                 }
835         } else {
836                 /* print a warning? */
837         }
838         /*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
839         unlock_handles (handles);
840
841         if (type == HANDLE_WEAK_TRACK) {
842                 MonoDomain *domain = mono_domain_get ();
843
844                 domain_finalizers_lock (domain);
845
846                 if (old_obj)
847                         remove_weak_track_handle (domain, old_obj, gchandle);
848                 if (obj)
849                         add_weak_track_handle (domain, obj, gchandle);
850
851                 domain_finalizers_unlock (domain);
852         }
853 }
854
855 /**
856  * mono_gchandle_is_in_domain:
857  * @gchandle: a GCHandle's handle.
858  * @domain: An application domain.
859  *
860  * Returns: true if the object wrapped by the @gchandle belongs to the specific @domain.
861  */
862 gboolean
863 mono_gchandle_is_in_domain (guint32 gchandle, MonoDomain *domain)
864 {
865         guint slot = gchandle >> 3;
866         guint type = (gchandle & 7) - 1;
867         HandleData *handles = &gc_handles [type];
868         gboolean result = FALSE;
869         if (type > 3)
870                 return FALSE;
871         lock_handles (handles);
872         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
873                 if (handles->type <= HANDLE_WEAK_TRACK) {
874                         result = domain->domain_id == handles->domain_ids [slot];
875                 } else {
876                         MonoObject *obj;
877                         obj = handles->entries [slot];
878                         if (obj == NULL)
879                                 result = TRUE;
880                         else
881                                 result = domain == mono_object_domain (obj);
882                 }
883         } else {
884                 /* print a warning? */
885         }
886         unlock_handles (handles);
887         return result;
888 }
889
890 /**
891  * mono_gchandle_free:
892  * @gchandle: a GCHandle's handle.
893  *
894  * Frees the @gchandle handle.  If there are no outstanding
895  * references, the garbage collector can reclaim the memory of the
896  * object wrapped. 
897  */
898 void
899 mono_gchandle_free (guint32 gchandle)
900 {
901         guint slot = gchandle >> 3;
902         guint type = (gchandle & 7) - 1;
903         HandleData *handles = &gc_handles [type];
904         if (type > 3)
905                 return;
906         if (type == HANDLE_WEAK_TRACK) {
907                 MonoDomain *domain = mono_domain_get ();
908                 MonoObject *obj;
909
910                 /* Clean our entries in the two hashes in MonoDomain */
911
912                 domain_finalizers_lock (domain);
913
914                 /* Get the original object this handle pointed to */
915                 obj = g_hash_table_lookup (domain->track_resurrection_handles_hash, GUINT_TO_POINTER (gchandle));
916                 if (obj) {
917                         g_hash_table_remove (domain->track_resurrection_handles_hash, GUINT_TO_POINTER (gchandle));
918
919                         remove_weak_track_handle (domain, obj, gchandle);
920                 }
921
922                 domain_finalizers_unlock (domain);
923         }
924
925         lock_handles (handles);
926         if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
927                 if (handles->type <= HANDLE_WEAK_TRACK) {
928                         if (handles->entries [slot])
929                                 mono_gc_weak_link_remove (&handles->entries [slot]);
930                 } else {
931                         handles->entries [slot] = NULL;
932                 }
933                 handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
934         } else {
935                 /* print a warning? */
936         }
937         mono_perfcounters->gc_num_handles--;
938         /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/
939         unlock_handles (handles);
940 }
941
942 /**
943  * mono_gchandle_free_domain:
944  * @domain: domain that is unloading
945  *
946  * Function used internally to cleanup any GC handle for objects belonging
947  * to the specified domain during appdomain unload.
948  */
949 void
950 mono_gchandle_free_domain (MonoDomain *domain)
951 {
952         guint type;
953
954         for (type = 0; type < 3; ++type) {
955                 guint slot;
956                 HandleData *handles = &gc_handles [type];
957                 lock_handles (handles);
958                 for (slot = 0; slot < handles->size; ++slot) {
959                         if (!(handles->bitmap [slot / 32] & (1 << (slot % 32))))
960                                 continue;
961                         if (type <= HANDLE_WEAK_TRACK) {
962                                 if (domain->domain_id == handles->domain_ids [slot]) {
963                                         handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
964                                         if (handles->entries [slot])
965                                                 mono_gc_weak_link_remove (&handles->entries [slot]);
966                                 }
967                         } else {
968                                 if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
969                                         handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
970                                         handles->entries [slot] = NULL;
971                                 }
972                         }
973                 }
974                 unlock_handles (handles);
975         }
976
977 }
978
979 #ifndef HAVE_NULL_GC
980
981 #if USE_POSIX_SEM
982 static sem_t finalizer_sem;
983 #endif
984 static HANDLE finalizer_event;
985 static volatile gboolean finished=FALSE;
986
987 void
988 mono_gc_finalize_notify (void)
989 {
990 #ifdef DEBUG
991         g_message (G_GNUC_PRETTY_FUNCTION ": prodding finalizer");
992 #endif
993
994 #if USE_POSIX_SEM
995         sem_post (&finalizer_sem);
996 #else
997         SetEvent (finalizer_event);
998 #endif
999 }
1000
1001 #ifdef HAVE_BOEHM_GC
1002
1003 static void
1004 collect_objects (gpointer key, gpointer value, gpointer user_data)
1005 {
1006         GPtrArray *arr = (GPtrArray*)user_data;
1007         g_ptr_array_add (arr, key);
1008 }
1009
1010 #endif
1011
1012 /*
1013  * finalize_domain_objects:
1014  *
1015  *  Run the finalizers of all finalizable objects in req->domain.
1016  */
1017 static void
1018 finalize_domain_objects (DomainFinalizationReq *req)
1019 {
1020         MonoDomain *domain = req->domain;
1021
1022 #ifdef HAVE_BOEHM_GC
1023         while (g_hash_table_size (domain->finalizable_objects_hash) > 0) {
1024                 int i;
1025                 GPtrArray *objs;
1026                 /* 
1027                  * Since the domain is unloading, nobody is allowed to put
1028                  * new entries into the hash table. But finalize_object might
1029                  * remove entries from the hash table, so we make a copy.
1030                  */
1031                 objs = g_ptr_array_new ();
1032                 g_hash_table_foreach (domain->finalizable_objects_hash, collect_objects, objs);
1033                 /* printf ("FINALIZING %d OBJECTS.\n", objs->len); */
1034
1035                 for (i = 0; i < objs->len; ++i) {
1036                         MonoObject *o = (MonoObject*)g_ptr_array_index (objs, i);
1037                         /* FIXME: Avoid finalizing threads, etc */
1038                         mono_gc_run_finalize (o, 0);
1039                 }
1040
1041                 g_ptr_array_free (objs, TRUE);
1042         }
1043 #elif defined(HAVE_SGEN_GC)
1044 #define NUM_FOBJECTS 64
1045         MonoObject *to_finalize [NUM_FOBJECTS];
1046         int count;
1047         while ((count = mono_gc_finalizers_for_domain (domain, to_finalize, NUM_FOBJECTS))) {
1048                 int i;
1049                 for (i = 0; i < count; ++i) {
1050                         mono_gc_run_finalize (to_finalize [i], 0);
1051                 }
1052         }
1053 #endif
1054
1055         /* Process finalizers which are already in the queue */
1056         mono_gc_invoke_finalizers ();
1057
1058         /* printf ("DONE.\n"); */
1059         SetEvent (req->done_event);
1060
1061         /* The event is closed in mono_domain_finalize if we get here */
1062         g_free (req);
1063 }
1064
1065 static guint32
1066 finalizer_thread (gpointer unused)
1067 {
1068         gc_thread = mono_thread_current ();
1069
1070         SetEvent (thread_started_event);
1071
1072         while (!finished) {
1073                 /* Wait to be notified that there's at least one
1074                  * finaliser to run
1075                  */
1076 #if USE_POSIX_SEM
1077                 sem_wait (&finalizer_sem);
1078 #else
1079                 /* Use alertable=FALSE since we will be asked to exit using the event too */
1080                 WaitForSingleObjectEx (finalizer_event, INFINITE, FALSE);
1081 #endif
1082
1083 #ifndef DISABLE_ATTACH
1084                 mono_attach_maybe_start ();
1085 #endif
1086
1087                 if (domains_to_finalize) {
1088                         mono_finalizer_lock ();
1089                         if (domains_to_finalize) {
1090                                 DomainFinalizationReq *req = domains_to_finalize->data;
1091                                 domains_to_finalize = g_slist_remove (domains_to_finalize, req);
1092                                 mono_finalizer_unlock ();
1093
1094                                 finalize_domain_objects (req);
1095                         } else {
1096                                 mono_finalizer_unlock ();
1097                         }
1098                 }                               
1099
1100                 /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup),
1101                  * before the domain is unloaded.
1102                  */
1103                 mono_gc_invoke_finalizers ();
1104
1105                 SetEvent (pending_done_event);
1106         }
1107
1108         SetEvent (shutdown_event);
1109         return 0;
1110 }
1111
1112 void
1113 mono_gc_init (void)
1114 {
1115         InitializeCriticalSection (&handle_section);
1116         InitializeCriticalSection (&allocator_section);
1117
1118         InitializeCriticalSection (&finalizer_mutex);
1119
1120         MONO_GC_REGISTER_ROOT (gc_handles [HANDLE_NORMAL].entries);
1121         MONO_GC_REGISTER_ROOT (gc_handles [HANDLE_PINNED].entries);
1122
1123         mono_gc_base_init ();
1124
1125         if (g_getenv ("GC_DONT_GC")) {
1126                 gc_disabled = TRUE;
1127                 return;
1128         }
1129         
1130         finalizer_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1131         pending_done_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1132         shutdown_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1133         thread_started_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1134         if (finalizer_event == NULL || pending_done_event == NULL || shutdown_event == NULL || thread_started_event == NULL) {
1135                 g_assert_not_reached ();
1136         }
1137 #if USE_POSIX_SEM
1138         sem_init (&finalizer_sem, 0, 0);
1139 #endif
1140
1141         mono_thread_create (mono_domain_get (), finalizer_thread, NULL);
1142
1143         /*
1144          * Wait until the finalizer thread sets gc_thread since its value is needed
1145          * by mono_thread_attach ()
1146          *
1147          * FIXME: Eliminate this as to avoid some deadlocks on windows. 
1148          * Waiting for a new thread should result in a deadlock when the runtime is
1149          * initialized from _CorDllMain that is called while the OS loader lock is
1150          * held by LoadLibrary.
1151          */
1152         WaitForSingleObjectEx (thread_started_event, INFINITE, FALSE);
1153 }
1154
1155 void
1156 mono_gc_cleanup (void)
1157 {
1158 #ifdef DEBUG
1159         g_message (G_GNUC_PRETTY_FUNCTION ": cleaning up finalizer");
1160 #endif
1161
1162         if (!gc_disabled) {
1163                 ResetEvent (shutdown_event);
1164                 finished = TRUE;
1165                 if (mono_thread_current () != gc_thread) {
1166                         mono_gc_finalize_notify ();
1167                         /* Finishing the finalizer thread, so wait a little bit... */
1168                         /* MS seems to wait for about 2 seconds */
1169                         if (WaitForSingleObjectEx (shutdown_event, 2000, FALSE) == WAIT_TIMEOUT) {
1170                                 int ret;
1171
1172                                 /* Set a flag which the finalizer thread can check */
1173                                 suspend_finalizers = TRUE;
1174
1175                                 /* Try to abort the thread, in the hope that it is running managed code */
1176                                 mono_thread_stop (gc_thread);
1177
1178                                 /* Wait for it to stop */
1179                                 ret = WaitForSingleObjectEx (gc_thread->handle, 100, TRUE);
1180
1181                                 if (ret == WAIT_TIMEOUT) {
1182                                         /* 
1183                                          * The finalizer thread refused to die. There is not much we 
1184                                          * can do here, since the runtime is shutting down so the 
1185                                          * state the finalizer thread depends on will vanish.
1186                                          */
1187                                         g_warning ("Shutting down finalizer thread timed out.");
1188                                 } else {
1189                                         /*
1190                                          * FIXME: On unix, when the above wait returns, the thread 
1191                                          * might still be running io-layer code, or pthreads code.
1192                                          */
1193                                         Sleep (100);
1194                                 }
1195
1196                         }
1197                 }
1198                 gc_thread = NULL;
1199 #ifdef HAVE_BOEHM_GC
1200                 GC_finalizer_notifier = NULL;
1201 #endif
1202         }
1203
1204         DeleteCriticalSection (&handle_section);
1205         DeleteCriticalSection (&allocator_section);
1206         DeleteCriticalSection (&finalizer_mutex);
1207 }
1208
1209 #else
1210
1211 /* Null GC dummy functions */
1212 void
1213 mono_gc_finalize_notify (void)
1214 {
1215 }
1216
1217 void mono_gc_init (void)
1218 {
1219         InitializeCriticalSection (&handle_section);
1220 }
1221
1222 void mono_gc_cleanup (void)
1223 {
1224 }
1225
1226 #endif
1227
1228 /**
1229  * mono_gc_is_finalizer_thread:
1230  * @thread: the thread to test.
1231  *
1232  * In Mono objects are finalized asynchronously on a separate thread.
1233  * This routine tests whether the @thread argument represents the
1234  * finalization thread.
1235  * 
1236  * Returns true if @thread is the finalization thread.
1237  */
1238 gboolean
1239 mono_gc_is_finalizer_thread (MonoThread *thread)
1240 {
1241         return thread == gc_thread;
1242 }
1243
1244