2010-06-22 Geoff Norton <gnorton@novell.com>
authorGeoff Norton <grompf@sublimeintervention.com>
Tue, 22 Jun 2010 14:58:55 +0000 (14:58 -0000)
committerGeoff Norton <grompf@sublimeintervention.com>
Tue, 22 Jun 2010 14:58:55 +0000 (14:58 -0000)
        * domain.c: Allow gettings the tls key, since we need it for
        cross thread tls poking in sgen-mach
        * sgen-gc.(c|h), gc-internal.h: Rework sgen into having some functions
        in external files for platform specific STW support.
        * sgen-os-mach.c: Add a new mach kernel backend implementation of STW.
        * sgen-os-posix.c: Move the existing posix signal based STW here.

svn path=/trunk/mono/; revision=159349

mono/metadata/ChangeLog
mono/metadata/Makefile.am
mono/metadata/domain.c
mono/metadata/gc-internal.h
mono/metadata/sgen-gc.c
mono/metadata/sgen-gc.h
mono/metadata/sgen-os-mach.c [new file with mode: 0644]
mono/metadata/sgen-os-posix.c [new file with mode: 0644]

index 7e7be059e7843b328236665f79e2e7dd4b5f1227..3c9007f0c3ce7818010b4351993fa8c91815c5dd 100644 (file)
@@ -1,3 +1,12 @@
+2010-06-22  Geoff Norton  <gnorton@novell.com>
+
+       * domain.c: Allow gettings the tls key, since we need it for
+       cross thread tls poking in sgen-mach
+       * sgen-gc.(c|h), gc-internal.h: Rework sgen into having some functions
+       in external files for platform specific STW support.
+       * sgen-os-mach.c: Add a new mach kernel backend implementation of STW.
+       * sgen-os-posix.c: Move the existing posix signal based STW here.
+
 2010-06-21  Zoltan Varga  <vargaz@gmail.com>
 
        * marshal.c (mono_array_to_lparray): Allow MONO_TYPE_PTR. Fixes #615952.
index aef0b0570c3091d6f1dc113c8812380aa4cfa95f..b073671b7b279fe607753ff1e996628cb033b5e3 100644 (file)
@@ -156,6 +156,8 @@ libmonoruntime_la_SOURCES = \
        security-core-clr.h     \
        security-manager.c      \
        security-manager.h      \
+       sgen-os-posix.c         \
+       sgen-os-mach.c          \
        sgen-gc.c               \
        sgen-gc.h               \
        sgen-archdep.h          \
index 4629b351b84882113a15fdcbf13ef51c8cb1e042..26f75788907f09e772b356d007c186c04a6133ee 100644 (file)
@@ -158,12 +158,7 @@ mono_jit_info_find_aot_module (guint8* addr);
 guint32
 mono_domain_get_tls_key (void)
 {
-#ifdef NO_TLS_SET_VALUE
-       g_assert_not_reached ();
-       return 0;
-#else
        return appdomain_thread_id;
-#endif
 }
 
 gint32
index c6e9a0bd16714bafba340a3c22413d4b5ae19219..b2be0a861ba0d7c227342603000ea24a48ce84a8 100644 (file)
@@ -207,6 +207,7 @@ typedef struct {
 
 /* Set the callback functions callable by the GC */
 void mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks) MONO_INTERNAL;
+MonoGCCallbacks *mono_gc_get_gc_callbacks (void) MONO_INTERNAL;
 
 /* Functions callable from the thread mark func */
 
index 5e5f1ba20790d06da8c088fcbad5dfebba787c9a..7a95f8f6dfd446e4f424724edc3d41a78a95756d 100644 (file)
 
 #include <mono/utils/memcheck.h>
 
+#if defined(__MACH__)
+#include "utils/mach-support.h"
+#endif
+
 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
        a = i,
 
@@ -223,11 +227,6 @@ enum {
  * ########  Types and constants used by the GC.
  * ######################################################################
  */
-#if SIZEOF_VOID_P == 4
-typedef guint32 mword;
-#else
-typedef guint64 mword;
-#endif
 
 static int gc_initialized = 0;
 static int gc_debug_level = 0;
@@ -357,9 +356,6 @@ mono_gc_flush_info (void)
 }
 */
 
