[xbuild] Use the env var $MSBuildExtensionsPath before trying other paths.
[mono.git] / mono / metadata / threads.c
index 41a50a1b6bb71cff15025c23f39b81b27e4249df..7fcbc28b61e701848f249cec4a7636bcf726040c 100644 (file)
 #include <signal.h>
 #include <string.h>
 
+#if defined(__OpenBSD__)
+#include <pthread.h>
+#include <pthread_np.h>
+#endif
+
 #include <mono/metadata/object.h>
 #include <mono/metadata/domain-internals.h>
 #include <mono/metadata/profiler-private.h>
@@ -28,7 +33,7 @@
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/marshal.h>
 #include <mono/io-layer/io-layer.h>
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
 #include <mono/io-layer/threads.h>
 #endif
 #include <mono/metadata/object-internals.h>
 
 #include <mono/metadata/gc-internal.h>
 
+#ifdef PLATFORM_ANDROID
+#include <errno.h>
+
+extern int tkill (pid_t tid, int signal);
+#endif
+
 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
 #define THREAD_DEBUG(a)
 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
 #define LIBGC_DEBUG(a)
 
+#define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
+#define SPIN_LOCK(i) do { \
+                               if (SPIN_TRYLOCK (i)) \
+                                       break; \
+                       } while (1)
+
+#define SPIN_UNLOCK(i) i = 0
+
 /* Provide this for systems with glib < 2.6 */
 #ifndef G_GSIZE_FORMAT
 #   if GLIB_SIZEOF_LONG == 8
@@ -145,7 +164,7 @@ static __thread MonoInternalThread * tls_current_object MONO_TLS_FAST;
 #define GET_CURRENT_OBJECT() tls_current_object
 #else
 #define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x)
-#define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key)
+#define GET_CURRENT_OBJECT() (MonoInternalThread*) TlsGetValue (current_object_key)
 #endif
 
 /* function called at thread start */
@@ -165,6 +184,7 @@ static guint32 default_stacksize = 0;
 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
 
 static void thread_adjust_static_data (MonoInternalThread *thread);
+static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
 static void mono_init_static_data_info (StaticDataInfo *static_data);
 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
 static gboolean mono_thread_resume (MonoInternalThread* thread);
@@ -192,7 +212,11 @@ static int highest_small_id = -1;
 static MonoInternalThread **small_id_table = NULL;
 
 /* The hazard table */
+#if MONO_SMALL_CONFIG
+#define HAZARD_TABLE_MAX_SIZE  256
+#else
 #define HAZARD_TABLE_MAX_SIZE  16384 /* There cannot be more threads than this number. */
+#endif
 static volatile int hazard_table_size = 0;
 static MonoThreadHazardPointers * volatile hazard_table = NULL;
 
@@ -238,7 +262,7 @@ static gboolean handle_store(MonoThread *thread)
        }
 
        if(threads==NULL) {
-               MONO_GC_REGISTER_ROOT (threads);
+               MONO_GC_REGISTER_ROOT_FIXED (threads);
                threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
        }
 
@@ -313,6 +337,11 @@ small_id_alloc (MonoInternalThread *thread)
 
        if (!small_id_table) {
                small_id_table_size = 2;
+               /* 
+                * Enabling this causes problems, because SGEN doesn't track/update the TLS slot holding
+                * the current thread.
+                */
+               //small_id_table = mono_gc_alloc_fixed (small_id_table_size * sizeof (MonoInternalThread*), mono_gc_make_root_descr_all_refs (small_id_table_size));
                small_id_table = mono_gc_alloc_fixed (small_id_table_size * sizeof (MonoInternalThread*), NULL);
        }
        for (i = small_id_next; i < small_id_table_size; ++i) {
@@ -335,6 +364,7 @@ small_id_alloc (MonoInternalThread *thread)
                if (new_size >= (1 << 16))
                        g_assert_not_reached ();
                id = small_id_table_size;
+               //new_table = mono_gc_alloc_fixed (new_size * sizeof (MonoInternalThread*), mono_gc_make_root_descr_all_refs (new_size));
                new_table = mono_gc_alloc_fixed (new_size * sizeof (MonoInternalThread*), NULL);
                memcpy (new_table, small_id_table, small_id_table_size * sizeof (void*));
                mono_gc_free_fixed (small_id_table);
@@ -348,7 +378,12 @@ small_id_alloc (MonoInternalThread *thread)
        if (small_id_next > small_id_table_size)
                small_id_next = 0;
 
+       g_assert (id < HAZARD_TABLE_MAX_SIZE);
        if (id >= hazard_table_size) {
+#if MONO_SMALL_CONFIG
+               hazard_table = g_malloc0 (sizeof (MonoThreadHazardPointers) * HAZARD_TABLE_MAX_SIZE);
+               hazard_table_size = HAZARD_TABLE_MAX_SIZE;
+#else
                gpointer page_addr;
                int pagesize = mono_pagesize ();
                int num_pages = (hazard_table_size * sizeof (MonoThreadHazardPointers) + pagesize - 1) / pagesize;
@@ -362,15 +397,13 @@ small_id_alloc (MonoInternalThread *thread)
                g_assert (hazard_table != NULL);
                page_addr = (guint8*)hazard_table + num_pages * pagesize;
 
-               g_assert (id < HAZARD_TABLE_MAX_SIZE);
-
                mono_mprotect (page_addr, pagesize, MONO_MMAP_READ | MONO_MMAP_WRITE);
 
                ++num_pages;
                hazard_table_size = num_pages * pagesize / sizeof (MonoThreadHazardPointers);
 
+#endif
                g_assert (id < hazard_table_size);
-
                hazard_table [id].hazard_pointers [0] = NULL;
                hazard_table [id].hazard_pointers [1] = NULL;
        }
@@ -518,7 +551,6 @@ static void thread_cleanup (MonoInternalThread *thread)
        g_assert (thread != NULL);
 
        if (thread->abort_state_handle) {
-               g_assert (thread->abort_exc);
                mono_gchandle_free (thread->abort_state_handle);
                thread->abort_state_handle = 0;
        }
@@ -537,8 +569,12 @@ static void thread_cleanup (MonoInternalThread *thread)
        }
 
        /* if the thread is not in the hash it has been removed already */
-       if (!handle_remove (thread))
+       if (!handle_remove (thread)) {
+               /* This needs to be called even if handle_remove () fails */
+               if (mono_thread_cleanup_fn)
+                       mono_thread_cleanup_fn (thread);
                return;
+       }
        mono_release_type_locks (thread);
 
        EnterCriticalSection (thread->synch_cs);
