#ifdef __MACH__
#define _XOPEN_SOURCE
#endif
+
+#include "metadata/sgen-gc.h"
#include "metadata/metadata-internals.h"
#include "metadata/class-internals.h"
#include "metadata/gc-internal.h"
#include "metadata/object-internals.h"
#include "metadata/threads.h"
-#include "metadata/sgen-gc.h"
#include "metadata/sgen-cardtable.h"
#include "metadata/sgen-protocol.h"
#include "metadata/sgen-archdep.h"
/* If set, do a plausibility check on the scan_starts before and after
each collection */
static gboolean do_scan_starts_check = FALSE;
+static gboolean disable_minor_collections = FALSE;
+static gboolean disable_major_collections = FALSE;
#ifdef HEAVY_STATISTICS
static long long stat_objects_alloced = 0;
static void check_for_xdomain_refs (void);
static void dump_heap (const char *type, int num, const char *reason);
-void mono_gc_scan_for_specific_ref (MonoObject *key);
+void mono_gc_scan_for_specific_ref (MonoObject *key, gboolean precise);
static void init_stats (void);
o, o->vtable->klass->name_space, o->vtable->klass->name,
offset, field ? field->name : "",
ref, ref->vtable->klass->name_space, ref->vtable->klass->name, str ? str : "");
- mono_gc_scan_for_specific_ref (o);
+ mono_gc_scan_for_specific_ref (o, TRUE);
if (str)
g_free (str);
}
#include "sgen-scan-object.h"
}
+static gboolean scan_object_for_specific_ref_precise = TRUE;
+
#undef HANDLE_PTR
#define HANDLE_PTR(ptr,obj) do { \
if ((MonoObject*)*(ptr) == key) { \
if ((forwarded = SGEN_OBJECT_IS_FORWARDED (start)))
start = forwarded;
- #include "sgen-scan-object.h"
+ if (scan_object_for_specific_ref_precise) {
+ #include "sgen-scan-object.h"
+ } else {
+ mword *words = (mword*)start;
+ size_t size = safe_object_get_size ((MonoObject*)start);
+ int i;
+ for (i = 0; i < size / sizeof (mword); ++i) {
+ if (words [i] == (mword)key) {
+ g_print ("found possible ref to %p in object %p (%s) at offset %td\n",
+ key, start, safe_name (start), i * sizeof (mword));
+ }
+ }
+ }
}
void
}
void
-mono_gc_scan_for_specific_ref (MonoObject *key)
+mono_gc_scan_for_specific_ref (MonoObject *key, gboolean precise)
{
RootRecord *root;
int i;
+ scan_object_for_specific_ref_precise = precise;
+
mono_sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data,
(IterateObjectCallbackFunc)scan_object_for_specific_ref_callback, key, TRUE);
frag->next = NULL;
return frag;
}
+
+static void
+add_fragment (char *start, char *end)
+{
+ Fragment *fragment;
+
+ fragment = alloc_fragment ();
+ fragment->fragment_start = start;
+ fragment->fragment_limit = start;
+ fragment->fragment_end = end;
+ fragment->next = nursery_fragments;
+ nursery_fragments = fragment;
+}
/* size must be a power of 2 */
void*
GCMemSection *section;
char *data;
int scan_starts;
- Fragment *frag;
int alloc_size;
if (nursery_section)
nursery_start = data;
nursery_end = nursery_start + nursery_size;
mono_sgen_update_heap_boundaries ((mword)nursery_start, (mword)nursery_end);
- nursery_next = nursery_start;
DEBUG (4, fprintf (gc_debug_file, "Expanding nursery size (%p-%p): %lu, total: %lu\n", data, data + alloc_size, (unsigned long)nursery_size, (unsigned long)total_alloc));
section->data = section->next_data = data;
section->size = alloc_size;
nursery_section = section;
/* Setup the single first large fragment */
- frag = alloc_fragment ();
- frag->fragment_start = nursery_start;
- frag->fragment_limit = nursery_start;
- frag->fragment_end = nursery_end;
- nursery_frag_real_end = nursery_end;
- /* FIXME: frag here is lost */
+ add_fragment (nursery_start, nursery_end);
}
void*
static void
add_nursery_frag (size_t frag_size, char* frag_start, char* frag_end)
{
- Fragment *fragment;
DEBUG (4, fprintf (gc_debug_file, "Found empty fragment: %p-%p, size: %zd\n", frag_start, frag_end, frag_size));
binary_protocol_empty (frag_start, frag_size);
/* Not worth dealing with smaller fragments: need to tune */
if (nursery_clear_policy == CLEAR_AT_GC)
memset (frag_start, 0, frag_size);
- fragment = alloc_fragment ();
- fragment->fragment_start = frag_start;
- fragment->fragment_limit = frag_start;
- fragment->fragment_end = frag_end;
- fragment->next = nursery_fragments;
- nursery_fragments = fragment;
+ add_fragment (frag_start, frag_end);
fragment_total += frag_size;
} else {
/* Clear unused fragments, pinning depends on this */
scan_from_remsets (job_data->heap_start, job_data->heap_end, job_gray_queue (worker_data));
}
+typedef struct
+{
+ CopyOrMarkObjectFunc func;
+ char *heap_start;
+ char *heap_end;
+ int root_type;
+} ScanFromRegisteredRootsJobData;
+
+static void
+job_scan_from_registered_roots (WorkerData *worker_data, void *job_data_untyped)
+{
+ ScanFromRegisteredRootsJobData *job_data = job_data_untyped;
+
+ scan_from_registered_roots (job_data->func,
+ job_data->heap_start, job_data->heap_end,
+ job_data->root_type,
+ job_gray_queue (worker_data));
+}
+
+typedef struct
+{
+ char *heap_start;
+ char *heap_end;
+} ScanThreadDataJobData;
+
+static void
+job_scan_thread_data (WorkerData *worker_data, void *job_data_untyped)
+{
+ ScanThreadDataJobData *job_data = job_data_untyped;
+
+ scan_thread_data (job_data->heap_start, job_data->heap_end, TRUE,
+ job_gray_queue (worker_data));
+}
+
/*
* Collect objects in the nursery. Returns whether to trigger a major
* collection.
size_t max_garbage_amount;
char *orig_nursery_next;
ScanFromRemsetsJobData sfrjd;
+ ScanFromRegisteredRootsJobData scrrjd_normal, scrrjd_wbarrier;
+ ScanThreadDataJobData stdjd;
TV_DECLARE (all_atv);
TV_DECLARE (all_btv);
TV_DECLARE (atv);
TV_DECLARE (btv);
+ if (disable_minor_collections)
+ return TRUE;
+
mono_perfcounters->gc_collections0++;
current_collection_generation = GENERATION_NURSERY;
report_finalizer_roots ();
TV_GETTIME (atv);
time_minor_scan_pinned += TV_ELAPSED_MS (btv, atv);
+
/* registered roots, this includes static fields */
- scan_from_registered_roots (major_collector.copy_object, nursery_start, nursery_next, ROOT_TYPE_NORMAL, WORKERS_DISTRIBUTE_GRAY_QUEUE);
- scan_from_registered_roots (major_collector.copy_object, nursery_start, nursery_next, ROOT_TYPE_WBARRIER, WORKERS_DISTRIBUTE_GRAY_QUEUE);
+ scrrjd_normal.func = major_collector.copy_object;
+ scrrjd_normal.heap_start = nursery_start;
+ scrrjd_normal.heap_end = nursery_next;
+ scrrjd_normal.root_type = ROOT_TYPE_NORMAL;
+ workers_enqueue_job (workers_distribute_gray_queue.allocator, job_scan_from_registered_roots, &scrrjd_normal);
+
+ scrrjd_wbarrier.func = major_collector.copy_object;
+ scrrjd_wbarrier.heap_start = nursery_start;
+ scrrjd_wbarrier.heap_end = nursery_next;
+ scrrjd_wbarrier.root_type = ROOT_TYPE_WBARRIER;
+ workers_enqueue_job (workers_distribute_gray_queue.allocator, job_scan_from_registered_roots, &scrrjd_wbarrier);
+
TV_GETTIME (btv);
time_minor_scan_registered_roots += TV_ELAPSED_MS (atv, btv);
+
/* thread data */
- scan_thread_data (nursery_start, nursery_next, TRUE, WORKERS_DISTRIBUTE_GRAY_QUEUE);
+ stdjd.heap_start = nursery_start;
+ stdjd.heap_end = nursery_next;
+ workers_enqueue_job (workers_distribute_gray_queue.allocator, job_scan_thread_data, &stdjd);
+
TV_GETTIME (atv);
time_minor_scan_thread_data += TV_ELAPSED_MS (btv, atv);
btv = atv;
return needs_major;
}
-typedef struct
-{
- char *heap_start;
- char *heap_end;
- int root_type;
-} ScanFromRegisteredRootsJobData;
-
-static void
-job_scan_from_registered_roots (WorkerData *worker_data, void *job_data_untyped)
-{
- ScanFromRegisteredRootsJobData *job_data = job_data_untyped;
-
- scan_from_registered_roots (major_collector.copy_or_mark_object,
- job_data->heap_start, job_data->heap_end,
- job_data->root_type,
- job_gray_queue (worker_data));
-}
-
-typedef struct
-{
- char *heap_start;
- char *heap_end;
-} ScanThreadDataJobData;
-
-static void
-job_scan_thread_data (WorkerData *worker_data, void *job_data_untyped)
-{
- ScanThreadDataJobData *job_data = job_data_untyped;
-
- scan_thread_data (job_data->heap_start, job_data->heap_end, TRUE,
- job_gray_queue (worker_data));
-}
-
typedef struct
{
FinalizeEntry *list;
time_major_scan_pinned += TV_ELAPSED_MS (btv, atv);
/* registered roots, this includes static fields */
+ scrrjd_normal.func = major_collector.copy_or_mark_object;
scrrjd_normal.heap_start = heap_start;
scrrjd_normal.heap_end = heap_end;
scrrjd_normal.root_type = ROOT_TYPE_NORMAL;
workers_enqueue_job (workers_distribute_gray_queue.allocator, job_scan_from_registered_roots, &scrrjd_normal);
+ scrrjd_wbarrier.func = major_collector.copy_or_mark_object;
scrrjd_wbarrier.heap_start = heap_start;
scrrjd_wbarrier.heap_end = heap_end;
scrrjd_wbarrier.root_type = ROOT_TYPE_WBARRIER;
static void
major_collection (const char *reason)
{
- if (g_getenv ("MONO_GC_NO_MAJOR")) {
+ if (disable_major_collections) {
collect_nursery (0);
return;
}
* ######################################################################
*/
-/* FIXME: handle large/small config */
-#define HASH_PTHREAD_T(id) (((unsigned int)(id) >> 4) * 2654435761u)
-
-SgenThreadInfo* thread_table [THREAD_HASH_SIZE];
-
#if USE_SIGNAL_BASED_START_STOP_WORLD
static MonoSemType suspend_ack_semaphore;
static mword cur_thread_regs [ARCH_NUM_REGS] = {0};
#endif
-
-SgenThreadInfo*
-mono_sgen_thread_info_lookup (ARCH_THREAD_TYPE id)
-{
- unsigned int hash = HASH_PTHREAD_T (id) % THREAD_HASH_SIZE;
- SgenThreadInfo *info;
-
- info = thread_table [hash];
- while (info && !ARCH_THREAD_EQUALS (info->id, id)) {
- info = info->next;
- }
- return info;
-}
-
static void
update_current_thread_stack (void *start)
{
#ifndef USE_MONO_CTX
void *ptr = cur_thread_regs;
#endif
- SgenThreadInfo *info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
+ SgenThreadInfo *info = mono_thread_info_current ();
info->stack_start = align_pointer (&stack_guard);
g_assert (info->stack_start >= info->stack_start_limit && info->stack_start < info->stack_end);
void
mono_sgen_wait_for_suspend_ack (int count)
{
+#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
+ /* mach thread_resume is synchronous so we dont need to wait for them */
+#else
int i, result;
for (i = 0; i < count; ++i) {
}
}
}
+#endif
}
static int
restart_threads_until_none_in_managed_allocator (void)
{
SgenThreadInfo *info;
- int result, num_threads_died = 0;
+ int num_threads_died = 0;
int sleep_duration = -1;
for (;;) {
int restart_count = 0, restarted_count = 0;
/* restart all threads that stopped in the
allocator */
- FOREACH_THREAD (info) {
+ FOREACH_THREAD_SAFE (info) {
+ gboolean result;
if (info->skip)
continue;
if (!info->stack_start || info->in_critical_region ||
is_ip_in_managed_allocator (info->stopped_domain, info->stopped_ip)) {
- binary_protocol_thread_restart ((gpointer)info->id);
-#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
- result = thread_resume (pthread_mach_thread_np (info->id));
-#else
- result = pthread_kill (info->id, restart_signal_num);
-#endif
- if (result == 0) {
+ binary_protocol_thread_restart ((gpointer)mono_thread_info_get_tid (info));
+ result = mono_sgen_resume_thread (info);
+ if (result) {
++restart_count;
} else {
info->skip = 1;
info->stopped_ip = NULL;
info->stopped_domain = NULL;
}
- } END_FOREACH_THREAD
+ } END_FOREACH_THREAD_SAFE
/* if no threads were restarted, we're done */
if (restart_count == 0)
break;
-#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
- /* mach thread_resume is synchronous so we dont need to wait for them */
-#else
/* wait for the threads to signal their restart */
mono_sgen_wait_for_suspend_ack (restart_count);
-#endif
if (sleep_duration < 0) {
sched_yield ();
/* stop them again */
FOREACH_THREAD (info) {
+ gboolean result;
if (info->skip || info->stopped_ip == NULL)
continue;
-#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
- result = thread_suspend (pthread_mach_thread_np (info->id));
-#else
- result = pthread_kill (info->id, suspend_signal_num);
-#endif
- if (result == 0) {
+ result = mono_sgen_suspend_thread (info);
+
+ if (result) {
++restarted_count;
} else {
info->skip = 1;
} END_FOREACH_THREAD
/* some threads might have died */
num_threads_died += restart_count - restarted_count;
-#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
- /* mach thread_resume is synchronous so we dont need to wait for them */
-#else
/* wait for the threads to signal their suspension
again */
mono_sgen_wait_for_suspend_ack (restart_count);
-#endif
}
return num_threads_died;
suspend_handler (int sig, siginfo_t *siginfo, void *context)
{
SgenThreadInfo *info;
- pthread_t id;
int stop_count;
int old_errno = errno;
#ifdef USE_MONO_CTX
#endif
gpointer stack_start;
- id = pthread_self ();
- info = mono_sgen_thread_info_lookup (id);
+ info = mono_thread_info_current ();
info->stopped_domain = mono_domain_get ();
info->stopped_ip = (gpointer) ARCH_SIGCTX_IP (context);
stop_count = global_stop_count;
if (gc_callbacks.thread_suspend_func)
gc_callbacks.thread_suspend_func (info->runtime_data, context);
- DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)ARCH_GET_THREAD ()));
+ DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for suspend from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
/* notify the waiting thread */
MONO_SEM_POST (suspend_ack_semaphore_ptr);
info->stop_count = stop_count;
sigsuspend (&suspend_signal_mask);
} while (info->signal != restart_signal_num);
- DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)ARCH_GET_THREAD ()));
+ DEBUG (4, fprintf (gc_debug_file, "Posting suspend_ack_semaphore for resume from %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
/* notify the waiting thread */
MONO_SEM_POST (suspend_ack_semaphore_ptr);
SgenThreadInfo *info;
int old_errno = errno;
- info = mono_sgen_thread_info_lookup (pthread_self ());
+ info = mono_thread_info_current ();
info->signal = restart_signal_num;
- DEBUG (4, fprintf (gc_debug_file, "Restart handler in %p %p\n", info, (gpointer)ARCH_GET_THREAD ()));
+ DEBUG (4, fprintf (gc_debug_file, "Restart handler in %p %p\n", info, (gpointer)mono_native_thread_id_get ()));
errno = old_errno;
}
update_current_thread_stack (&count);
global_stop_count++;
- DEBUG (3, fprintf (gc_debug_file, "stopping world n %d from %p %p\n", global_stop_count, mono_sgen_thread_info_lookup (ARCH_GET_THREAD ()), (gpointer)ARCH_GET_THREAD ()));
+ DEBUG (3, fprintf (gc_debug_file, "stopping world n %d from %p %p\n", global_stop_count, mono_thread_info_current (), (gpointer)mono_native_thread_id_get ()));
TV_GETTIME (stop_world_time);
count = mono_sgen_thread_handshake (suspend_signal_num);
count -= restart_threads_until_none_in_managed_allocator ();
continue;
while (start < (char**)info->stack_end) {
if (*start >= obj && *start < endobj) {
- DEBUG (0, fprintf (gc_debug_file, "Object %p referenced in thread %p (id %p) at %p, stack: %p-%p\n", obj, info, (gpointer)info->id, start, info->stack_start, info->stack_end));
+ DEBUG (0, fprintf (gc_debug_file, "Object %p referenced in thread %p (id %p) at %p, stack: %p-%p\n", obj, info, (gpointer)mono_thread_info_get_tid (info), start, info->stack_start, info->stack_end));
}
start++;
}
#endif
if (w >= (mword)obj && w < (mword)obj + size)
- DEBUG (0, fprintf (gc_debug_file, "Object %p referenced in saved reg %d of thread %p (id %p)\n", obj, j, info, (gpointer)info->id));
+ DEBUG (0, fprintf (gc_debug_file, "Object %p referenced in saved reg %d of thread %p (id %p)\n", obj, j, info, (gpointer)mono_thread_info_get_tid (info)));
} END_FOREACH_THREAD
}
}
ptr_on_stack (void *ptr)
{
gpointer stack_start = &stack_start;
- SgenThreadInfo *info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
+ SgenThreadInfo *info = mono_thread_info_current ();
if (ptr >= stack_start && ptr < (gpointer)info->stack_end)
return TRUE;
} END_FOREACH_THREAD
}
-/* LOCKING: assumes the GC lock is held */
-static SgenThreadInfo*
-gc_register_current_thread (void *addr)
+static void*
+sgen_thread_register (SgenThreadInfo* info, void *addr)
{
- int hash;
- SgenThreadInfo* info = malloc (sizeof (SgenThreadInfo));
#ifndef HAVE_KW_THREAD
SgenThreadInfo *__thread_info__ = info;
#endif
- if (!info)
- return NULL;
-
- memset (info, 0, sizeof (SgenThreadInfo));
+ LOCK_GC;
#ifndef HAVE_KW_THREAD
info->tlab_start = info->tlab_next = info->tlab_temp_end = info->tlab_real_end = NULL;
thread_info = info;
#endif
- info->id = ARCH_GET_THREAD ();
info->stop_count = -1;
info->skip = 0;
info->signal = 0;
info->stopped_regs = NULL;
#endif
- binary_protocol_thread_register ((gpointer)info->id);
+ binary_protocol_thread_register ((gpointer)mono_thread_info_get_tid (info));
#ifdef HAVE_KW_THREAD
tlab_next_addr = &tlab_next;
store_remset_buffer_index_addr = &store_remset_buffer_index;
#endif
+#if defined(__MACH__)
+ info->mach_port = mach_thread_self ();
+#endif
+
/* try to get it with attributes first */
#if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
{
stack_end = info->stack_end;
#endif
- /* hash into the table */
- hash = HASH_PTHREAD_T (info->id) % THREAD_HASH_SIZE;
- info->next = thread_table [hash];
- thread_table [hash] = info;
-
info->remset = alloc_remset (DEFAULT_REMSET_SIZE, info);
pthread_setspecific (remembered_set_key, info->remset);
#ifdef HAVE_KW_THREAD
STORE_REMSET_BUFFER = mono_sgen_alloc_internal (INTERNAL_MEM_STORE_REMSET);
STORE_REMSET_BUFFER_INDEX = 0;
- DEBUG (3, fprintf (gc_debug_file, "registered thread %p (%p) (hash: %d)\n", info, (gpointer)info->id, hash));
+ DEBUG (3, fprintf (gc_debug_file, "registered thread %p (%p)\n", info, (gpointer)mono_thread_info_get_tid (info)));
if (gc_callbacks.thread_attach_func)
info->runtime_data = gc_callbacks.thread_attach_func ();
+ UNLOCK_GC;
return info;
}
}
static void
-unregister_current_thread (void)
+sgen_thread_unregister (SgenThreadInfo *p)
{
- int hash;
- SgenThreadInfo *prev = NULL;
- SgenThreadInfo *p;
RememberedSet *rset;
- ARCH_THREAD_TYPE id = ARCH_GET_THREAD ();
+
+ /* If a delegate is passed to native code and invoked on a thread we dont
+ * know about, the jit will register it with mono_jit_thread_attach, but
+ * we have no way of knowing when that thread goes away. SGen has a TSD
+ * so we assume that if the domain is still registered, we can detach
+ * the thread
+ */
+ if (mono_domain_get ())
+ mono_thread_detach (mono_thread_current ());
+
+ LOCK_GC;
binary_protocol_thread_unregister ((gpointer)id);
+ DEBUG (3, fprintf (gc_debug_file, "unregister thread %p (%p)\n", p, (gpointer)mono_thread_info_get_tid (p)));
- hash = HASH_PTHREAD_T (id) % THREAD_HASH_SIZE;
- p = thread_table [hash];
- assert (p);
- DEBUG (3, fprintf (gc_debug_file, "unregister thread %p (%p)\n", p, (gpointer)p->id));
- while (!ARCH_THREAD_EQUALS (p->id, id)) {
- prev = p;
- p = p->next;
- }
- if (prev == NULL) {
- thread_table [hash] = p->next;
- } else {
- prev->next = p->next;
- }
+#if defined(__MACH__)
+ mach_port_deallocate (current_task (), p->mach_port);
+#endif
if (gc_callbacks.thread_detach_func) {
gc_callbacks.thread_detach_func (p->runtime_data);
if (*p->store_remset_buffer_index_addr)
add_generic_store_remset_from_buffer (*p->store_remset_buffer_addr);
mono_sgen_free_internal (*p->store_remset_buffer_addr, INTERNAL_MEM_STORE_REMSET);
- free (p);
-}
-
-static void
-unregister_thread (void *k)
-{
- /* If a delegate is passed to native code and invoked on a thread we dont
- * know about, the jit will register it with mono_jit_thead_attach, but
- * we have no way of knowing when that thread goes away. SGen has a TSD
- * so we assume that if the domain is still registered, we can detach
- * the thread
- */
- if (mono_domain_get ())
- mono_thread_detach (mono_thread_current ());
-
- LOCK_GC;
- unregister_current_thread ();
UNLOCK_GC;
}
-gboolean
-mono_gc_register_thread (void *baseptr)
-{
- SgenThreadInfo *info;
+static void
+sgen_thread_attach (SgenThreadInfo *info)
+{
LOCK_GC;
+ /*this is odd, can we get attached before the gc is inited?*/
init_stats ();
- info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
- if (info == NULL) {
- info = gc_register_current_thread (baseptr);
- } else {
- /* The main thread might get registered before callbacks are set */
- if (gc_callbacks.thread_attach_func && !info->runtime_data)
- info->runtime_data = gc_callbacks.thread_attach_func ();
- }
UNLOCK_GC;
+
+ if (gc_callbacks.thread_attach_func && !info->runtime_data)
+ info->runtime_data = gc_callbacks.thread_attach_func ();
/* Need a better place to initialize this */
if (!array_fill_vtable && mono_get_root_domain ()) {
array_fill_vtable = mono_class_vtable (mono_get_root_domain (), mono_array_class_get (mono_defaults.byte_class, 1));
}
-
- return info != NULL;
+
+}
+gboolean
+mono_gc_register_thread (void *baseptr)
+{
+ return mono_thread_info_attach (baseptr) != NULL;
}
/*
SgenThreadInfo *info;
LOCK_GC;
- info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
+ info = mono_thread_info_current ();
if (info) {
g_assert (stack_end < info->stack_end);
info->stack_end = stack_end;
#if USE_PTHREAD_INTERCEPT
-typedef struct {
- void *(*start_routine) (void *);
- void *arg;
- int flags;
- MonoSemType registered;
-} SgenThreadStartInfo;
-
-static void*
-gc_start_thread (void *arg)
-{
- SgenThreadStartInfo *start_info = arg;
- SgenThreadInfo* info;
- void *t_arg = start_info->arg;
- void *(*start_func) (void*) = start_info->start_routine;
- void *result;
- int post_result;
-
- LOCK_GC;
- info = gc_register_current_thread (&result);
- UNLOCK_GC;
- post_result = MONO_SEM_POST (&(start_info->registered));
- g_assert (!post_result);
- result = start_func (t_arg);
- g_assert (!mono_domain_get ());
- /*
- * this is done by the pthread key dtor
- LOCK_GC;
- unregister_current_thread ();
- UNLOCK_GC;
- */
-
- return result;
-}
int
mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
{
- SgenThreadStartInfo *start_info;
- int result;
-
- start_info = malloc (sizeof (SgenThreadStartInfo));
- if (!start_info)
- return ENOMEM;
- MONO_SEM_INIT (&(start_info->registered), 0);
- start_info->arg = arg;
- start_info->start_routine = start_routine;
-
- result = pthread_create (new_thread, attr, gc_start_thread, start_info);
- if (result == 0) {
- while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
- /*if (EINTR != errno) ABORT("sem_wait failed"); */
- }
- }
- MONO_SEM_DESTROY (&(start_info->registered));
- free (start_info);
- return result;
+ return mono_threads_pthread_create (new_thread, attr, start_routine, arg);
}
int
rs->next = REMEMBERED_SET;
REMEMBERED_SET = rs;
#ifdef HAVE_KW_THREAD
- mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+ mono_thread_info_current ()->remset = rs;
#endif
*(rs->store_next++) = (mword)field_ptr;
*(void**)field_ptr = value;
rs->next = REMEMBERED_SET;
REMEMBERED_SET = rs;
#ifdef HAVE_KW_THREAD
- mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+ mono_thread_info_current ()->remset = rs;
#endif
*(rs->store_next++) = (mword)slot_ptr;
*(void**)slot_ptr = value;
rs->next = REMEMBERED_SET;
REMEMBERED_SET = rs;
#ifdef HAVE_KW_THREAD
- mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+ mono_thread_info_current ()->remset = rs;
#endif
*(rs->store_next++) = (mword)dest_ptr | REMSET_RANGE;
*(rs->store_next++) = count;
rs = alloc_remset (rs->end_set - rs->data, (void*)1);
rs->next = REMEMBERED_SET;
REMEMBERED_SET = rs;
-#ifdef HAVE_KW_THREAD
- mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
-#endif
+
+ mono_thread_info_current ()->remset = rs;
*(rs->store_next++) = (mword)dest | REMSET_VTYPE;
*(rs->store_next++) = (mword)klass->gc_descr;
*(rs->store_next++) = (mword)count;
rs = alloc_remset (rs->end_set - rs->data, (void*)1);
rs->next = REMEMBERED_SET;
REMEMBERED_SET = rs;
-#ifdef HAVE_KW_THREAD
- mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
-#endif
+
+ mono_thread_info_current ()->remset = rs;
+
*(rs->store_next++) = (mword)obj | REMSET_OBJECT;
UNLOCK_GC;
}
{
gsize *gc_bitmap;
void *descr;
+ int num_bytes = numbits / 8;
if (numbits < 32 && all_ref_root_descrs [numbits])
return all_ref_root_descrs [numbits];
- gc_bitmap = g_malloc0 (ALIGN_TO (numbits, 8) + 1);
- memset (gc_bitmap, 0xff, numbits / 8);
+ gc_bitmap = g_malloc0 (ALIGN_TO (ALIGN_TO (numbits, 8) + 1, sizeof (gsize)));
+ memset (gc_bitmap, 0xff, num_bytes);
+ if (numbits < ((sizeof (*gc_bitmap) * 8) - ROOT_DESC_TYPE_SHIFT))
+ gc_bitmap[0] = GUINT64_TO_LE(gc_bitmap[0]);
+ else if (numbits && num_bytes % (sizeof (*gc_bitmap)))
+ gc_bitmap[num_bytes / 8] = GUINT64_TO_LE(gc_bitmap [num_bytes / 8]);
if (numbits % 8)
gc_bitmap [numbits / 8] = (1 << (numbits % 8)) - 1;
descr = mono_gc_make_descr_from_bitmap (gc_bitmap, numbits);
{
gboolean result;
LOCK_GC;
- result = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ()) != NULL;
+ result = mono_thread_info_current () != NULL;
UNLOCK_GC;
return result;
}
void
mono_gc_base_init (void)
{
+ MonoThreadInfoCallbacks cb;
char *env;
char **opts, **ptr;
char *major_collector_opt = NULL;
pagesize = mono_pagesize ();
gc_debug_file = stdout;
+ cb.thread_register = sgen_thread_register;
+ cb.thread_unregister = sgen_thread_unregister;
+ cb.thread_attach = sgen_thread_attach;
+ mono_threads_init (&cb, sizeof (SgenThreadInfo));
+
LOCK_INIT (interruption_mutex);
LOCK_INIT (global_remset_mutex);
LOCK_INIT (pin_queue_mutex);
nursery_clear_policy = CLEAR_AT_GC;
} else if (!strcmp (opt, "check-scan-starts")) {
do_scan_starts_check = TRUE;
+ } else if (!strcmp (opt, "disable-minor")) {
+ disable_minor_collections = TRUE;
+ } else if (!strcmp (opt, "disable-major")) {
+ disable_major_collections = TRUE;
} else if (g_str_has_prefix (opt, "heap-dump=")) {
char *filename = strchr (opt, '=') + 1;
nursery_clear_policy = CLEAR_AT_GC;
} else {
fprintf (stderr, "Invalid format for the MONO_GC_DEBUG env variable: '%s'\n", env);
fprintf (stderr, "The format is: MONO_GC_DEBUG=[l[:filename]|<option>]+ where l is a debug level 0-9.\n");
- fprintf (stderr, "Valid options are: collect-before-allocs[=<n>], check-at-minor-collections, xdomain-checks, clear-at-gc.\n");
+ fprintf (stderr, "Valid options are:\n");
+ fprintf (stderr, " collect-before-allocs[=<n>]\n");
+ fprintf (stderr, " check-at-minor-collections\n");
+ fprintf (stderr, " disable-minor\n");
+ fprintf (stderr, " disable-major\n");
+ fprintf (stderr, " xdomain-checks\n");
+ fprintf (stderr, " clear-at-gc\n");
exit (1);
}
}
global_remset = alloc_remset (1024, NULL);
global_remset->next = NULL;
- pthread_key_create (&remembered_set_key, unregister_thread);
+ pthread_key_create (&remembered_set_key, NULL);
#ifndef HAVE_KW_THREAD
pthread_key_create (&thread_info_key, NULL);
gc_initialized = TRUE;
UNLOCK_GC;
- mono_gc_register_thread (&sinfo);
+ mono_thread_info_attach (&sinfo);
}
int