Move thread management from sgen to utils. Move smr from MonoInternalThread to thread...
authorRodrigo Kumpera <kumpera@gmail.com>
Wed, 6 Apr 2011 03:24:04 +0000 (00:24 -0300)
committerRodrigo Kumpera <kumpera@gmail.com>
Fri, 8 Apr 2011 00:12:10 +0000 (21:12 -0300)
* mono-threads.c: An implementation of low level thread management that
fits what sgen needs. It uses hazard pointers to manage the thread list
since we can't protect it with the GC lock as this would cause boehm to
deadlock. This requires us to move small_id one layer down.

* Thread.cs:
* object-internals.h:
* threads.c: Small id is now stored on MonoThreadInfo so it can be
used by lower layers of the runtime such as sgen.

* sgen-major-copying.c:
* sgen-os-mach.c:
* sgen-os-posix.c:
* sgen-gc.h:
* sgen-gc.c: Replace sgen's thread management code with
the new one.

* boehm-gc.c: Hookup the new thread management code. Boehm's
own management code is not been replaced as I'm too much of
a coward to mess with it.

* hazard-pointer.c: Adjust to the new location of small_id.

14 files changed:
mcs/class/corlib/System.Threading/Thread.cs
mono/metadata/boehm-gc.c
mono/metadata/object-internals.h
mono/metadata/sgen-gc.c
mono/metadata/sgen-gc.h
mono/metadata/sgen-major-copying.c
mono/metadata/sgen-os-mach.c
mono/metadata/sgen-os-posix.c
mono/metadata/threads.c
mono/utils/Makefile.am
mono/utils/hazard-pointer.c
mono/utils/hazard-pointer.h
mono/utils/mono-threads.c [new file with mode: 0644]
mono/utils/mono-threads.h [new file with mode: 0644]