-#define MAX_DEBUG_LEVEL 2
-#define DEBUG(level,a) do {if (G_UNLIKELY ((level) <= MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) a;} while (0)
-
 /* Define this to allow the user to change some of the constants by specifying
  * their values in the MONO_GC_PARAMS environmental variable. See
  * mono_gc_base_init for details. */
@@ -508,15 +504,6 @@ struct _RootRecord {
        mword root_desc;
 };
 
-/* for use with write barriers */
-typedef struct _RememberedSet RememberedSet;
-struct _RememberedSet {
-       mword *store_next;
-       mword *end_set;
-       RememberedSet *next;
-       mword data [MONO_ZERO_LEN_ARRAY];
-};
-
 /*
  * We're never actually using the first element.  It's always set to
  * NULL to simplify the elimination of consecutive duplicate
@@ -831,40 +818,6 @@ static int num_roots_entries [ROOT_TYPE_NUM] = { 0, 0, 0 };
  */
 static char *nursery_start = NULL;
 
-/* eventually share with MonoThread? */
-typedef struct _SgenThreadInfo SgenThreadInfo;
-
-struct _SgenThreadInfo {
-       SgenThreadInfo *next;
-       ARCH_THREAD_TYPE id;
-       unsigned int stop_count; /* to catch duplicate signals */
-       int signal;
-       int skip;
-       volatile int in_critical_region;
-       void *stack_end;
-       void *stack_start;
-       void *stack_start_limit;
-       char **tlab_next_addr;
-       char **tlab_start_addr;
-       char **tlab_temp_end_addr;
-       char **tlab_real_end_addr;
-       gpointer **store_remset_buffer_addr;
-       long *store_remset_buffer_index_addr;
-       RememberedSet *remset;
-       gpointer runtime_data;
-       gpointer stopped_ip;    /* only valid if the thread is stopped */
-       MonoDomain *stopped_domain; /* ditto */
-       gpointer *stopped_regs;     /* ditto */
-#ifndef HAVE_KW_THREAD
-       char *tlab_start;
-       char *tlab_next;
-       char *tlab_temp_end;
-       char *tlab_real_end;
-       gpointer *store_remset_buffer;
-       long store_remset_buffer_index;
-#endif
-};
-
 #ifdef HAVE_KW_THREAD
 #define TLAB_ACCESS_INIT
 #define TLAB_START     tlab_start
@@ -5254,7 +5207,6 @@ mono_gc_deregister_root (char* addr)
  */
 
 /* FIXME: handle large/small config */
-#define THREAD_HASH_SIZE 11
 #define HASH_PTHREAD_T(id) (((unsigned int)(id) >> 4) * 2654435761u)
 
 static SgenThreadInfo* thread_table [THREAD_HASH_SIZE];
@@ -5264,18 +5216,19 @@ static SgenThreadInfo* thread_table [THREAD_HASH_SIZE];
 static MonoSemType suspend_ack_semaphore;
 static MonoSemType *suspend_ack_semaphore_ptr;
 static unsigned int global_stop_count = 0;
-#ifdef __APPLE__
-static int suspend_signal_num = SIGXFSZ;
-#else
-static int suspend_signal_num = SIGPWR;
-#endif
-static int restart_signal_num = SIGXCPU;
+
 static sigset_t suspend_signal_mask;
 static mword cur_thread_regs [ARCH_NUM_REGS] = {0};
 
 /* LOCKING: assumes the GC lock is held */
