private IntPtr stack_ptr;
private UIntPtr static_data; /* GC-tracked */
private IntPtr jit_data;
- private IntPtr lock_data;
+ private IntPtr runtime_thread_info;
/* current System.Runtime.Remoting.Contexts.Context instance
keep as an object to avoid triggering its class constructor when not needed */
private object current_appcontext;
#include <mono/metadata/marshal.h>
#include <mono/utils/mono-logger-internal.h>
#include <mono/utils/mono-time.h>
+#include <mono/utils/mono-threads.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/gc_wrapper.h>
static gboolean gc_initialized = FALSE;
+static void*
+boehm_thread_register (MonoThreadInfo* info, void *baseptr);
+
static void
mono_gc_warning (char *msg, GC_word arg)
{
void
mono_gc_base_init (void)
{
+ MonoThreadInfoCallbacks cb;
char *env;
if (gc_initialized)
g_strfreev (opts);
}
+ memset (&cb, 0, sizeof (cb));
+ cb.thread_register = boehm_thread_register;
+ mono_threads_init (&cb, sizeof (MonoThreadInfo));
+
mono_gc_enable_events ();
gc_initialized = TRUE;
}
gboolean
mono_gc_register_thread (void *baseptr)
+{
+ return mono_thread_info_attach (baseptr) != NULL;
+}
+
+static void*
+boehm_thread_register (MonoThreadInfo* info, void *baseptr)
{
#if GC_VERSION_MAJOR >= 7
struct GC_stack_base sb;
res = GC_register_my_thread (&sb);
if ((res != GC_SUCCESS) && (res != GC_DUPLICATE)) {
g_warning ("GC_register_my_thread () failed.\n");
- return FALSE;
+ return NULL;
}
- return TRUE;
+ return info;
#else
if (mono_gc_is_gc_thread())
- return TRUE;
+ return info;
#if defined(USE_INCLUDED_LIBGC) && !defined(HOST_WIN32)
- return GC_thread_register_foreign (baseptr);
+ return GC_thread_register_foreign (baseptr) ? info : NULL;
#else
- return FALSE;
+ return NULL;
#endif
#endif
}
int
mono_gc_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
{
- return pthread_create (new_thread, attr, start_routine, arg);
+ return mono_threads_pthread_create (new_thread, attr, start_routine, arg);
}
int
gpointer stack_ptr;
gpointer *static_data;
gpointer jit_data;
- gpointer lock_data;
+ void *thread_info; /*This is MonoThreadInfo*, but to simplify dependencies, let's make it a void* here. */
MonoAppContext *current_appcontext;
int stack_size;
gpointer appdomain_refs;
MonoBoolean thread_interrupt_requested;
guint8 apartment_state;
gint32 critical_region_level;
- guint32 small_id; /* A small, unique id, used for the hazard pointer table. */
+ guint32 unused0;
MonoThreadManageCallback manage_callback;
MonoException *pending_exception;
MonoThread *root_domain_thread;
#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"
* ######################################################################
*/
-/* 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_current (void)
-{
-#ifdef HAVE_KW_THREAD
- return thread_info;
-#else
- return pthread_getspecific (thread_info_key);
-#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_current ();
+ 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);
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);
+ binary_protocol_thread_restart ((gpointer)mono_thread_info_get_tid (info));
result = mono_sgen_resume_thread (info);
if (result) {
++restart_count;
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;
#endif
gpointer stack_start;
- info = mono_sgen_thread_info_current ();
+ 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_current ();
+ 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_current (), (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_current ();
+ 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;
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 ();
- binary_protocol_thread_unregister ((gpointer)id);
+ /* 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 ());
- 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;
- }
+ 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)));
#if defined(__MACH__)
mach_port_deallocate (current_task (), p->mach_port);
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_current ();
- 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_current ();
+ 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_current ()->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_current ()->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_current ()->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_current ()->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_current ()->remset = rs;
-#endif
+
+ mono_thread_info_current ()->remset = rs;
+
*(rs->store_next++) = (mword)obj | REMSET_OBJECT;
UNLOCK_GC;
}
{
gboolean result;
LOCK_GC;
- result = mono_sgen_thread_info_current () != 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);
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
#ifdef HAVE_SGEN_GC
+typedef struct _SgenThreadInfo SgenThreadInfo;
+#define THREAD_INFO_TYPE SgenThreadInfo
+
#include <glib.h>
#include <pthread.h>
#include <signal.h>
#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-threads.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/object-internals.h>
#include <mono/metadata/sgen-archdep.h>
//#define SGEN_DEBUG_INTERNAL_ALLOC
-#define THREAD_HASH_SIZE 11
-
#define GC_BITS_PER_WORD (sizeof (mword) * 8)
-#define ARCH_THREAD_TYPE pthread_t
-#define ARCH_GET_THREAD pthread_self
-#define ARCH_THREAD_EQUALS(a,b) pthread_equal (a, b)
#if SIZEOF_VOID_P == 4
typedef guint32 mword;
#define SGEN_TV_ELAPSED(start,end) (int)((end-start) / 10)
#define SGEN_TV_ELAPSED_MS(start,end) ((SGEN_TV_ELAPSED((start),(end)) + 500) / 1000)
-/* LOCKING: assumes the GC lock is held */
-#define FOREACH_THREAD(thread) { \
- int __i; \
- for (__i = 0; __i < THREAD_HASH_SIZE; ++__i) \
- for ((thread) = thread_table [__i]; (thread); (thread) = (thread)->next) {
-
-#define END_FOREACH_THREAD }}
-
/* for use with write barriers */
typedef struct _RememberedSet RememberedSet;
struct _RememberedSet {
};
/* eventually share with MonoThread? */
-typedef struct _SgenThreadInfo SgenThreadInfo;
-
struct _SgenThreadInfo {
- SgenThreadInfo *next;
- ARCH_THREAD_TYPE id;
+ MonoThreadInfo info;
#if defined(__MACH__)
thread_port_t mach_port;
#endif
#endif
};
-extern SgenThreadInfo* thread_table [THREAD_HASH_SIZE] MONO_INTERNAL;
-
enum {
MEMORY_ROLE_GEN0,
MEMORY_ROLE_GEN1,
void mono_sgen_free_os_memory (void *addr, size_t size) MONO_INTERNAL;
int mono_sgen_thread_handshake (int signum) MONO_INTERNAL;
-SgenThreadInfo* mono_sgen_thread_info_lookup (ARCH_THREAD_TYPE id) MONO_INTERNAL;
-SgenThreadInfo* mono_sgen_thread_info_current (void) MONO_INTERNAL;
gboolean mono_sgen_suspend_thread (SgenThreadInfo *info) MONO_INTERNAL;
gboolean mono_sgen_resume_thread (SgenThreadInfo *info) MONO_INTERNAL;
#ifdef HAVE_SGEN_GC
#include "utils/mono-counters.h"
-#include "metadata/object-internals.h"
-#include "metadata/profiler-private.h"
#include "metadata/sgen-gc.h"
#include "metadata/sgen-protocol.h"
#include "metadata/mono-gc.h"
+#include "metadata/object-internals.h"
+#include "metadata/profiler-private.h"
#define MAJOR_SECTION_SIZE SGEN_PINNED_CHUNK_SIZE
#define BLOCK_FOR_OBJECT(o) SGEN_PINNED_CHUNK_FOR_PTR ((o))
#include "config.h"
#ifdef HAVE_SGEN_GC
+
+
#include <glib.h>
-#include "metadata/gc-internal.h"
#include "metadata/sgen-gc.h"
#include "metadata/sgen-archdep.h"
#include "metadata/object-internals.h"
+#include "metadata/gc-internal.h"
#if defined(__MACH__)
#include "utils/mach-support.h"
mono_mach_arch_thread_state_to_mcontext (state, mctx);
ctx.uc_mcontext = mctx;
- info->stopped_domain = mono_mach_arch_get_tls_value_from_thread ((pthread_t)info->id, mono_domain_get_tls_offset ());
+ info->stopped_domain = mono_mach_arch_get_tls_value_from_thread (
+ mono_thread_info_get_tid (info), mono_domain_get_tls_offset ());
info->stopped_ip = (gpointer) mono_mach_arch_get_ip (state);
stack_start = (char*) mono_mach_arch_get_sp (state) - REDZONE_SIZE;
/* If stack_start is not within the limits, then don't set it in info and we will be restarted. */
/* Notify the JIT */
if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
+
return TRUE;
}
int
mono_sgen_thread_handshake (int signum)
{
- SgenThreadInfo *cur_thread = mono_sgen_thread_info_current ();
+ SgenThreadInfo *cur_thread = mono_thread_info_current ();
kern_return_t ret;
-
SgenThreadInfo *info;
int count = 0;
- FOREACH_THREAD (info) {
- if (info == cur_thread || mono_sgen_is_worker_thread (info->id))
+ FOREACH_THREAD_SAFE (info) {
+ if (info == cur_thread || mono_sgen_is_worker_thread (mono_thread_info_get_tid (info)))
continue;
if (signum == suspend_signal_num) {
continue;
}
count ++;
- } END_FOREACH_THREAD
+ } END_FOREACH_THREAD_SAFE
return count;
}
#endif
#include "config.h"
#ifdef HAVE_SGEN_GC
#include <glib.h>
-#include "metadata/gc-internal.h"
#include "metadata/sgen-gc.h"
+#include "metadata/gc-internal.h"
#include "metadata/sgen-archdep.h"
#include "metadata/object-internals.h"
gboolean
mono_sgen_resume_thread (SgenThreadInfo *info)
{
- return pthread_kill (info->id, restart_signal_num) == 0;
+ return pthread_kill (mono_thread_info_get_tid (info), restart_signal_num) == 0;
}
gboolean
mono_sgen_suspend_thread (SgenThreadInfo *info)
{
- return pthread_kill (info->id, suspend_signal_num) == 0;
+ return pthread_kill (mono_thread_info_get_tid (info), suspend_signal_num) == 0;
}
int
{
int count, result;
SgenThreadInfo *info;
- pthread_t me = pthread_self ();
+
+ MonoNativeThreadId me = mono_native_thread_id_get ();
count = 0;
- FOREACH_THREAD (info) {
- if (ARCH_THREAD_EQUALS (info->id, me)) {
+ FOREACH_THREAD_SAFE (info) {
+ if (mono_native_thread_id_equals (mono_thread_info_get_tid (info), me)) {
continue;
}
/*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
continue;*/
- result = pthread_kill (info->id, signum);
+ result = pthread_kill (mono_thread_info_get_tid (info), signum);
if (result == 0) {
count++;
} else {
info->skip = 1;
}
- } END_FOREACH_THREAD
+ } END_FOREACH_THREAD_SAFE
mono_sgen_wait_for_suspend_ack (count);
#include <mono/utils/mono-mmap.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-time.h>
+#include <mono/utils/mono-threads.h>
#include <mono/utils/hazard-pointer.h>
#include <mono/metadata/gc-internal.h>
if (mono_thread_cleanup_fn)
mono_thread_cleanup_fn (thread);
- mono_thread_small_id_free (thread->small_id);
MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
- thread->small_id = -2;
}
static gpointer
static guint32 WINAPI start_wrapper_internal(void *data)
{
+ MonoThreadInfo *info;
struct StartInfo *start_info=(struct StartInfo *)data;
guint32 (*start_func)(void *);
void *start_arg;
* thread resumed
*/
+ info = mono_thread_info_current ();
+ g_assert (info);
+ internal->thread_info = info;
+
+
tid=internal->tid;
SET_CURRENT_OBJECT (internal);
internal->handle=thread_handle;
internal->tid=tid;
internal->apartment_state=ThreadApartmentState_Unknown;
- internal->small_id = mono_thread_small_id_alloc ();
internal->thread_pinning_ref = internal;
MONO_GC_REGISTER_ROOT (internal->thread_pinning_ref);
thread->android_tid = (gpointer) gettid ();
#endif
thread->apartment_state=ThreadApartmentState_Unknown;
- thread->small_id = mono_thread_small_id_alloc ();
thread->thread_pinning_ref = thread;
MONO_GC_REGISTER_ROOT (thread->thread_pinning_ref);
return NULL;
}
- internal->small_id = -1;
-
if ((internal->state & ThreadState_Aborted) != 0) {
LeaveCriticalSection (internal->synch_cs);
return this;
internal->handle=thread;
internal->tid=tid;
- internal->small_id = mono_thread_small_id_alloc ();
internal->thread_pinning_ref = internal;
MONO_GC_REGISTER_ROOT (internal->thread_pinning_ref);
hazard-pointer.c \
hazard-pointer.h \
mono-linked-list-set.c \
- mono-linked-list-set.h
+ mono-linked-list-set.h \
+ mono-threads.c \
+ mono-threads.h
arch_sources =
#include <config.h>
-#include <mono/metadata/object-internals.h>
+#include <mono/metadata/class-internals.h>
#include <mono/utils/hazard-pointer.h>
+#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-mmap.h>
#include <mono/utils/monobitset.h>
+#include <mono/utils/mono-threads.h>
#include <mono/io-layer/io-layer.h>
typedef struct {
MonoThreadHazardPointers*
mono_hazard_pointer_get (void)
{
- MonoInternalThread *current_thread = mono_thread_internal_current ();
+ MonoThreadInfo *current_thread = mono_thread_info_current ();
if (!(current_thread && current_thread->small_id >= 0)) {
static MonoThreadHazardPointers emerg_hazard_table;
return &hazard_table [current_thread->small_id];
}
+MonoThreadHazardPointers*
+mono_hazard_pointer_get_by_id (int small_id)
+{
+ g_assert (small_id >= 0 && small_id <= highest_small_id);
+ return &hazard_table [small_id];
+}
+
/* Can be called with hp==NULL, in which case it acts as an ordinary
pointer fetch. It's used that way indirectly from
mono_jit_info_table_add(), which doesn't have to care about hazards
#include <glib.h>
#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-membar.h>
#define HAZARD_POINTER_COUNT 3
void mono_thread_hazardous_try_free_all (void) MONO_INTERNAL;
MonoThreadHazardPointers* mono_hazard_pointer_get (void) MONO_INTERNAL;
gpointer get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index) MONO_INTERNAL;
+MonoThreadHazardPointers* mono_hazard_pointer_get_by_id (int small_id) MONO_INTERNAL;
#define mono_hazard_pointer_set(hp,i,v) \
do { g_assert ((i) >= 0 && (i) < HAZARD_POINTER_COUNT); \
--- /dev/null
+/*
+ * mono-threads.c: Low-level threading
+ *
+ * Author:
+ * Rodrigo Kumpera (kumpera@gmail.com)
+ *
+ * (C) 2011 Novell, Inc
+ */
+
+#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-semaphore.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/hazard-pointer.h>
+#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/appdomain.h>
+
+#include <pthread.h>
+#include <errno.h>
+
+
+#define THREADS_DEBUG(...)
+//#define THREADS_DEBUG(...) g_message(__VA_ARGS__)
+
+typedef struct {
+ void *(*start_routine) (void *);
+ void *arg;
+ int flags;
+ MonoSemType registered;
+} ThreadStartInfo;
+
+static int thread_info_size;
+static MonoThreadInfoCallbacks threads_callbacks;
+static pthread_key_t thread_info_key;
+static MonoLinkedListSet thread_list;
+
+static inline void
+mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
+{
+ if (retain != 0)
+ mono_hazard_pointer_clear (hp, 0);
+ if (retain != 1)
+ mono_hazard_pointer_clear (hp, 1);
+ if (retain != 2)
+ mono_hazard_pointer_clear (hp, 2);
+}
+
+static gboolean
+mono_thread_info_insert (MonoThreadInfo *info)
+{
+ MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+
+ if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
+ mono_hazard_pointer_clear_all (hp, -1);
+ return FALSE;
+ }
+
+ mono_hazard_pointer_clear_all (hp, -1);
+ return TRUE;
+}
+
+static gboolean
+mono_thread_info_remove (MonoThreadInfo *info)
+{
+ /*TLS is gone by now, so we can't rely on it to retrieve hp*/
+ MonoThreadHazardPointers *hp = mono_hazard_pointer_get_by_id (info->small_id);
+ THREADS_DEBUG ("removing info %p\n", info);
+ gboolean res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
+ mono_hazard_pointer_clear_all (hp, -1);
+ return res;
+}
+
+static void
+free_thread_info (gpointer mem)
+{
+ MonoThreadInfo *info = mem;
+
+ g_free (info);
+}
+
+static void*
+register_thread (MonoThreadInfo *info, gpointer baseptr)
+{
+ gboolean result;
+ mono_thread_info_set_tid (info, mono_native_thread_id_get ());
+ info->small_id = mono_thread_small_id_alloc ();
+
+ THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
+
+ if (threads_callbacks.thread_register) {
+ if (threads_callbacks.thread_register (info, baseptr) == NULL) {
+ g_warning ("thread registation failed\n");
+ g_free (info);
+ return NULL;
+ }
+ }
+
+ pthread_setspecific (thread_info_key, info);
+
+ /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
+ result = mono_thread_info_insert (info);
+ g_assert (result);
+ return info;
+}
+
+static void
+unregister_thread (void *arg)
+{
+ gboolean result;
+ MonoThreadInfo *info = arg;
+ int small_id = info->small_id;
+ g_assert (info);
+
+ THREADS_DEBUG ("unregistering info %p\n", info);
+
+ if (threads_callbacks.thread_unregister)
+ threads_callbacks.thread_unregister (info);
+
+ result = mono_thread_info_remove (info);
+ g_assert (result);
+
+ mono_thread_small_id_free (small_id);
+}
+
+static void*
+inner_start_thread (void *arg)
+{
+ ThreadStartInfo *start_info = arg;
+ MonoThreadInfo* info;
+ void *t_arg = start_info->arg;
+ void *(*start_func) (void*) = start_info->start_routine;
+ void *result;
+ int post_result;
+
+ info = g_malloc0 (thread_info_size);
+
+ register_thread (info, &post_result);
+
+ post_result = MONO_SEM_POST (&(start_info->registered));
+ g_assert (!post_result);
+
+ result = start_func (t_arg);
+ g_assert (!mono_domain_get ());
+
+ return result;
+}
+
+MonoThreadInfo*
+mono_thread_info_current (void)
+{
+ return pthread_getspecific (thread_info_key);
+}
+
+MonoLinkedListSet*
+mono_thread_info_list_head (void)
+{
+ return &thread_list;
+}
+
+MonoThreadInfo*
+mono_thread_info_attach (void *baseptr)
+{
+ MonoThreadInfo *info = pthread_getspecific (thread_info_key);
+ if (!info) {
+ info = g_malloc0 (thread_info_size);
+ if (!register_thread (info, baseptr))
+ return NULL;
+ } else if (threads_callbacks.thread_attach) {
+ threads_callbacks.thread_attach (info);
+ }
+ return info;
+}
+
+void
+mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
+{
+ threads_callbacks = *callbacks;
+ thread_info_size = info_size;
+ pthread_key_create (&thread_info_key, unregister_thread);
+ mono_lls_init (&thread_list, free_thread_info);
+ mono_thread_smr_init ();
+ g_assert (sizeof (MonoNativeThreadId) == sizeof (uintptr_t));
+}
+
+int
+mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
+{
+ ThreadStartInfo *start_info;
+ int result;
+
+ start_info = g_malloc0 (sizeof (ThreadStartInfo));
+ 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, inner_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));
+ g_free (start_info);
+ return result;
+}
--- /dev/null
+/*
+ * mono-threads.h: Low-level threading
+ *
+ * Author:
+ * Rodrigo Kumpera (kumpera@gmail.com)
+ *
+ * (C) 2011 Novell, Inc
+ */
+
+#ifndef __MONO_THREADS_H__
+#define __MONO_THREADS_H__
+
+#include <mono/utils/mono-semaphore.h>
+#include <mono/utils/mono-stack-unwinding.h>
+#include <mono/utils/mono-linked-list-set.h>
+
+#include <pthread.h>
+#include <glib.h>
+
+#if defined(__MACH__)
+#include <mono/utils/mach-support.h>
+#endif
+
+typedef pthread_t MonoNativeThreadId;
+
+#define mono_native_thread_id_get pthread_self
+#define mono_native_thread_id_equals pthread_equal
+
+#ifndef THREAD_INFO_TYPE
+#define THREAD_INFO_TYPE MonoThreadInfo
+#endif
+
+typedef struct {
+ MonoLinkedListSetNode node;
+ guint32 small_id; /*Used by hazard pointers */
+} MonoThreadInfo;
+
+typedef struct {
+ void* (*thread_register)(THREAD_INFO_TYPE *info, void *baseaddr);
+ void (*thread_unregister)(THREAD_INFO_TYPE *info);
+ void (*thread_attach)(THREAD_INFO_TYPE *info);
+} MonoThreadInfoCallbacks;
+
+/*
+Requires the world to be stoped
+*/
+#define FOREACH_THREAD(thread) MONO_LLS_FOREACH (mono_thread_info_list_head (), thread)
+#define END_FOREACH_THREAD MONO_LLS_END_FOREACH
+
+/*
+Snapshot iteration.
+*/
+#define FOREACH_THREAD_SAFE(thread) MONO_LLS_FOREACH_SAFE (mono_thread_info_list_head (), thread)
+#define END_FOREACH_THREAD_SAFE MONO_LLS_END_FOREACH_SAFE
+
+#define mono_thread_info_get_tid(info) ((MonoNativeThreadId)((MonoThreadInfo*)info)->node.key)
+#define mono_thread_info_set_tid(info, val) do { ((MonoThreadInfo*)(info))->node.key = (uintptr_t)(val); } while (0)
+
+/*
+ * @thread_info_size is sizeof (GcThreadInfo), a struct the GC defines to make it possible to have
+ * a single block with info from both camps.
+ */
+void
+mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t thread_info_size) MONO_INTERNAL;
+
+int
+mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) MONO_INTERNAL;
+
+THREAD_INFO_TYPE *
+mono_thread_info_attach (void *baseptr) MONO_INTERNAL;
+
+THREAD_INFO_TYPE *
+mono_thread_info_current (void) MONO_INTERNAL;
+
+MonoLinkedListSet*
+mono_thread_info_list_head (void) MONO_INTERNAL;
+
+MonoThreadInfo*
+mono_thread_info_lookup (MonoNativeThreadId id) MONO_INTERNAL;
+
+#endif /* __MONO_THREADS_H__ */