index e7fa1e186df31bd3ce37d1ecb4f964fca3cf4a11..7d0f5dad9a314d110f3d93ca74e8e31876e5aaf8 100644 (file)
@@ -70,7 +70,7 @@ namespace System.Threading {
                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;
index 01a947f118fc5e0224ae781cb7bf756175317fae..d4034190639a1b47648c03b269e8c82d70f55a3a 100644 (file)
@@ -22,6 +22,7 @@
 #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>
 
@@ -41,6 +42,9 @@
 
 static gboolean gc_initialized = FALSE;
 
+static void*
+boehm_thread_register (MonoThreadInfo* info, void *baseptr);
+
 static void
 mono_gc_warning (char *msg, GC_word arg)
 {
@@ -50,6 +54,7 @@ mono_gc_warning (char *msg, GC_word arg)
 void
 mono_gc_base_init (void)
 {
+       MonoThreadInfoCallbacks cb;
        char *env;
 
        if (gc_initialized)
@@ -164,6 +169,10 @@ mono_gc_base_init (void)
                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;
 }
@@ -320,6 +329,12 @@ extern int GC_thread_register_foreign (void *base_addr);
 
 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;
@@ -336,16 +351,16 @@ mono_gc_register_thread (void *baseptr)
        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
 }
@@ -1171,7 +1186,7 @@ mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
 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
index 1c3a0ae6da57e5cebf46fc902fd5115dd05808a7..cfeb119b15c529776b039de7911841156a8971aa 100644 (file)
@@ -383,7 +383,7 @@ struct _MonoInternalThread {
        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;
@@ -398,7 +398,7 @@ struct _MonoInternalThread {
        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;
index 311b5d5c2d24d8c5ba06d7885e9ca8068b224a5e..f0a263fe0a436db4c8993cf56aee3a4603d03c98 100644 (file)
 #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"
@@ -5136,11 +5137,6 @@ mono_gc_deregister_root (char* addr)
  * ######################################################################
  */
 
-/* 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;
@@ -5155,29 +5151,6 @@ static MonoContext cur_thread_ctx = {0};
 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)
 {
@@ -5185,7 +5158,7 @@ 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);
@@ -5247,14 +5220,13 @@ restart_threads_until_none_in_managed_allocator (void)
                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;
@@ -5270,7 +5242,7 @@ restart_threads_until_none_in_managed_allocator (void)
                                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;
@@ -5323,7 +5295,7 @@ suspend_handler (int sig, siginfo_t *siginfo, void *context)
 #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;
@@ -5357,7 +5329,7 @@ suspend_handler (int sig, siginfo_t *siginfo, void *context)
        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;
@@ -5368,7 +5340,7 @@ suspend_handler (int sig, siginfo_t *siginfo, void *context)
                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);
 
@@ -5381,9 +5353,9 @@ restart_handler (int sig)
        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;
 }
@@ -5415,7 +5387,7 @@ stop_world (int generation)
        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 ();
@@ -5554,7 +5526,7 @@ find_pinning_ref_from_thread (char *obj, size_t size)
                        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++;
                }
@@ -5567,7 +5539,7 @@ find_pinning_ref_from_thread (char *obj, size_t size)
 #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
        }
 }
@@ -5576,7 +5548,7 @@ static gboolean
 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;
@@ -5927,20 +5899,14 @@ clear_tlabs (void)
        } 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;
 
@@ -5950,7 +5916,6 @@ gc_register_current_thread (void *addr)
        thread_info = info;
 #endif
 
-       info->id = ARCH_GET_THREAD ();
        info->stop_count = -1;
        info->skip = 0;
        info->signal = 0;
@@ -5969,7 +5934,7 @@ gc_register_current_thread (void *addr)
        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;
@@ -6009,11 +5974,6 @@ gc_register_current_thread (void *addr)
        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
@@ -6023,11 +5983,12 @@ gc_register_current_thread (void *addr)
        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;
 }
 
@@ -6041,29 +6002,23 @@ add_generic_store_remset_from_buffer (gpointer *buffer)
 }
 
 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);
@@ -6087,49 +6042,31 @@ unregister_current_thread (void)
        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;
 }
 
 /*
@@ -6144,7 +6081,7 @@ mono_gc_set_stack_end (void *stack_end)
        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;
@@ -6154,62 +6091,11 @@ mono_gc_set_stack_end (void *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
@@ -6298,7 +6184,7 @@ mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* val
                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;
@@ -6336,7 +6222,7 @@ mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* va
                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;
@@ -6399,7 +6285,7 @@ mono_gc_wbarrier_arrayref_copy (gpointer dest_ptr, gpointer src_ptr, int count)
                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;
@@ -6588,9 +6474,8 @@ mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *
                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;
@@ -6630,9 +6515,9 @@ mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
        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;
 }
@@ -7240,7 +7125,7 @@ mono_gc_is_gc_thread (void)
 {
        gboolean result;
        LOCK_GC;
-        result = mono_sgen_thread_info_current () != NULL;
+       result = mono_thread_info_current () != NULL;
        UNLOCK_GC;
        return result;
 }
@@ -7248,6 +7133,7 @@ mono_gc_is_gc_thread (void)
 void
 mono_gc_base_init (void)
 {
+       MonoThreadInfoCallbacks cb;
        char *env;
        char **opts, **ptr;
        char *major_collector_opt = NULL;
@@ -7268,6 +7154,11 @@ mono_gc_base_init (void)
        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);
@@ -7529,7 +7420,7 @@ mono_gc_base_init (void)
        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);
@@ -7540,7 +7431,7 @@ mono_gc_base_init (void)
 
        gc_initialized = TRUE;
        UNLOCK_GC;
-       mono_gc_register_thread (&sinfo);
+       mono_thread_info_attach (&sinfo);
 }
 
 int
index c5a79c4f9cf73c6720bdf47f4820c1c884b62d88..8af465059c697bf0a2f10b619cfe72a9c82b44ff 100644 (file)
 
 #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;
@@ -79,14 +78,6 @@ typedef guint64 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 {
@@ -97,11 +88,8 @@ 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
@@ -147,8 +135,6 @@ struct _SgenThreadInfo {
 #endif
 };
 
-extern SgenThreadInfo* thread_table [THREAD_HASH_SIZE] MONO_INTERNAL;
-
 enum {
        MEMORY_ROLE_GEN0,
        MEMORY_ROLE_GEN1,
@@ -612,8 +598,6 @@ void* mono_sgen_alloc_os_memory_aligned (mword size, mword alignment, gboolean a
 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;
 
index ce007aa8e39f2cabef9fb46df5775683cfe9c8b5..15bfb44afb025c685d5f14c3b4fef12d634fd52c 100644 (file)
 #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))
index 05e226590c9bc94d05a1870c8bee0c1e7246e7e5..2aaa25532137ee33f36b9a5ab9e24fc7d13df892 100644 (file)
 
 #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"
@@ -72,7 +74,8 @@ mono_sgen_suspend_thread (SgenThreadInfo *info)
        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. */
@@ -93,6 +96,7 @@ mono_sgen_suspend_thread (SgenThreadInfo *info)
        /* 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;
 }
 
@@ -100,15 +104,14 @@ mono_sgen_suspend_thread (SgenThreadInfo *info)
 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) {
@@ -120,7 +123,7 @@ mono_sgen_thread_handshake (int signum)
                                continue;
                }
                count ++;
-       } END_FOREACH_THREAD
+       } END_FOREACH_THREAD_SAFE
        return count;
 }
 #endif
index e247b9c91c48030fbe5e91419fe2e61c6530b982..2c42fe26cac6a7aa7f8728562194896b0b688f60 100644 (file)
@@ -31,8 +31,8 @@
 #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
@@ -54,22 +54,23 @@ mono_sgen_thread_handshake (int signum)
 {
        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);
 
index a7a721dca8509d2a6670cdacf482e8e3c4493948..7afc1ec59fc6c53a2fc20a820c25933fec308cd9 100644 (file)
@@ -42,6 +42,7 @@
 #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>
@@ -375,9 +376,7 @@ static void thread_cleanup (MonoInternalThread *thread)
        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
@@ -458,6 +457,7 @@ init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
 
 static guint32 WINAPI start_wrapper_internal(void *data)
 {
+       MonoThreadInfo *info;
        struct StartInfo *start_info=(struct StartInfo *)data;
        guint32 (*start_func)(void *);
        void *start_arg;
@@ -478,6 +478,11 @@ static guint32 WINAPI start_wrapper_internal(void *data)
         * thread resumed
         */
 
+       info = mono_thread_info_current ();
+       g_assert (info);
+       internal->thread_info = info;
+
+
        tid=internal->tid;
 
        SET_CURRENT_OBJECT (internal);
@@ -712,7 +717,6 @@ MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer fu
        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);
 
@@ -836,7 +840,6 @@ mono_thread_attach (MonoDomain *domain)
        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);
 
@@ -958,8 +961,6 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
                return NULL;
        }
 