@@ -553,22 +589,17 @@ static void thread_cleanup (MonoInternalThread *thread)
        if (thread == mono_thread_internal_current ())
                mono_thread_pop_appdomain_ref ();
 
-       if (thread->serialized_culture_info)
-               g_free (thread->serialized_culture_info);
-
-       if (thread->serialized_ui_culture_info)
-               g_free (thread->serialized_ui_culture_info);
-
        thread->cached_culture_info = NULL;
 
-       mono_gc_free_fixed (thread->static_data);
+       mono_free_static_data (thread->static_data, TRUE);
        thread->static_data = NULL;
 
        if (mono_thread_cleanup_fn)
-               mono_thread_cleanup_fn (thread->root_domain_thread);
+               mono_thread_cleanup_fn (thread);
 
        small_id_free (thread->small_id);
        thread->small_id = -2;
+
 }
 
 static gpointer
@@ -613,11 +644,25 @@ set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, M
        *current_thread_ptr = current;
 }
 
+static MonoInternalThread*
+create_internal_thread_object (void)
+{
+       MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
+       return (MonoInternalThread*)mono_gc_alloc_mature (vt);
+}
+
+static MonoThread*
+create_thread_object (MonoDomain *domain)
+{
+       MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
+       return (MonoThread*)mono_gc_alloc_mature (vt);
+}
+
 static MonoThread*
 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
 {
-       MonoThread *thread = (MonoThread*) mono_object_new (domain, mono_defaults.thread_class);
-       thread->internal_thread = internal;
+       MonoThread *thread = create_thread_object (domain);
+       MONO_OBJECT_SETREF (thread, internal_thread, internal);
        return thread;
 }
 
@@ -630,18 +675,22 @@ init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
                candidate = new_thread_with_internal (domain, thread);
        set_current_thread_for_domain (domain, thread, candidate);
        g_assert (!thread->root_domain_thread);
-       thread->root_domain_thread = candidate;
+       MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
 }
 
-static guint32 WINAPI start_wrapper(void *data)
+static guint32 WINAPI start_wrapper_internal(void *data)
 {
        struct StartInfo *start_info=(struct StartInfo *)data;
        guint32 (*start_func)(void *);
        void *start_arg;
        gsize tid;
-       MonoThread *thread=start_info->obj;
-       MonoInternalThread *internal = thread->internal_thread;
+       /* 
+        * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
+        * GC stack walk.
+        */
+       MonoInternalThread *internal = start_info->obj->internal_thread;
        MonoObject *start_delegate = start_info->delegate;
+       MonoDomain *domain = start_info->obj->obj.vtable->domain;
 
        THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
 
@@ -658,9 +707,9 @@ static guint32 WINAPI start_wrapper(void *data)
        mono_monitor_init_tls ();
 
        /* Every thread references the appdomain which created it */
-       mono_thread_push_appdomain_ref (thread->obj.vtable->domain);
+       mono_thread_push_appdomain_ref (domain);
        
-       if (!mono_domain_set (thread->obj.vtable->domain, FALSE)) {
+       if (!mono_domain_set (domain, FALSE)) {
                /* No point in raising an appdomain_unloaded exception here */
                /* FIXME: Cleanup here */
                mono_thread_pop_appdomain_ref ();
@@ -673,7 +722,7 @@ static guint32 WINAPI start_wrapper(void *data)
        /* We have to do this here because mono_thread_new_init()
           requires that root_domain_thread is set up. */
        thread_adjust_static_data (internal);
-       init_root_domain_thread (internal, thread);
+       init_root_domain_thread (internal, start_info->obj);
 
        /* This MUST be called before any managed code can be
         * executed, as it calls the callback function that (for the
@@ -686,14 +735,10 @@ static guint32 WINAPI start_wrapper(void *data)
 
        THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
 
-       mono_profiler_thread_start (tid);
-
        /* On 2.0 profile (and higher), set explicitly since state might have been
           Unknown */
-       if (mono_framework_version () != 1) {
-               if (internal->apartment_state == ThreadApartmentState_Unknown)
-                       internal->apartment_state = ThreadApartmentState_MTA;
-       }
+       if (internal->apartment_state == ThreadApartmentState_Unknown)
+               internal->apartment_state = ThreadApartmentState_MTA;
 
        mono_thread_init_apartment_state ();
 
@@ -705,17 +750,24 @@ static guint32 WINAPI start_wrapper(void *data)
        }
 
        mono_threads_lock ();
-       mono_g_hash_table_remove (thread_start_args, thread);
+       mono_g_hash_table_remove (thread_start_args, start_info->obj);
        mono_threads_unlock ();
 
+       mono_thread_set_execution_context (start_info->obj->ec_to_set);
+       start_info->obj->ec_to_set = NULL;
+
        g_free (start_info);
 #ifdef DEBUG
        g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
                   thread->tid);
 #endif
 
-       mono_thread_set_execution_context (thread->ec_to_set);
-       thread->ec_to_set = NULL;
+       /* 
+        * Call this after calling start_notify, since the profiler callback might want
+        * to lock the thread, and the lock is held by thread_start () which waits for
+        * start_notify.
+        */
+       mono_profiler_thread_start (tid);
 
        /* start_func is set only for unmanaged start functions */
        if (start_func) {
@@ -753,11 +805,24 @@ static guint32 WINAPI start_wrapper(void *data)
         * to TLS data.)
         */
        SET_CURRENT_OBJECT (NULL);
+       mono_domain_unset ();
 
        return(0);
 }
 