-static SgenThreadInfo*
-thread_info_lookup (ARCH_THREAD_TYPE id)
+SgenThreadInfo**
+mono_sgen_get_thread_table ()
+{
+       return thread_table;
+}
+
+SgenThreadInfo*
+mono_sgen_thread_info_lookup (ARCH_THREAD_TYPE id)
 {
        unsigned int hash = HASH_PTHREAD_T (id) % THREAD_HASH_SIZE;
        SgenThreadInfo *info;
@@ -5291,7 +5244,7 @@ static void
 update_current_thread_stack (void *start)
 {
        void *ptr = cur_thread_regs;
-       SgenThreadInfo *info = thread_info_lookup (ARCH_GET_THREAD ());
+       SgenThreadInfo *info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
        
        info->stack_start = align_pointer (&ptr);
        g_assert (info->stack_start >= info->stack_start_limit && info->stack_start < info->stack_end);
@@ -5329,8 +5282,8 @@ signal_desc (int signum)
 static gboolean
 is_ip_in_managed_allocator (MonoDomain *domain, gpointer ip);
 
-static void
-wait_for_suspend_ack (int count)
+void
+mono_sgen_wait_for_suspend_ack (int count)
 {
        int i, result;
 
@@ -5343,40 +5296,6 @@ wait_for_suspend_ack (int count)
        }
 }
 
-/* LOCKING: assumes the GC lock is held */
-static int
-thread_handshake (int signum)
-{
-       int count, i, result;
-       SgenThreadInfo *info;
-       pthread_t me = pthread_self ();
-
-       count = 0;
-       for (i = 0; i < THREAD_HASH_SIZE; ++i) {
-               for (info = thread_table [i]; info; info = info->next) {
-                       DEBUG (4, fprintf (gc_debug_file, "considering thread %p for signal %d (%s)\n", info, signum, signal_desc (signum)));
-                       if (ARCH_THREAD_EQUALS (info->id, me)) {
-                               DEBUG (4, fprintf (gc_debug_file, "Skip (equal): %p, %p\n", (void*)me, (void*)info->id));
-                               continue;
-                       }
-                       /*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
-                               continue;*/
-                       result = pthread_kill (info->id, signum);
-                       if (result == 0) {
-                               DEBUG (4, fprintf (gc_debug_file, "thread %p signal sent\n", info));
-                               count++;
-                       } else {
-                               DEBUG (4, fprintf (gc_debug_file, "thread %p signal failed: %d (%s)\n", (void*)info->id, result, strerror (result)));
-                               info->skip = 1;
-                       }
-               }
-       }
-
-       wait_for_suspend_ack (count);
-
-       return count;
-}
-
 static int
 restart_threads_until_none_in_managed_allocator (void)
 {
@@ -5395,7 +5314,11 @@ restart_threads_until_none_in_managed_allocator (void)
                                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) {
                                                ++restart_count;
                                        } else {
@@ -5416,8 +5339,12 @@ restart_threads_until_none_in_managed_allocator (void)
                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 */
-               wait_for_suspend_ack (restart_count);
+               mono_sgen_wait_for_suspend_ack (restart_count);
+#endif
 
                if (sleep_duration < 0) {
                        sched_yield ();
@@ -5432,7 +5359,11 @@ restart_threads_until_none_in_managed_allocator (void)
                        for (info = thread_table [i]; info; info = info->next) {
                                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) {
                                        ++restarted_count;
                                } else {
@@ -5442,9 +5373,13 @@ restart_threads_until_none_in_managed_allocator (void)
                }
                /* 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 */
-               wait_for_suspend_ack (restart_count);
+               mono_sgen_wait_for_suspend_ack (restart_count);
+#endif
        }
 
        return num_threads_died;
@@ -5462,7 +5397,7 @@ suspend_handler (int sig, siginfo_t *siginfo, void *context)
        gpointer stack_start;
 
        id = pthread_self ();
-       info = thread_info_lookup (id);
+       info = mono_sgen_thread_info_lookup (id);
        info->stopped_domain = mono_domain_get ();
        info->stopped_ip = (gpointer) ARCH_SIGCTX_IP (context);
        stop_count = global_stop_count;
@@ -5515,7 +5450,7 @@ restart_handler (int sig)
        SgenThreadInfo *info;
        int old_errno = errno;
 
-       info = thread_info_lookup (pthread_self ());
+       info = mono_sgen_thread_info_lookup (pthread_self ());
        info->signal = restart_signal_num;
        DEBUG (4, fprintf (gc_debug_file, "Restart handler in %p %p\n", info, (gpointer)ARCH_GET_THREAD ()));
 
@@ -5548,9 +5483,9 @@ stop_world (void)
        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, 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_sgen_thread_info_lookup (ARCH_GET_THREAD ()), (gpointer)ARCH_GET_THREAD ()));
        TV_GETTIME (stop_world_time);