-       internal->small_id = -1;
-
        if ((internal->state & ThreadState_Aborted) != 0) {
                LeaveCriticalSection (internal->synch_cs);
                return this;
@@ -1004,7 +1005,6 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *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);
                
index 82fd609a916df2d8ac96dd071d47f555e1921f94..0b81c6ed99ac7e329a8e148a880892bea0e29973 100644 (file)
@@ -85,7 +85,9 @@ monoutils_sources = \
        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 = 
 
index 4f1e63e1e592dfc6cdaca2afcbf2d1e4db72dc05..f0cf3e1575d32d7fc9584fc6b1b99dc38d982c49 100644 (file)
@@ -6,10 +6,12 @@
 
 #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 {
@@ -149,7 +151,7 @@ is_pointer_hazardous (gpointer p)
 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;
@@ -160,6 +162,13 @@ mono_hazard_pointer_get (void)
        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
index 1486a0193c4df0729bfb1f35d50e160d14ed162c..6b841faa901d03516d786c4c5822d45a3fb715ca 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <glib.h>
 #include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-membar.h>
 
 #define HAZARD_POINTER_COUNT 3
 
@@ -21,6 +22,7 @@ void mono_thread_hazardous_free_or_queue (gpointer p, MonoHazardousFreeFunc free
 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); \
diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c
new file mode 100644 (file)
index 0000000..23f3e42
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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;
+}
diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h
new file mode 100644 (file)
index 0000000..609d011
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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__ */