-void mono_thread_new_init (gsize tid, gpointer stack_start, gpointer func)
+static guint32 WINAPI start_wrapper(void *data)
+{
+#ifdef HAVE_SGEN_GC
+       volatile int dummy;
+
+       /* Avoid scanning the frames above this frame during a GC */
+       mono_gc_set_stack_end ((void*)&dummy);
+#endif
+
+       return start_wrapper_internal (data);
+}
+
+void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
 {
        if (mono_thread_start_cb) {
                mono_thread_start_cb (tid, stack_start, func);
@@ -786,7 +851,7 @@ gpointer mono_create_thread (WapiSecurityAttributes *security,
 {
        gpointer res;
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        DWORD real_tid;
 
        res = CreateThread (security, stacksize, start, param, create, &real_tid);
@@ -799,6 +864,24 @@ gpointer mono_create_thread (WapiSecurityAttributes *security,
        return res;
 }
 
+/* 
+ * The thread start argument may be an object reference, and there is
+ * no ref to keep it alive when the new thread is started but not yet
+ * registered with the collector. So we store it in a GC tracked hash
+ * table.
+ *
+ * LOCKING: Assumes the threads lock is held.
+ */
+static void
+register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
+{
+       if (thread_start_args == NULL) {
+               MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
+               thread_start_args = mono_g_hash_table_new (NULL, NULL);
+       }
+       mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
+}
+
 MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread)
 {
        MonoThread *thread;
@@ -807,11 +890,9 @@ MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer fu
        struct StartInfo *start_info;
        gsize tid;
 
-       thread=(MonoThread *)mono_object_new (domain,
-                                             mono_defaults.thread_class);
-       internal = (MonoInternalThread*)mono_object_new (mono_get_root_domain (),
-                       mono_defaults.internal_thread_class);
-       thread->internal_thread = internal;
+       thread = create_thread_object (domain);
+       internal = create_internal_thread_object ();
+       MONO_OBJECT_SETREF (thread, internal_thread, internal);
 
        start_info=g_new0 (struct StartInfo, 1);
        start_info->func = func;
@@ -825,20 +906,12 @@ MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer fu
                return NULL;
        }
        if (threads_starting_up == NULL) {
-               MONO_GC_REGISTER_ROOT (threads_starting_up);
-               threads_starting_up = mono_g_hash_table_new (NULL, NULL);
-       }
-       if (thread_start_args == NULL) {
-               MONO_GC_REGISTER_ROOT (thread_start_args);
-               thread_start_args = mono_g_hash_table_new (NULL, NULL);
+               MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
+               threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
        }
+
+       register_thread_start_argument (thread, start_info);
        mono_g_hash_table_insert (threads_starting_up, thread, thread);
-       /* 
-        * The argument may be an object reference, and there is no ref to keep it alive
-        * when the new thread is started but not yet registered with the collector. So
-        * we store it in a GC tracked hash table.
-        */
-       mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
        mono_threads_unlock (); 
 
        /* Create suspended, so we can do some housekeeping before the thread
@@ -896,7 +969,7 @@ mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
        *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
        return;
        /* FIXME: simplify the mess below */
-#elif !defined(PLATFORM_WIN32)
+#elif !defined(HOST_WIN32)
        pthread_attr_t attr;
        guint8 *current = (guint8*)&attr;
 
@@ -909,6 +982,15 @@ mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
 #    elif defined(sun)
        *staddr = NULL;
        pthread_attr_getstacksize (&attr, &stsize);
+#    elif defined(__OpenBSD__)
+       stack_t ss;
+       int rslt;
+
+       rslt = pthread_stackseg_np(pthread_self(), &ss);
+       g_assert (rslt == 0);
+
+       *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
+       *stsize = ss.ss_size;
 #    else
        *staddr = NULL;
        *stsize = 0;
@@ -916,13 +998,18 @@ mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
 #    endif
 #  endif
 
-#  ifndef sun
+#  if !defined(sun)
+#    if !defined(__OpenBSD__)
        pthread_attr_getstack (&attr, (void**)staddr, stsize);
+#    endif
        if (*staddr)
                g_assert ((current > *staddr) && (current < *staddr + *stsize));
 #  endif
 
-       pthread_attr_destroy (&attr); 
+       pthread_attr_destroy (&attr);
+#else
+       *staddr = NULL;
+       *stsize = (size_t)-1;
 #endif
 
        /* When running under emacs, sometimes staddr is not aligned to a page size */
@@ -948,7 +1035,7 @@ mono_thread_attach (MonoDomain *domain)
                g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
        }
 
-       thread = (MonoInternalThread *)mono_object_new (domain, mono_defaults.internal_thread_class);
+       thread = create_internal_thread_object ();
 
        thread_handle = GetCurrentThread ();
        g_assert (thread_handle);
@@ -964,6 +1051,9 @@ mono_thread_attach (MonoDomain *domain)
 
        thread->handle=thread_handle;
        thread->tid=tid;
+#ifdef PLATFORM_ANDROID
+       thread->android_tid = (gpointer) gettid ();
+#endif
        thread->apartment_state=ThreadApartmentState_Unknown;
        small_id_alloc (thread);
        thread->stack_ptr = &tid;
@@ -1007,6 +1097,9 @@ mono_thread_attach (MonoDomain *domain)
                        mono_thread_attach_cb (tid, staddr + stsize);
        }
 
+       // FIXME: Need a separate callback
+       mono_profiler_thread_start (tid);
+
        return current_thread;
 }
 
@@ -1020,6 +1113,7 @@ mono_thread_detach (MonoThread *thread)
        thread_cleanup (thread->internal_thread);
 
        SET_CURRENT_OBJECT (NULL);
+       mono_domain_unset ();
 
        /* Don't need to CloseHandle this thread, even though we took a
         * reference in mono_thread_attach (), because the GC will do it
@@ -1036,9 +1130,10 @@ mono_thread_exit ()
 
        thread_cleanup (thread);
        SET_CURRENT_OBJECT (NULL);
+       mono_domain_unset ();
 
        /* we could add a callback here for embedders to use. */
-       if (thread == mono_thread_get_main ()->internal_thread)
+       if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
                exit (mono_environment_exitcode_get ());
        ExitThread (-1);
 }
@@ -1046,7 +1141,8 @@ mono_thread_exit ()
 void
 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
 {
-       MonoInternalThread *internal = (MonoInternalThread*)mono_object_new (mono_get_root_domain (), mono_defaults.internal_thread_class);
+       MonoInternalThread *internal = create_internal_thread_object ();
+
        internal->state = ThreadState_Unstarted;
        internal->apartment_state = ThreadApartmentState_Unknown;
 
@@ -1103,9 +1199,10 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
                }
 
                mono_threads_lock ();
+               register_thread_start_argument (this, start_info);
                if (threads_starting_up == NULL) {
-                       MONO_GC_REGISTER_ROOT (threads_starting_up);
-                       threads_starting_up = mono_g_hash_table_new (NULL, NULL);
+                       MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
+                       threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
                }
                mono_g_hash_table_insert (threads_starting_up, this, this);
                mono_threads_unlock (); 
@@ -1157,8 +1254,6 @@ void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInterna
                this->synch_cs = NULL;
        }
 
-       g_assert (!this->abort_exc && !this->abort_state_handle);
-
        g_free (this->name);
 }
 
@@ -1227,6 +1322,46 @@ ves_icall_System_Threading_Thread_GetDomainID (void)
        return mono_domain_get()->domain_id;
 }
 
