#include <mono/utils/mono-memory-model.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/dtrace.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/atomic.h>
#ifndef HOST_WIN32
#include <pthread.h>
MonoDomain *caller_domain = mono_domain_get ();
MonoDomain *domain;
RuntimeInvokeFunction runtime_invoke;
- GSList *l, *refs = NULL;
o = (MonoObject*)((char*)obj + GPOINTER_TO_UINT (data));
o2 = g_hash_table_lookup (domain->finalizable_objects_hash, o);
- refs = mono_gc_remove_weak_track_object (domain, o);
-
mono_domain_finalizers_unlock (domain);
if (!o2)
return;
#endif
- if (refs) {
- /*
- * Support for GCHandles of type WeakTrackResurrection:
- *
- * Its not exactly clear how these are supposed to work, or how their
- * semantics can be implemented. We only implement one crucial thing:
- * these handles are only cleared after the finalizer has ran.
- */
- for (l = refs; l; l = l->next) {
- guint32 gchandle = GPOINTER_TO_UINT (l->data);
-
- mono_gchandle_set_target (gchandle, o);
- }
-
- g_slist_free (refs);
- }
-
/* make sure the finalizer is not called again if the object is resurrected */
object_register_finalizer (obj, NULL);
HANDLE done_event;
MonoInternalThread *thread = mono_thread_internal_current ();
+#if defined(__native_client__)
+ return FALSE;
+#endif
+
if (mono_thread_internal_current () == gc_thread)
/* We are called from inside a finalizer, not much we can do here */
return FALSE;
return NULL;
}
+MonoBoolean
+ves_icall_Mono_Runtime_SetGCAllowSynchronousMajor (MonoBoolean flag)
+{
+ return mono_gc_set_allow_synchronous_major (flag);
+}
+
typedef struct {
guint32 *bitmap;
gpointer *entries;
gpointer *entries;
guint16 *domain_ids;
domain_ids = g_malloc0 (sizeof (guint16) * new_size);
- entries = g_malloc (sizeof (gpointer) * new_size);
- /* we disable GC because we could lose some disappearing link updates */
- mono_gc_disable ();
- mono_gc_memmove (entries, handles->entries, sizeof (gpointer) * handles->size);
- mono_gc_bzero (entries + handles->size, sizeof (gpointer) * handles->size);
+ entries = g_malloc0 (sizeof (gpointer) * new_size);
memcpy (domain_ids, handles->domain_ids, sizeof (guint16) * handles->size);
for (i = 0; i < handles->size; ++i) {
MonoObject *obj = mono_gc_weak_link_get (&(handles->entries [i]));
- if (handles->entries [i])
- mono_gc_weak_link_remove (&(handles->entries [i]));
- /*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]);*/
if (obj) {
mono_gc_weak_link_add (&(entries [i]), obj, track);
+ mono_gc_weak_link_remove (&(handles->entries [i]), track);
+ } else {
+ g_assert (!handles->entries [i]);
}
}
g_free (handles->entries);
g_free (handles->domain_ids);
handles->entries = entries;
handles->domain_ids = domain_ids;
- mono_gc_enable ();
}
/* set i and slot to the next free position */
{
guint32 handle = alloc_handle (&gc_handles [track_resurrection? HANDLE_WEAK_TRACK: HANDLE_WEAK], obj, track_resurrection);
-#ifndef HAVE_SGEN_GC
- if (track_resurrection)
- mono_gc_add_weak_track_handle (obj, handle);
-#endif
-
return handle;
}
if (handles->type <= HANDLE_WEAK_TRACK) {
old_obj = handles->entries [slot];
if (handles->entries [slot])
- mono_gc_weak_link_remove (&handles->entries [slot]);
+ mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
if (obj)
mono_gc_weak_link_add (&handles->entries [slot], obj, handles->type == HANDLE_WEAK_TRACK);
/*FIXME, what to use when obj == null?*/
}
/*g_print ("changed entry %d of type %d to object %p (in slot: %p)\n", slot, handles->type, obj, handles->entries [slot]);*/
unlock_handles (handles);
-
-#ifndef HAVE_SGEN_GC
- if (type == HANDLE_WEAK_TRACK)
- mono_gc_change_weak_track_handle (old_obj, obj, gchandle);
-#endif
}
/**
HandleData *handles = &gc_handles [type];
if (type > 3)
return;
-#ifndef HAVE_SGEN_GC
- if (type == HANDLE_WEAK_TRACK)
- mono_gc_remove_weak_track_handle (gchandle);
-#endif
lock_handles (handles);
if (slot < handles->size && (handles->bitmap [slot / 32] & (1 << (slot % 32)))) {
if (handles->type <= HANDLE_WEAK_TRACK) {
if (handles->entries [slot])
- mono_gc_weak_link_remove (&handles->entries [slot]);
+ mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
} else {
handles->entries [slot] = NULL;
}
if (domain->domain_id == handles->domain_ids [slot]) {
handles->bitmap [slot / 32] &= ~(1 << (slot % 32));
if (handles->entries [slot])
- mono_gc_weak_link_remove (&handles->entries [slot]);
+ mono_gc_weak_link_remove (&handles->entries [slot], handles->type == HANDLE_WEAK_TRACK);
}
} else {
if (handles->entries [slot] && mono_object_domain (handles->entries [slot]) == domain) {
void
mono_gc_init_finalizer_thread (void)
{
- gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, 0);
+ gc_thread = mono_thread_create_internal (mono_domain_get (), finalizer_thread, NULL, FALSE, TRUE, 0);
ves_icall_System_Threading_Thread_SetName_internal (gc_thread, mono_string_new (mono_domain_get (), "Finalizer"));
}
MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries);
MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries);
+ mono_counters_register ("Created object count", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &mono_stats.new_object_count);
mono_counters_register ("Minor GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.minor_gc_count);
mono_counters_register ("Major GC collections", MONO_COUNTER_GC | MONO_COUNTER_INT, &gc_stats.major_gc_count);
mono_counters_register ("Minor GC time", MONO_COUNTER_GC | MONO_COUNTER_TIME_INTERVAL, &gc_stats.minor_gc_time_usecs);
/* Wait for the thread to actually exit */
ret = WaitForSingleObjectEx (gc_thread->handle, INFINITE, TRUE);
g_assert (ret == WAIT_OBJECT_0);
+
+#ifndef HOST_WIN32
+ /*
+ * The above wait only waits for the exited event to be signalled, the thread might still be running. To fix this race, we
+ * create the finalizer thread without calling pthread_detach () on it, so we can wait for it manually.
+ */
+ ret = pthread_join ((MonoNativeThreadId)(gpointer)(gsize)gc_thread->tid, NULL);
+ g_assert (ret == 0);
+#endif
}
}
gc_thread = NULL;
while ((entry = *iter)) {
#ifdef HAVE_SGEN_GC
if (queue->should_be_deleted || !mono_gc_weak_link_get (&entry->dis_link)) {
- mono_gc_weak_link_remove (&entry->dis_link);
+ mono_gc_weak_link_remove (&entry->dis_link, TRUE);
#else
if (queue->should_be_deleted || !mono_gchandle_get_target (entry->gchandle)) {
mono_gchandle_free ((guint32)entry->gchandle);
#ifdef HAVE_SGEN_GC
obj = mono_gc_weak_link_get (&entry->dis_link);
if (obj && mono_object_domain (obj) == domain) {
- mono_gc_weak_link_remove (&entry->dis_link);
+ mono_gc_weak_link_remove (&entry->dis_link, TRUE);
#else
obj = mono_gchandle_get_target (entry->gchandle);
if (obj && mono_object_domain (obj) == domain) {
#define align_down(ptr) ((void*)(_toi(ptr) & ~ptr_mask))
#define align_up(ptr) ((void*) ((_toi(ptr) + ptr_mask) & ~ptr_mask))
+#define BZERO_WORDS(dest,words) do { \
+ int __i; \
+ for (__i = 0; __i < (words); ++__i) \
+ ((void **)(dest))[__i] = 0; \
+} while (0)
+
/**
* mono_gc_bzero:
* @dest: address to start to clear
void
mono_gc_bzero (void *dest, size_t size)
{
- char *p = (char*)dest;
- char *end = p + size;
- char *align_end = align_up (p);
- char *word_end;
-
- while (p < align_end)
- *p++ = 0;
-
- word_end = align_down (end);
- while (p < word_end) {
- *((void**)p) = NULL;
- p += sizeof (void*);
+ char *d = (char*)dest;
+ size_t tail_bytes, word_bytes;
+
+ /*
+ If we're copying less than a word, just use memset.
+
+ We cannot bail out early if both are aligned because some implementations
+ use byte copying for sizes smaller than 16. OSX, on this case.
+ */
+ if (size < sizeof(void*)) {
+ memset (dest, 0, size);
+ return;
}
- while (p < end)
- *p++ = 0;
-}
+ /*align to word boundary */
+ while (unaligned_bytes (d) && size) {
+ *d++ = 0;
+ --size;
+ }
+
+ /* copy all words with memmove */
+ word_bytes = (size_t)align_down (size);
+ switch (word_bytes) {
+ case sizeof (void*) * 1:
+ BZERO_WORDS (d, 1);
+ break;
+ case sizeof (void*) * 2:
+ BZERO_WORDS (d, 2);
+ break;
+ case sizeof (void*) * 3:
+ BZERO_WORDS (d, 3);
+ break;
+ case sizeof (void*) * 4:
+ BZERO_WORDS (d, 4);
+ break;
+ default:
+ memset (d, 0, word_bytes);
+ }
+ tail_bytes = unaligned_bytes (size);
+ if (tail_bytes) {
+ d += word_bytes;
+ do {
+ *d++ = 0;
+ } while (--tail_bytes);
+ }
+}
/**
* mono_gc_memmove:
* Move @size bytes from @src to @dest.
* size MUST be a multiple of sizeof (gpointer)
*
- * FIXME borrow faster code from some BSD libc or bionic
*/
void
mono_gc_memmove (void *dest, const void *src, size_t size)
{
/*
- * If dest and src are differently aligned with respect to
- * pointer size then it makes no sense to do aligned copying.
- * In fact, we would end up with unaligned loads which is
- * incorrect on some architectures.
- */
- if ((char*)dest - (char*)align_down (dest) != (char*)src - (char*)align_down (src)) {
+ If we're copying less than a word we don't need to worry about word tearing
+ so we bailout to memmove early.
+
+ If both dest is aligned and size is a multiple of word size, we can go straigh
+ to memmove.
+
+ */
+ if (size < sizeof(void*) || !((_toi (dest) | (size)) & sizeof (void*))) {
memmove (dest, src, size);
return;
}
* A bit of explanation on why we align only dest before doing word copies.
* Pointers to managed objects must always be stored in word aligned addresses, so
* even if dest is misaligned, src will be by the same amount - this ensure proper atomicity of reads.
+ *
+ * We don't need to case when source and destination have different alignments since we only do word stores
+ * using memmove, which must handle it.
*/
- if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) {
+ if (dest > src && ((size_t)((char*)dest - (char*)src) < size)) { /*backward copy*/
char *p = (char*)dest + size;
- char *s = (char*)src + size;
- char *start = (char*)dest;
- char *align_end = MAX((char*)dest, (char*)align_down (p));
- char *word_start;
-
- while (p > align_end)
- *--p = *--s;
-
- word_start = align_up (start);
- while (p > word_start) {
- p -= sizeof (void*);
- s -= sizeof (void*);
- *((void**)p) = *((void**)s);
- }
-
- while (p > start)
- *--p = *--s;
+ char *s = (char*)src + size;
+ char *start = (char*)dest;
+ char *align_end = MAX((char*)dest, (char*)align_down (p));
+ char *word_start;
+ size_t bytes_to_memmove;
+
+ while (p > align_end)
+ *--p = *--s;
+
+ word_start = align_up (start);
+ bytes_to_memmove = p - word_start;
+ p -= bytes_to_memmove;
+ s -= bytes_to_memmove;
+ memmove (p, s, bytes_to_memmove);
+
+ while (p > start)
+ *--p = *--s;
} else {
- char *p = (char*)dest;
- char *s = (char*)src;
- char *end = p + size;
- char *align_end = MIN ((char*)end, (char*)align_up (p));
- char *word_end;
-
- while (p < align_end)
- *p++ = *s++;
-
- word_end = align_down (end);
- while (p < word_end) {
- *((void**)p) = *((void**)s);
- p += sizeof (void*);
- s += sizeof (void*);
+ char *d = (char*)dest;
+ const char *s = (const char*)src;
+ size_t tail_bytes;
+
+ /*align to word boundary */
+ while (unaligned_bytes (d)) {
+ *d++ = *s++;
+ --size;
}
- while (p < end)
- *p++ = *s++;
+ /* copy all words with memmove */
+ memmove (d, s, (size_t)align_down (size));
+
+ tail_bytes = unaligned_bytes (size);
+ if (tail_bytes) {
+ d += (size_t)align_down (size);
+ s += (size_t)align_down (size);
+ do {
+ *d++ = *s++;
+ } while (--tail_bytes);
+ }
}
}