-       count = thread_handshake (suspend_signal_num);
+       count = mono_sgen_thread_handshake (suspend_signal_num);
        count -= restart_threads_until_none_in_managed_allocator ();
        g_assert (count >= 0);
        DEBUG (3, fprintf (gc_debug_file, "world stopped %d thread(s)\n", count));
@@ -5582,7 +5517,7 @@ restart_world (void)
 
        release_gc_locks ();
 
-       count = thread_handshake (restart_signal_num);
+       count = mono_sgen_thread_handshake (restart_signal_num);
        TV_GETTIME (end_sw);
        usec = TV_ELAPSED (stop_world_time, end_sw);
        max_pause_usec = MAX (usec, max_pause_usec);
@@ -5598,6 +5533,12 @@ mono_gc_set_gc_callbacks (MonoGCCallbacks *callbacks)
        gc_callbacks = *callbacks;
 }
 
+MonoGCCallbacks *
+mono_gc_get_gc_callbacks ()
+{
+       return &gc_callbacks;
+}
+
 /* Variables holding start/end nursery so it won't have to be passed at every call */
 static void *scan_area_arg_start, *scan_area_arg_end;
 
@@ -5676,7 +5617,7 @@ static gboolean
 ptr_on_stack (void *ptr)
 {
        gpointer stack_start = &stack_start;
-       SgenThreadInfo *info = thread_info_lookup (ARCH_GET_THREAD ());
+       SgenThreadInfo *info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
 
        if (ptr >= stack_start && ptr < (gpointer)info->stack_end)
                return TRUE;
@@ -6186,7 +6127,7 @@ mono_gc_register_thread (void *baseptr)
 
        LOCK_GC;
        init_stats ();
-       info = thread_info_lookup (ARCH_GET_THREAD ());
+       info = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ());
        if (info == NULL)
                info = gc_register_current_thread (baseptr);
        UNLOCK_GC;