+gboolean 
+ves_icall_System_Threading_Thread_Yield (void)
+{
+#ifdef HOST_WIN32
+       return SwitchToThread ();
+#else
+       return sched_yield () == 0;
+#endif
+}
+
+/*
+ * mono_thread_get_name:
+ *
+ *   Return the name of the thread. NAME_LEN is set to the length of the name.
+ * Return NULL if the thread has no name. The returned memory is owned by the
+ * caller.
+ */
+gunichar2*
+mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
+{
+       gunichar2 *res;
+
+       ensure_synch_cs_set (this_obj);
+       
+       EnterCriticalSection (this_obj->synch_cs);
+       
+       if (!this_obj->name) {
+               *name_len = 0;
+               res = NULL;
+       } else {
+               *name_len = this_obj->name_len;
+               res = g_new (gunichar2, this_obj->name_len);
+               memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
+       }
+       
+       LeaveCriticalSection (this_obj->synch_cs);
+
+       return res;
+}
+
 MonoString* 
 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
 {
@@ -1268,24 +1403,11 @@ ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj
                this_obj->name = NULL;
        
        LeaveCriticalSection (this_obj->synch_cs);
-}
-
-static MonoObject*
-lookup_cached_culture (MonoInternalThread *this, MonoDomain *domain, int start_idx)
-{
-       MonoObject *res;
-       int i;
-
-       if (this->cached_culture_info) {
-               domain = mono_domain_get ();
-               for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
-                       res = mono_array_get (this->cached_culture_info, MonoObject*, i);
-                       if (res && res->vtable->domain == domain)
-                               return res;
-               }
+       if (this_obj->name) {
+               char *tname = mono_string_to_utf8 (name);
+               mono_profiler_thread_name (this_obj->tid, tname);
+               mono_free (tname);
        }
-
-       return NULL;
 }
 
 /* If the array is already in the requested domain, we just return it,
@@ -1318,148 +1440,6 @@ ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
        return byte_array_to_domain (arr, mono_domain_get ());
 }
 
-MonoObject*
-ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoInternalThread *this)
-{
-       return lookup_cached_culture (this, mono_domain_get (), CULTURES_START_IDX);
-}
-
-MonoArray*
-ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoInternalThread *this)
-{
-       MonoArray *res;
-
-       ensure_synch_cs_set (this);
-       
-       EnterCriticalSection (this->synch_cs);
-       
-       if (this->serialized_culture_info) {
-               res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
-               memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
-       } else {
-               res = NULL;
-       }
-
-       LeaveCriticalSection (this->synch_cs);
-
-       return res;
-}
-
-static void
-cache_culture (MonoInternalThread *this, MonoObject *culture, int start_idx)
-{
-       int i;
-       MonoDomain *domain = mono_domain_get ();
-       MonoObject *obj;
-       int free_slot = -1;
-       int same_domain_slot = -1;
-
-       ensure_synch_cs_set (this);
-       
-       EnterCriticalSection (this->synch_cs);
-       
-       if (!this->cached_culture_info)
-               MONO_OBJECT_SETREF (this, cached_culture_info, mono_array_new_cached (mono_get_root_domain (), mono_defaults.object_class, NUM_CACHED_CULTURES * 2));
-
-       for (i = start_idx; i < start_idx + NUM_CACHED_CULTURES; ++i) {
-               obj = mono_array_get (this->cached_culture_info, MonoObject*, i);
-               /* Free entry */
-               if (!obj) {
-                       free_slot = i;
-                       /* we continue, because there may be a slot used with the same domain */
-                       continue;
-               }
-               /* Replace */
-               if (obj->vtable->domain == domain) {
-                       same_domain_slot = i;
-                       break;
-               }
-       }
-       if (same_domain_slot >= 0)
-               mono_array_setref (this->cached_culture_info, same_domain_slot, culture);
-       else if (free_slot >= 0)
-               mono_array_setref (this->cached_culture_info, free_slot, culture);
-       /* we may want to replace an existing entry here, even when no suitable slot is found */
-
-       LeaveCriticalSection (this->synch_cs);
-}
-
-void
-ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
-{
-       MonoDomain *domain = mono_object_get_domain (&this->obj);
-       g_assert (domain == mono_domain_get ());
-       cache_culture (this->internal_thread, culture, CULTURES_START_IDX);
-}
-
-void
-ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoInternalThread *this, MonoArray *arr)
-{
-       ensure_synch_cs_set (this);
-       
-       EnterCriticalSection (this->synch_cs);
-       
-       if (this->serialized_culture_info)
-               g_free (this->serialized_culture_info);
-       this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
-       this->serialized_culture_info_len = mono_array_length (arr);
-       memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
-
-       LeaveCriticalSection (this->synch_cs);
-}
-
-
-MonoObject*
-ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoInternalThread *this)
-{
-       return lookup_cached_culture (this, mono_domain_get (), UICULTURES_START_IDX);
-}
-
-MonoArray*
-ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoInternalThread *this)
-{
-       MonoArray *res;
-
-       ensure_synch_cs_set (this);
-       
-       EnterCriticalSection (this->synch_cs);
-       
-       if (this->serialized_ui_culture_info) {
-               res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
-               memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
-       } else {
-               res = NULL;
-       }
-
-       LeaveCriticalSection (this->synch_cs);
-
-       return res;
-}
-
-void
-ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
-{
-       MonoDomain *domain = mono_object_get_domain (&this->obj);
-       g_assert (domain == mono_domain_get ());
-       cache_culture (this->internal_thread, culture, UICULTURES_START_IDX);
-}
-
-void
-ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoInternalThread *this, MonoArray *arr)
-{
-       ensure_synch_cs_set (this);
-       
-       EnterCriticalSection (this->synch_cs);
-       
-       if (this->serialized_ui_culture_info)
-               g_free (this->serialized_ui_culture_info);
-       this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
-       this->serialized_ui_culture_info_len = mono_array_length (arr);
-       memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
-
-       LeaveCriticalSection (this->synch_cs);
-}
-
 MonoThread *
 mono_thread_current (void)
 {
@@ -1580,18 +1560,20 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_
 /* FIXME: exitContext isnt documented */
 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
 {
-       HANDLE *handles;
+       HANDLE handles [MAXIMUM_WAIT_OBJECTS];
        guint32 numhandles;
        guint32 ret;
        guint32 i;
        MonoObject *waitHandle;
        MonoInternalThread *thread = mono_thread_internal_current ();
+       guint32 start;
 
        /* Do this WaitSleepJoin check before creating objects */
        mono_thread_current_check_pending_interrupt ();
 
        numhandles = mono_array_length(mono_handles);
-       handles = g_new0(HANDLE, numhandles);
+       if (numhandles > MAXIMUM_WAIT_OBJECTS)
+               return WAIT_FAILED;
 
        for(i = 0; i < numhandles; i++) {       
                waitHandle = mono_array_get(mono_handles, MonoObject*, i);
@@ -1603,12 +1585,23 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha
        }
 
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
-       
-       ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
+
+       start = (ms == -1) ? 0 : mono_msec_ticks ();
+       do {
+               ret = WaitForMultipleObjectsEx (numhandles, handles, FALSE, ms, TRUE);
+               if (ret != WAIT_IO_COMPLETION)
+                       break;
+               if (ms != -1) {
+                       guint32 diff;
+
+                       diff = mono_msec_ticks () - start;
+                       ms -= diff;
+                       if (ms <= 0)
+                               break;
+               }
+       } while (ms == -1 || ms > 0);
 
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
-       
-       g_free(handles);
 
        THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
 
@@ -2211,7 +2204,7 @@ void mono_thread_current_check_pending_interrupt ()
 int  
 mono_thread_get_abort_signal (void)
 {
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        return -1;
 #else
 #ifndef        SIGRTMIN
@@ -2237,16 +2230,16 @@ mono_thread_get_abort_signal (void)
        /* fallback to the old way */
        return SIGRTMIN;
 #endif
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
 }
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
 static void CALLBACK interruption_request_apc (ULONG_PTR param)
 {
        MonoException* exc = mono_thread_request_interruption (FALSE);
        if (exc) mono_raise_exception (exc);
 }
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
 
 /*
  * signal_thread_state_change
@@ -2263,15 +2256,11 @@ static void signal_thread_state_change (MonoInternalThread *thread)
                        mono_raise_exception (exc);
        }
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
 #else
        /* fixme: store the state somewhere */
-#ifdef PTHREAD_POINTER_ID
-       pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
-#else
-       pthread_kill (thread->tid, mono_thread_get_abort_signal ());
-#endif
+       mono_thread_kill (thread, mono_thread_get_abort_signal ());
 
        /* 
         * This will cause waits to be broken.
@@ -2281,7 +2270,7 @@ static void signal_thread_state_change (MonoInternalThread *thread)
         * make it return.
         */
        wapi_interrupt_thread (thread->handle);
-#endif /* PLATFORM_WIN32 */
+#endif /* HOST_WIN32 */
 }
 
 void
@@ -2316,6 +2305,14 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject
        }
        thread->abort_exc = NULL;
 
+       /*
+        * abort_exc is set in mono_thread_execute_interruption(),
+        * triggered by the call to signal_thread_state_change(),
+        * below.  There's a point between where we have
+        * abort_state_handle set, but abort_exc NULL, but that's not
+        * a problem.
+        */
+
        LeaveCriticalSection (thread->synch_cs);
 
        THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
@@ -2332,121 +2329,56 @@ void
 ves_icall_System_Threading_Thread_ResetAbort (void)
 {
        MonoInternalThread *thread = mono_thread_internal_current ();
+       gboolean was_aborting;
 
        ensure_synch_cs_set (thread);
        
        EnterCriticalSection (thread->synch_cs);
-
+       was_aborting = thread->state & ThreadState_AbortRequested;
        thread->state &= ~ThreadState_AbortRequested;
-       
-       if (!thread->abort_exc) {
-               const char *msg = "Unable to reset abort because no abort was requested";
-               LeaveCriticalSection (thread->synch_cs);
-               mono_raise_exception (mono_get_exception_thread_state (msg));
-       } else {
-               thread->abort_exc = NULL;
-               if (thread->abort_state_handle) {
-                       mono_gchandle_free (thread->abort_state_handle);
-                       /* This is actually not necessary - the handle
-                          only counts if the exception is set */
-                       thread->abort_state_handle = 0;
-               }
-       }
-       
        LeaveCriticalSection (thread->synch_cs);
-}
-
-static MonoObject*
-serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
-{
-       static MonoMethod *serialize_method;
-
-       void *params [1];
-       MonoObject *array;
-
-       if (!serialize_method) {
-               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
-               serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
-       }
-
-       if (!serialize_method) {
-               *failure = TRUE;
-               return NULL;
-       }
-
-       g_assert (!obj->vtable->klass->marshalbyref);
-
-       params [0] = obj;
-       *exc = NULL;
-       array = mono_runtime_invoke (serialize_method, NULL, params, exc);
-       if (*exc)
-               *failure = TRUE;
-
-       return array;
-}
 