@@ -6317,7 +6258,7 @@ mono_gc_wbarrier_set_field (MonoObject *obj, gpointer field_ptr, MonoObject* val
        rs->next = REMEMBERED_SET;
        REMEMBERED_SET = rs;
 #ifdef HAVE_KW_THREAD
-       thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+       mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
 #endif
        *(rs->store_next++) = (mword)field_ptr;
        *(void**)field_ptr = value;
@@ -6347,7 +6288,7 @@ mono_gc_wbarrier_set_arrayref (MonoArray *arr, gpointer slot_ptr, MonoObject* va
        rs->next = REMEMBERED_SET;
        REMEMBERED_SET = rs;
 #ifdef HAVE_KW_THREAD
-       thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+       mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
 #endif
        *(rs->store_next++) = (mword)slot_ptr;
        *(void**)slot_ptr = value;
@@ -6378,7 +6319,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
-       thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+       mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
 #endif
        *(rs->store_next++) = (mword)dest_ptr | REMSET_RANGE;
        *(rs->store_next++) = count;
@@ -6556,7 +6497,7 @@ mono_gc_wbarrier_value_copy (gpointer dest, gpointer src, int count, MonoClass *
        rs->next = REMEMBERED_SET;
        REMEMBERED_SET = rs;
 #ifdef HAVE_KW_THREAD
-       thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+       mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
 #endif
        *(rs->store_next++) = (mword)dest | REMSET_VTYPE;
        *(rs->store_next++) = (mword)klass->gc_descr;
@@ -6597,7 +6538,7 @@ mono_gc_wbarrier_object_copy (MonoObject* obj, MonoObject *src)
        rs->next = REMEMBERED_SET;
        REMEMBERED_SET = rs;
 #ifdef HAVE_KW_THREAD
-       thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
+       mono_sgen_thread_info_lookup (ARCH_GET_THREAD ())->remset = rs;
 #endif
        *(rs->store_next++) = (mword)obj | REMSET_OBJECT;
        UNLOCK_GC;
@@ -7098,7 +7039,7 @@ mono_gc_is_gc_thread (void)
 {
        gboolean result;
        LOCK_GC;
-        result = thread_info_lookup (ARCH_GET_THREAD ()) != NULL;
+        result = mono_sgen_thread_info_lookup (ARCH_GET_THREAD ()) != NULL;
        UNLOCK_GC;
        return result;
 }
index 126bd4a1529cb118cf6551ebcd6a8cecce30957e..1a5b582ad8e4d65fbb6ceb505b1bd2c7cccbf6a0 100644 (file)
 #define __MONO_SGENGC_H__
 
 /* pthread impl */
+#include "config.h"
+#include <glib.h>
 #include <pthread.h>
+#include <sys/signal.h>
+#include "utils/mono-compiler.h"
+#include "metadata/class-internals.h"
+
+#define THREAD_HASH_SIZE 11
 
 #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;
+#else
+typedef guint64 mword;
+#endif
+
+/* for use with write barriers */
+typedef struct _RememberedSet RememberedSet;
+struct _RememberedSet {
+       mword *store_next;
+       mword *end_set;
+       RememberedSet *next;
+       mword data [MONO_ZERO_LEN_ARRAY];
+};
+
+/* eventually share with MonoThread? */
+typedef struct _SgenThreadInfo SgenThreadInfo;
+
+struct _SgenThreadInfo {
+       SgenThreadInfo *next;
+       ARCH_THREAD_TYPE id;
+       unsigned int stop_count; /* to catch duplicate signals */
+       int signal;
+       int skip;
+       volatile int in_critical_region;
+       void *stack_end;
+       void *stack_start;
+       void *stack_start_limit;
+       char **tlab_next_addr;
+       char **tlab_start_addr;
+       char **tlab_temp_end_addr;
+       char **tlab_real_end_addr;
+       gpointer **store_remset_buffer_addr;
+       long *store_remset_buffer_index_addr;
+       RememberedSet *remset;
+       gpointer runtime_data;
+       gpointer stopped_ip;    /* only valid if the thread is stopped */
+       MonoDomain *stopped_domain; /* ditto */
+       gpointer *stopped_regs;     /* ditto */
+#ifndef HAVE_KW_THREAD
+       char *tlab_start;
+       char *tlab_next;
+       char *tlab_temp_end;
+       char *tlab_real_end;
+       gpointer *store_remset_buffer;
+       long store_remset_buffer_index;
+#endif
+};
+
+#ifdef __APPLE__
+static int suspend_signal_num = SIGXFSZ;
+#else
+static int suspend_signal_num = SIGPWR;
+#endif
+static int restart_signal_num = SIGXCPU;
+
 /*
  * Recursion is not allowed for the thread lock.
  */
 /* we intercept pthread_create calls to know which threads exist */
 #define USE_PTHREAD_INTERCEPT 1
 
+#define MAX_DEBUG_LEVEL 2
+#define DEBUG(level,a) do {if (G_UNLIKELY ((level) <= MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) a;} while (0)
+
+int mono_sgen_thread_handshake (int signum) MONO_INTERNAL;
+SgenThreadInfo* mono_sgen_thread_info_lookup (ARCH_THREAD_TYPE id) MONO_INTERNAL;
+SgenThreadInfo** mono_sgen_get_thread_table () MONO_INTERNAL;
+void mono_sgen_wait_for_suspend_ack (int count) MONO_INTERNAL;
+
 #endif /* __MONO_SGENGC_H__ */
 
diff --git a/mono/metadata/sgen-os-mach.c b/mono/metadata/sgen-os-mach.c
new file mode 100644 (file)
index 0000000..cf0fc07
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * sgen-os-mach.c: Simple generational GC.
+ *
+ * Author:
+ *     Paolo Molaro (lupus@ximian.com)
+ *     Mark Probst (mprobst@novell.com)
+ *     Geoff Norton (gnorton@novell.com)
+ *
+ * Copyright 2010 Novell, Inc (http://www.novell.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "metadata/gc-internal.h"
+#include "metadata/sgen-gc.h"
+#include "metadata/sgen-archdep.h"
+#include "metadata/object-internals.h"
+
+#if defined(__MACH__)
+#include "utils/mach-support.h"
+#endif
+
+/* LOCKING: assumes the GC lock is held */
+#if defined(__MACH__) && MONO_MACH_ARCH_SUPPORTED
+int
+mono_sgen_thread_handshake (int signum)
+{
+       task_t task = current_task ();
+       thread_port_t cur_thread = mach_thread_self ();
+       thread_act_array_t thread_list;
+       mach_msg_type_number_t num_threads;
+       mach_msg_type_number_t num_state;
+       thread_state_t state;
+       kern_return_t ret;
+       ucontext_t ctx;
+
+       SgenThreadInfo *info;
+       gpointer regs [ARCH_NUM_REGS];
+       gpointer stack_start;
+
+       int count, i;
+
+       mono_mach_get_threads (&thread_list, &num_threads);
+
+       for (i = 0, count = 0; i < num_threads; i++) {
+               thread_port_t t = thread_list [i];
+               if (t != cur_thread) {
+                       if (signum == suspend_signal_num) {
+                               ret = thread_suspend (t);
+                               if (ret != KERN_SUCCESS) {
+                                       mach_port_deallocate (task, t);
+                                       continue;
+                               }
+
+                               ret = mono_mach_arch_get_thread_state (t, &state, &num_state);
+                               if (ret != KERN_SUCCESS) {
+                                       mach_port_deallocate (task, t);
+                                       continue;
+                               }
+
+
+                               info = mono_sgen_thread_info_lookup (pthread_from_mach_thread_np (t));
+
+                               /* Ensure that the runtime is aware of this thread */
+                               if (info != NULL) {
+                                       ctx.uc_mcontext = mono_mach_arch_thread_state_to_context (state);
+
+                                       info->stopped_domain = mono_mach_arch_get_tls_value_from_thread (t, mono_pthread_key_for_tls (mono_domain_get_tls_key ()));
+                                       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. */
+                                       if (stack_start >= info->stack_start_limit && info->stack_start <= info->stack_end) {
+                                               info->stack_start = stack_start;
+
+                                               ARCH_COPY_SIGCTX_REGS (regs, &ctx);
+                                               info->stopped_regs = regs;
+                                       } else {
+                                               g_assert (!info->stack_start);
+                                       }
+
+                                       /* Notify the JIT */
+                                       if (mono_gc_get_gc_callbacks ()->thread_suspend_func)
+                                               mono_gc_get_gc_callbacks ()->thread_suspend_func (info->runtime_data, &ctx);
+
+                                       g_free (ctx.uc_mcontext);
+                               }
+                       } else {
+                               ret = thread_resume (t);
+                               if (ret != KERN_SUCCESS) {
+                                       mach_port_deallocate (task, t);
+                                       continue;
+                               }
+                       }
+                       count ++;
+
+                       mach_port_deallocate (task, t);
+               }
+       }
+
+       mach_port_deallocate (task, cur_thread);
+
+       return count;
+}
+#endif
diff --git a/mono/metadata/sgen-os-posix.c b/mono/metadata/sgen-os-posix.c
new file mode 100644 (file)
index 0000000..6e2421f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * sgen-os-posix.c: Simple generational GC.
+ *
+ * Author:
+ *     Paolo Molaro (lupus@ximian.com)
+ *     Mark Probst (mprobst@novell.com)
+ *     Geoff Norton (gnorton@novell.com)
+ *
+ * Copyright 2010 Novell, Inc (http://www.novell.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+#include <glib.h>
+#include "metadata/gc-internal.h"
+#include "metadata/sgen-gc.h"
+#include "metadata/sgen-archdep.h"
+#include "metadata/object-internals.h"
+
+#if !defined(__MACH__) && !MONO_MACH_ARCH_SUPPORTED
+int
+mono_sgen_thread_handshake (int signum)
+{
+       int count, i, result;
+       SgenThreadInfo **thread_table;
+       SgenThreadInfo *info;
+       pthread_t me = pthread_self ();
+
+       thread_table = mono_sgen_get_thread_table ();
+       count = 0;
+       for (i = 0; i < THREAD_HASH_SIZE; ++i) {
+               for (info = thread_table [i]; info; info = info->next) {
+                       if (ARCH_THREAD_EQUALS (info->id, me)) {
+                               continue;
+                       }
+                       /*if (signum == suspend_signal_num && info->stop_count == global_stop_count)
+                               continue;*/
+                       result = pthread_kill (info->id, signum);
+                       if (result == 0) {
+                               count++;
+                       } else {
+                               info->skip = 1;
+                       }
+               }
+       }
+
+       mono_sgen_wait_for_suspend_ack (count);
+
+       return count;
+}
+#endif