-static MonoObject*
-deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
-{
-       static MonoMethod *deserialize_method;
-
-       void *params [1];
-       MonoObject *result;
-
-       if (!deserialize_method) {
-               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
-               deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
+       if (!was_aborting) {
+               const char *msg = "Unable to reset abort because no abort was requested";
+               mono_raise_exception (mono_get_exception_thread_state (msg));
        }
-       if (!deserialize_method) {
-               *failure = TRUE;
-               return NULL;
+       thread->abort_exc = NULL;
+       if (thread->abort_state_handle) {
+               mono_gchandle_free (thread->abort_state_handle);
+               /* This is actually not necessary - the handle
+                  only counts if the exception is set */
+               thread->abort_state_handle = 0;
        }
-
-       params [0] = obj;
-       *exc = NULL;
-       result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
-       if (*exc)
-               *failure = TRUE;
-
-       return result;
 }
 
-static MonoObject*
-make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
+void
+mono_thread_internal_reset_abort (MonoInternalThread *thread)
 {
-       static MonoMethod *get_proxy_method;
-
-       MonoDomain *domain = mono_domain_get ();
-       MonoRealProxy *real_proxy;
-       MonoReflectionType *reflection_type;
-       MonoTransparentProxy *transparent_proxy;
-
-       if (!get_proxy_method)
-               get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
-
-       g_assert (obj->vtable->klass->marshalbyref);
+       ensure_synch_cs_set (thread);
 
-       real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
-       reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
+       EnterCriticalSection (thread->synch_cs);
 
-       real_proxy->class_to_proxy = reflection_type;
-       real_proxy->unwrapped_server = obj;
+       thread->state &= ~ThreadState_AbortRequested;
 
-       *exc = NULL;
-       transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
-       if (*exc)
-               *failure = TRUE;
+       if (thread->abort_exc) {
+               thread->abort_exc = NULL;
+               if (thread->abort_state_handle) {
+                       mono_gchandle_free (thread->abort_state_handle);
+                       /* This is actually not necessary - the handle
+                          only counts if the exception is set */
+                       thread->abort_state_handle = 0;
+               }
+       }
 
-       return (MonoObject*) transparent_proxy;
+       LeaveCriticalSection (thread->synch_cs);
 }
 
 MonoObject*
 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
 {
        MonoInternalThread *thread = this->internal_thread;
-       MonoObject *state, *serialized, *deserialized = NULL, *exc;
+       MonoObject *state, *deserialized = NULL, *exc;
        MonoDomain *domain;
-       gboolean failure = FALSE;
 
        if (!thread->abort_state_handle)
                return NULL;
@@ -2455,20 +2387,12 @@ ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
        g_assert (state);
 
        domain = mono_domain_get ();
-       if (state->vtable->domain == domain)
+       if (mono_object_domain (state) == domain)
                return state;
 
-       if (state->vtable->klass->marshalbyref) {
-               deserialized = make_transparent_proxy (state, &failure, &exc);
-       } else {
-               mono_domain_set_internal_with_options (state->vtable->domain, FALSE);
-               serialized = serialize_object (state, &failure, &exc);
-               mono_domain_set_internal_with_options (domain, FALSE);
-               if (!failure)
-                       deserialized = deserialize_object (serialized, &failure, &exc);
-       }
+       deserialized = mono_object_xdomain_representation (state, domain, &exc);
 
-       if (failure) {
+       if (!deserialized) {
                MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
                if (exc)
                        MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
@@ -2686,7 +2610,7 @@ ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
 void mono_thread_init (MonoThreadStartCB start_cb,
                       MonoThreadAttachCB attach_cb)
 {
-       MONO_GC_REGISTER_ROOT (small_id_table);
+       MONO_GC_REGISTER_ROOT_FIXED (small_id_table);
        InitializeCriticalSection(&threads_mutex);
        InitializeCriticalSection(&interlocked_mutex);
        InitializeCriticalSection(&contexts_mutex);
@@ -2719,7 +2643,7 @@ void mono_thread_cleanup (void)
 {
        mono_thread_hazardous_try_free_all ();
 
-#if !defined(PLATFORM_WIN32) && !defined(RUN_IN_SUBTHREAD)
+#if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
        /* The main thread must abandon any held mutexes (particularly
         * important for named mutexes as they are shared across
         * processes, see bug 74680.)  This will happen when the
@@ -2794,7 +2718,7 @@ static void wait_for_tids (struct wait_data *wait, guint32 timeout)
        
        THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
 
-       ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
+       ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
 
        if(ret==WAIT_FAILED) {
                /* See the comment in build_wait_tids() */
@@ -2848,7 +2772,7 @@ static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeo
                count++;
        }
 
-       ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, FALSE);
+       ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
 
        if(ret==WAIT_FAILED) {
                /* See the comment in build_wait_tids() */
@@ -2900,11 +2824,16 @@ static void build_wait_tids (gpointer key, gpointer value, gpointer user)
                        return;
                }
 
-               if (thread == mono_thread_get_main ()->internal_thread) {
+               if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
                        THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
                        return;
                }
 
+               if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
+                       THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
+                       return;
+               }
+
                handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
                if (handle == NULL) {
                        THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
@@ -2942,7 +2871,8 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
                return FALSE;
 
        /* The finalizer thread is not a background thread */
-       if (thread->tid != self && (thread->state & ThreadState_Background) != 0) {
+       if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
+               !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
        
                handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
                if (handle == NULL)
@@ -2992,6 +2922,9 @@ mono_threads_set_shutting_down (void)
                        LeaveCriticalSection (current_thread->synch_cs);
                }
 
+               /*since we're killing the thread, unset the current domain.*/
+               mono_domain_unset ();
+
                /* Wake up other threads potentially waiting for us */
                ExitThread (0);
        } else {
@@ -3024,8 +2957,10 @@ mono_threads_is_shutting_down (void)
 
 void mono_thread_manage (void)
 {
-       struct wait_data *wait=g_new0 (struct wait_data, 1);
+       struct wait_data wait_data;
+       struct wait_data *wait = &wait_data;
 
+       memset (wait, 0, sizeof (struct wait_data));
        /* join each thread that's still running */
        THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
        
@@ -3033,7 +2968,6 @@ void mono_thread_manage (void)
        if(threads==NULL) {
                THREAD_DEBUG (g_message("%s: No threads", __func__));
                mono_threads_unlock ();
-               g_free (wait);
                return;
        }
        mono_threads_unlock ();
@@ -3050,6 +2984,8 @@ void mono_thread_manage (void)
        
                ResetEvent (background_change_event);
                wait->num=0;
+               /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
+               memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
                mono_g_hash_table_foreach (threads, build_wait_tids, wait);
                mono_threads_unlock ();
                if(wait->num>0) {
@@ -3076,6 +3012,8 @@ void mono_thread_manage (void)
                mono_threads_lock ();
 
                wait->num = 0;
+               /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
+               memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
                mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
 
                mono_threads_unlock ();
@@ -3092,11 +3030,9 @@ void mono_thread_manage (void)
         * to get correct user and system times from getrusage/wait/time(1)).
         * This could be removed if we avoid pthread_detach() and use pthread_join().
         */
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
        sched_yield ();
 #endif
-
-       g_free (wait);
 }
 
 static void terminate_thread (gpointer key, gpointer value, gpointer user)
@@ -3157,13 +3093,15 @@ collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
  */
 void mono_thread_suspend_all_other_threads (void)
 {
-       struct wait_data *wait = g_new0 (struct wait_data, 1);
+       struct wait_data wait_data;
+       struct wait_data *wait = &wait_data;
        int i;
        gsize self = GetCurrentThreadId ();
        gpointer *events;
        guint32 eventidx = 0;
        gboolean starting, finished;
 
+       memset (wait, 0, sizeof (struct wait_data));
        /*
         * The other threads could be in an arbitrary state at this point, i.e.
         * they could be starting up, shutting down etc. This means that there could be
@@ -3190,6 +3128,8 @@ void mono_thread_suspend_all_other_threads (void)
                 * threads while threads_mutex is held.
                 */
                wait->num = 0;
+               /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
+               memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
                mono_threads_lock ();
                mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
                mono_threads_unlock ();
@@ -3201,7 +3141,7 @@ void mono_thread_suspend_all_other_threads (void)
                        MonoInternalThread *thread = wait->threads [i];
                        gboolean signal_suspend = FALSE;
 
-                       if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread)) {
+                       if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
                                //CloseHandle (wait->handles [i]);
                                wait->threads [i] = NULL; /* ignore this thread in next loop */
                                continue;
@@ -3254,6 +3194,8 @@ void mono_thread_suspend_all_other_threads (void)
 
                                if (thread == NULL)
                                        continue;
+
+                               ensure_synch_cs_set (thread);
                        
                                EnterCriticalSection (thread->synch_cs);
                                if ((thread->state & ThreadState_Suspended) != 0) {
@@ -3284,8 +3226,6 @@ void mono_thread_suspend_all_other_threads (void)
 
                g_free (events);
        }
-
-       g_free (wait);
 }
 
 static void
@@ -3314,9 +3254,12 @@ collect_threads (gpointer key, gpointer value, gpointer user_data)
 void
 mono_threads_request_thread_dump (void)
 {
-       struct wait_data *wait = g_new0 (struct wait_data, 1);
+       struct wait_data wait_data;
+       struct wait_data *wait = &wait_data;
        int i;
 
+       memset (wait, 0, sizeof (struct wait_data));
+
        /* 
         * Make a copy of the hashtable since we can't do anything with
         * threads while threads_mutex is held.
@@ -3354,9 +3297,9 @@ mono_thread_push_appdomain_ref (MonoDomain *domain)
 
        if (thread) {
                /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
-               mono_threads_lock ();
+               SPIN_LOCK (thread->lock_thread_id);
                thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
-               mono_threads_unlock ();
+               SPIN_UNLOCK (thread->lock_thread_id);
        }
 }
 
@@ -3367,11 +3310,11 @@ mono_thread_pop_appdomain_ref (void)
 
        if (thread) {
                /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
-               mono_threads_lock ();
                /* FIXME: How can the list be empty ? */
+               SPIN_LOCK (thread->lock_thread_id);
                if (thread->appdomain_refs)
                        thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
-               mono_threads_unlock ();
+               SPIN_UNLOCK (thread->lock_thread_id);
        }
 }
 
@@ -3379,9 +3322,9 @@ gboolean
 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
 {
        gboolean res;
-       mono_threads_lock ();
+       SPIN_LOCK (thread->lock_thread_id);
        res = g_slist_find (thread->appdomain_refs, domain) != NULL;
-       mono_threads_unlock ();
+       SPIN_UNLOCK (thread->lock_thread_id);
        return res;
 }
 
@@ -3529,11 +3472,47 @@ mono_thread_get_undeniable_exception (void)
        return NULL;
 }
 
+#if MONO_SMALL_CONFIG
+#define NUM_STATIC_DATA_IDX 4
+static const int static_data_size [NUM_STATIC_DATA_IDX] = {
+       64, 256, 1024, 4096
+};
+#else
 #define NUM_STATIC_DATA_IDX 8
 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
        1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
 };
+#endif
 
+static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
+
+#ifdef HAVE_SGEN_GC
+static void
+mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
+{
+       int i;
+       gpointer *static_data = addr;
+       for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
+               int j, numwords;
+               void **ptr;
+               if (!static_data [i])
+                       continue;
+               numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
+               ptr = static_data [i];
+               for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
+                       uintptr_t bmap = static_reference_bitmaps [i][j];
+                       void ** p = ptr;
+                       while (bmap) {
+                               if ((bmap & 1) && *p) {
+                                       mark_func (p);
+                               }
+                               p++;
+                               bmap >>= 1;
+                       }
+               }
+       }
+}
+#endif
 
 /*
  *  mono_alloc_static_data
@@ -3541,14 +3520,19 @@ static const int static_data_size [NUM_STATIC_DATA_IDX] = {
  *   Allocate memory blocks for storing threads or context static data
  */
 static void 
-mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
+mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
 {
        guint idx = (offset >> 24) - 1;
        int i;
 
        gpointer* static_data = *static_data_ptr;
        if (!static_data) {
-               static_data = mono_gc_alloc_fixed (static_data_size [0], NULL);
+               static void* tls_desc = NULL;
+#ifdef HAVE_SGEN_GC
+               if (!tls_desc)
+                       tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
+#endif
+               static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
                *static_data_ptr = static_data;
                static_data [0] = static_data;
        }
@@ -3556,10 +3540,33 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
        for (i = 1; i <= idx; ++i) {
                if (static_data [i])
                        continue;
+#ifdef HAVE_SGEN_GC
+               static_data [i] = threadlocal?g_malloc0 (static_data_size [i]):mono_gc_alloc_fixed (static_data_size [i], NULL);
+#else
                static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
+#endif
        }
 }
 
+static void 
+mono_free_static_data (gpointer* static_data, gboolean threadlocal)
+{
+       int i;
+       for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
+               if (!static_data [i])
+                       continue;
+#ifdef HAVE_SGEN_GC
+               if (threadlocal)
+                       g_free (static_data [i]);
+               else
+                       mono_gc_free_fixed (static_data [i]);
+#else
+               mono_gc_free_fixed (static_data [i]);
+#endif
+       }
+       mono_gc_free_fixed (static_data);
+}
+
 /*
  *  mono_init_static_data_info
  *
@@ -3616,7 +3623,7 @@ thread_adjust_static_data (MonoInternalThread *thread)
        if (thread_static_info.offset || thread_static_info.idx > 0) {
                /* get the current allocated size */
                offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
-               mono_alloc_static_data (&(thread->static_data), offset);
+               mono_alloc_static_data (&(thread->static_data), offset, TRUE);
        }
        mono_threads_unlock ();
 }
@@ -3627,7 +3634,7 @@ alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
        MonoInternalThread *thread = value;
        guint32 offset = GPOINTER_TO_UINT (user);
 
-       mono_alloc_static_data (&(thread->static_data), offset);
+       mono_alloc_static_data (&(thread->static_data), offset, TRUE);
 }
 
 static MonoThreadDomainTls*
@@ -3648,6 +3655,39 @@ search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32
        return NULL;
 }
 
+static void
+update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int max_set)
+{
+       int i;
+       int idx = (offset >> 24) - 1;
+       uintptr_t *rb;
+       if (!static_reference_bitmaps [idx])
+               static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
+       rb = static_reference_bitmaps [idx];
+       offset &= 0xffffff;
+       offset /= sizeof (gpointer);
+       /* offset is now the bitmap offset */
+       for (i = 0; i < max_set; ++i) {
+               if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
+                       rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
+       }
+}
+
+static void
+clear_reference_bitmap (guint32 offset, guint32 size)
+{
+       int idx = (offset >> 24) - 1;
+       uintptr_t *rb;
+       rb = static_reference_bitmaps [idx];
+       offset &= 0xffffff;
+       offset /= sizeof (gpointer);
+       size /= sizeof (gpointer);
+       size += offset;
+       /* offset is now the bitmap offset */
+       for (; offset < size; ++offset)
+               rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
+}
+
 /*
  * The offset for a special static variable is composed of three parts:
  * a bit that indicates the type of static data (0:thread, 1:context),
@@ -3657,11 +3697,10 @@ search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32
  */
 
 guint32
-mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
+mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int max_set)
 {
        guint32 offset;
-       if (static_type == SPECIAL_STATIC_THREAD)
-       {
+       if (static_type == SPECIAL_STATIC_THREAD) {
                MonoThreadDomainTls *item;
                mono_threads_lock ();
                item = search_tls_slot_in_freelist (&thread_static_info, size, align);
@@ -3672,13 +3711,12 @@ mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align
                } else {
                        offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
                }
+               update_tls_reference_bitmap (offset, bitmap, max_set);
                /* This can be called during startup */
                if (threads != NULL)
                        mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
                mono_threads_unlock ();
-       }
-       else
-       {
+       } else {
                g_assert (static_type == SPECIAL_STATIC_CONTEXT);
                mono_contexts_lock ();
                offset = mono_alloc_static_data_slot (&context_static_info, size, align);
@@ -3689,7 +3727,7 @@ mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align
 }
 
 gpointer
-mono_get_special_static_data (guint32 offset)
+mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
 {
        /* The high bit means either thread (0) or static (1) data. */
 
@@ -3700,7 +3738,7 @@ mono_get_special_static_data (guint32 offset)
        idx = (offset >> 24) - 1;
 
        if (static_type == 0) {
-               return get_thread_static_data (mono_thread_internal_current (), offset);
+               return get_thread_static_data (thread, offset);
        } else {
                /* Allocate static data block under demand, since we don't have a list
                // of contexts
@@ -3708,13 +3746,19 @@ mono_get_special_static_data (guint32 offset)
                MonoAppContext *context = mono_context_get ();
                if (!context->static_data || !context->static_data [idx]) {
                        mono_contexts_lock ();
-                       mono_alloc_static_data (&(context->static_data), offset);
+                       mono_alloc_static_data (&(context->static_data), offset, FALSE);
                        mono_contexts_unlock ();
                }
                return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
        }
 }
 
+gpointer
+mono_get_special_static_data (guint32 offset)
+{
+       return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
+}
+
 typedef struct {
        guint32 offset;
        guint32 size;
@@ -3749,12 +3793,19 @@ do_free_special (gpointer key, gpointer value, gpointer data)
                MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
                data.offset = offset & 0x7fffffff;
                data.size = size;
+               clear_reference_bitmap (data.offset, data.size);
                if (threads != NULL)
                        mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
                item->offset = offset;
                item->size = size;
-               item->next = thread_static_info.freelist;
-               thread_static_info.freelist = item;
+
+               if (!mono_runtime_is_shutting_down ()) {
+                       item->next = thread_static_info.freelist;
+                       thread_static_info.freelist = item;
+               } else {
+                       /* We could be called during shutdown after mono_thread_cleanup () is called */
+                       g_free (item);
+               }
        } else {
                /* FIXME: free context static data as well */
        }
@@ -3832,7 +3883,7 @@ mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
        }
 }
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
 static void CALLBACK dummy_apc (ULONG_PTR param)
 {
 }
@@ -3860,7 +3911,7 @@ static MonoException* mono_thread_execute_interruption (MonoInternalThread *thre
                /* this will consume pending APC calls */
                WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
                InterlockedDecrement (&thread_interruption_requested);
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
                /* Clear the interrupted flag of the thread so it can wait again */
                wapi_clear_interruption ();
 #endif
@@ -3950,7 +4001,7 @@ mono_thread_request_interruption (gboolean running_managed)
        if (thread == NULL) 
                return NULL;
 
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        if (thread->interrupt_on_stop && 
                thread->state & ThreadState_StopRequested && 
                thread->state & ThreadState_Background)
@@ -3983,6 +4034,37 @@ mono_thread_request_interruption (gboolean running_managed)
        }
 }
 
+/*This function should be called by a thread after it has exited all of
+ * its handle blocks at interruption time.*/
+MonoException*
+mono_thread_resume_interruption (void)
+{
+       MonoInternalThread *thread = mono_thread_internal_current ();
+       gboolean still_aborting;
+
+       /* The thread may already be stopping */
+       if (thread == NULL)
+               return NULL;
+
+       ensure_synch_cs_set (thread);
+       EnterCriticalSection (thread->synch_cs);
+       still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
+       LeaveCriticalSection (thread->synch_cs);
+
+       /*This can happen if the protected block called Thread::ResetAbort*/
+       if (!still_aborting)
+               return FALSE;
+
+       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+               return NULL;
+       InterlockedIncrement (&thread_interruption_requested);
+
+#ifndef HOST_WIN32
+       wapi_self_interrupt ();
+#endif
+       return mono_thread_execute_interruption (thread);
+}
+
 gboolean mono_thread_interruption_requested ()
 {
        if (thread_interruption_requested) {
@@ -4101,7 +4183,7 @@ gint32* mono_thread_interruption_request_flag ()
 void 
 mono_thread_init_apartment_state (void)
 {
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        MonoInternalThread* thread = mono_thread_internal_current ();
 
        /* Positive return value indicates success, either
@@ -4121,7 +4203,7 @@ mono_thread_init_apartment_state (void)
 void 
 mono_thread_cleanup_apartment_state (void)
 {
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
        MonoInternalThread* thread = mono_thread_internal_current ();
 
        if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
@@ -4217,3 +4299,35 @@ mono_runtime_has_tls_get (void)
 {
        return has_tls_get;
 }
+
+int
+mono_thread_kill (MonoInternalThread *thread, int signal)
+{
+#ifdef HOST_WIN32
+       /* Win32 uses QueueUserAPC and callers of this are guarded */
+       g_assert_not_reached ();
+#else
+#  ifdef PTHREAD_POINTER_ID
+       return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
+#  else
+#    ifdef PLATFORM_ANDROID
+       if (thread->android_tid != 0) {
+               int  ret;
+               int  old_errno = errno;
+
+               ret = tkill ((pid_t) thread->android_tid, signal);
+               if (ret < 0) {
+                       ret = errno;
+                       errno = old_errno;
+               }
+
+               return ret;
+       }
+       else
+               return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
+#    else
+       return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
+#    endif
+#  endif
+#endif
+}