[threads] Remove ThreadState_StopRequested (#4462)
[mono.git] / mono / metadata / threads.c
index 28b66c8eb3da13ed2d013971115376e0bbaf0628..57e1d9addf3d489102d8bab5e5219a1d1dcabd41 100644 (file)
@@ -29,7 +29,7 @@
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/runtime.h>
 #include <mono/metadata/object-internals.h>
-#include <mono/metadata/mono-debug-debugger.h>
+#include <mono/metadata/debug-internals.h>
 #include <mono/utils/monobitset.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-mmap.h>
@@ -114,14 +114,6 @@ typedef struct {
        StaticDataFreeList *freelist;
 } StaticDataInfo;
 
-/* Number of cached culture objects in the MonoThread->cached_culture_info array
- * (per-type): we use the first NUM entries for CultureInfo and the last for
- * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
- */
-#define NUM_CACHED_CULTURES 4
-#define CULTURES_START_IDX 0
-#define UICULTURES_START_IDX NUM_CACHED_CULTURES
-
 /* Controls access to the 'threads' hash table */
 static void mono_threads_lock (void);
 static void mono_threads_unlock (void);
@@ -656,7 +648,7 @@ static void
 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
 
 static gboolean
-mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
+mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
 {
        MonoThreadInfo *info;
        MonoInternalThread *internal;
@@ -674,7 +666,6 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean
        internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
        internal->thread_info = info;
        internal->small_id = info->small_id;
-       internal->stack_ptr = stack_ptr;
 
        THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
 
@@ -695,11 +686,11 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean
 
        if (shutting_down && !force_attach) {
                mono_threads_unlock ();
+               mono_thread_pop_appdomain_ref ();
                return FALSE;
        }
 
        if (!threads) {
-               MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
                threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
        }
 
@@ -742,6 +733,7 @@ typedef struct {
        MonoObject *start_delegate_arg;
        MonoThreadStart start_func;
        gpointer start_func_arg;
+       gboolean force_attach;
        gboolean failed;
        MonoCoopSem registered;
 } StartInfo;
@@ -768,7 +760,7 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack
 
        THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
 
-       if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
+       if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
                start_info->failed = TRUE;
 
                mono_coop_sem_post (&start_info->registered);
@@ -881,11 +873,25 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack
        return(0);
 }
 
-static gsize WINAPI start_wrapper(void *data)
+static gsize WINAPI
+start_wrapper (gpointer data)
 {
-       volatile gsize dummy;
+       StartInfo *start_info;
+       MonoThreadInfo *info;
+       gsize res;
+
+       start_info = (StartInfo*) data;
+       g_assert (start_info);
+
+       info = mono_thread_info_attach (&res);
+       info->runtime_thread = TRUE;
+
+       /* Run the actual main function of the thread */
+       res = start_wrapper_internal (start_info, &res);
+
+       mono_thread_info_exit (res);
 
-       return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
+       g_assert_not_reached ();
 }
 
 /*
@@ -896,10 +902,9 @@ static gsize WINAPI start_wrapper(void *data)
  */
 static gboolean
 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
-       gboolean threadpool_thread, guint32 stack_size, MonoError *error)
+       MonoThreadCreateFlags flags, MonoError *error)
 {
        StartInfo *start_info = NULL;
-       MonoThreadHandle *thread_handle;
        MonoNativeThreadId tid;
        gboolean ret;
        gsize stack_set_size;
@@ -909,30 +914,40 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *sta
        if (start_func)
                g_assert (!start_delegate);
 
+       if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
+               g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
+               g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
+       }
+       if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
+               g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
+               g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
+       }
+
        /*
         * Join joinable threads to prevent running out of threads since the finalizer
         * thread might be blocked/backlogged.
         */
        mono_threads_join_threads ();
 
-       mono_error_init (error);
+       error_init (error);
 
        mono_threads_lock ();
-       if (shutting_down) {
+       if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
                mono_threads_unlock ();
                return FALSE;
        }
        if (threads_starting_up == NULL) {
-               MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
                threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
        }
        mono_g_hash_table_insert (threads_starting_up, thread, thread);
        mono_threads_unlock ();
 
-       internal->threadpool_thread = threadpool_thread;
-       if (threadpool_thread)
+       internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
+       if (internal->threadpool_thread)
                mono_thread_set_state (internal, ThreadState_Background);
 
+       internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
+
        start_info = g_new0 (StartInfo, 1);
        start_info->ref = 2;
        start_info->thread = thread;
@@ -940,17 +955,16 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *sta
        start_info->start_delegate_arg = thread->start_obj;
        start_info->start_func = start_func;
        start_info->start_func_arg = start_func_arg;
+       start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
        start_info->failed = FALSE;
        mono_coop_sem_init (&start_info->registered, 0);
 
-       if (stack_size == 0)
+       if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
                stack_set_size = default_stacksize_for_thread (internal);
        else
                stack_set_size = 0;
 
-       thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
-
-       if (thread_handle == NULL) {
+       if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
                /* The thread couldn't be created, so set an exception */
                mono_threads_lock ();
                mono_g_hash_table_remove (threads_starting_up, thread);
@@ -975,8 +989,6 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *sta
 
        mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
 
-       mono_threads_close_thread_handle (thread_handle);
-
        THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
 
        ret = !start_info->failed;
@@ -1013,13 +1025,13 @@ guint32 mono_threads_get_default_stacksize (void)
  *   ARG should not be a GC reference.
  */
 MonoInternalThread*
-mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
+mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
 {
        MonoThread *thread;
        MonoInternalThread *internal;
        gboolean res;
 
-       mono_error_init (error);
+       error_init (error);
 
        internal = create_internal_thread_object ();
 
@@ -1027,11 +1039,11 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gb
 
        LOCK_THREAD (internal);
 
-       res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
-       return_val_if_nok (error, NULL);
+       res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
 
        UNLOCK_THREAD (internal);
 
+       return_val_if_nok (error, NULL);
        return internal;
 }
 
@@ -1046,7 +1058,7 @@ mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
 gboolean
 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
 {
-       return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
+       return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
 }
 
 MonoThread *
@@ -1062,6 +1074,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
 {
        MonoInternalThread *internal;
        MonoThread *thread;
+       MonoThreadInfo *info;
        MonoNativeThreadId tid;
        gsize stack_ptr;
 
@@ -1072,9 +1085,8 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
                return mono_thread_current ();
        }
 
-       if (!mono_gc_register_thread (&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.", mono_native_thread_id_get ());
-       }
+       info = mono_thread_info_attach (&stack_ptr);
+       g_assert (info);
 
        tid=mono_native_thread_id_get ();
 
@@ -1082,7 +1094,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
 
        thread = create_thread_object (domain, internal);
 
-       if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
+       if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
                /* Mono is shutting down, so just wait for the end */
                for (;;)
                        mono_thread_info_sleep (10000, NULL);
@@ -1131,17 +1143,6 @@ mono_thread_detach_internal (MonoInternalThread *thread)
        thread->abort_exc = NULL;
        thread->current_appcontext = NULL;
 
-       /*
-        * This is necessary because otherwise we might have
-        * cross-domain references which will not get cleaned up when
-        * the target domain is unloaded.
-        */
-       if (thread->cached_culture_info) {
-               int i;
-               for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
-                       mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
-       }
-
        /*
         * thread->synch_cs can be NULL if this was called after
         * ves_icall_System_Threading_InternalThread_Thread_free_internal.
@@ -1232,8 +1233,6 @@ mono_thread_detach_internal (MonoInternalThread *thread)
        if (thread == mono_thread_internal_current ())
                mono_thread_pop_appdomain_ref ();
 
-       thread->cached_culture_info = NULL;
-
        mono_free_static_data (thread->static_data);
        thread->static_data = NULL;
        ref_stack_destroy (thread->appdomain_refs);
@@ -1367,7 +1366,7 @@ ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
                return this_obj;
        }
 
-       res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
+       res = create_thread (this_obj, internal, start, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
        if (!res) {
                mono_error_cleanup (&error);
                UNLOCK_THREAD (internal);
@@ -1551,7 +1550,7 @@ ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj
        MonoError error;
        MonoString* str;
 
-       mono_error_init (&error);
+       error_init (&error);
 
        LOCK_THREAD (this_obj);
        
@@ -1569,13 +1568,15 @@ ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj
 }
 
 void 
-mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
+mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error)
 {
        LOCK_THREAD (this_obj);
 
-       mono_error_init (error);
+       error_init (error);
 
-       if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
+       if (reset) {
+               this_obj->flags &= ~MONO_THREAD_FLAG_NAME_SET;
+       } else if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
                UNLOCK_THREAD (this_obj);
                
                mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
@@ -1586,8 +1587,7 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g
                this_obj->name_len = 0;
        }
        if (name) {
-               this_obj->name = g_new (gunichar2, mono_string_length (name));
-               memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
+               this_obj->name = g_memdup (mono_string_chars (name), mono_string_length (name) * sizeof (gunichar2));
                this_obj->name_len = mono_string_length (name);
 
                if (permanent)
@@ -1612,7 +1612,7 @@ void
 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
 {
        MonoError error;
-       mono_thread_set_name_internal (this_obj, name, TRUE, &error);
+       mono_thread_set_name_internal (this_obj, name, TRUE, FALSE, &error);
        mono_error_set_pending_exception (&error);
 }
 
@@ -1662,7 +1662,7 @@ byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
 {
        MonoArray *copy;
 
-       mono_error_init (error);
+       error_init (error);
        if (!arr)
                return NULL;
 
@@ -1743,7 +1743,7 @@ mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError
        gint32 diff_ms;
        gint32 wait = ms;
 
-       mono_error_init (error);
+       error_init (error);
 
        start = (ms == -1) ? 0 : mono_msec_ticks ();
        for (;;) {
@@ -1852,7 +1852,7 @@ mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointe
        gint32 diff_ms;
        gint32 wait = ms;
 
-       mono_error_init (error);
+       error_init (error);
 
        start = (ms == -1) ? 0 : mono_100ns_ticks ();
        do {
@@ -2352,9 +2352,7 @@ request_thread_abort (MonoInternalThread *thread, MonoObject *state)
 {
        LOCK_THREAD (thread);
        
-       if ((thread->state & ThreadState_AbortRequested) != 0 || 
-               (thread->state & ThreadState_StopRequested) != 0 ||
-               (thread->state & ThreadState_Stopped) != 0)
+       if (thread->state & (ThreadState_AbortRequested | ThreadState_Stopped))
        {
                UNLOCK_THREAD (thread);
                return FALSE;
@@ -2506,17 +2504,13 @@ mono_thread_suspend (MonoInternalThread *thread)
 {
        LOCK_THREAD (thread);
 
-       if ((thread->state & ThreadState_Unstarted) != 0 || 
-               (thread->state & ThreadState_Aborted) != 0 || 
-               (thread->state & ThreadState_Stopped) != 0)
+       if (thread->state & (ThreadState_Unstarted | ThreadState_Aborted | ThreadState_Stopped))
        {
                UNLOCK_THREAD (thread);
                return FALSE;
        }
 
-       if ((thread->state & ThreadState_Suspended) != 0 || 
-               (thread->state & ThreadState_SuspendRequested) != 0 ||
-               (thread->state & ThreadState_StopRequested) != 0) 
+       if (thread->state & (ThreadState_Suspended | ThreadState_SuspendRequested | ThreadState_AbortRequested))
        {
                UNLOCK_THREAD (thread);
                return TRUE;
@@ -2630,53 +2624,14 @@ is_running_protected_wrapper (void)
        return found;
 }
 
-static gboolean
-request_thread_stop (MonoInternalThread *thread)
-{
-       LOCK_THREAD (thread);
-
-       if ((thread->state & ThreadState_StopRequested) != 0 ||
-               (thread->state & ThreadState_Stopped) != 0)
-       {
-               UNLOCK_THREAD (thread);
-               return FALSE;
-       }
-       
-       /* Make sure the thread is awake */
-       mono_thread_resume (thread);
-
-       thread->state |= ThreadState_StopRequested;
-       thread->state &= ~ThreadState_AbortRequested;
-       
-       UNLOCK_THREAD (thread);
-       return TRUE;
-}
-
-/**
- * mono_thread_internal_stop:
- *
- * Request thread @thread to stop.
- *
- * @thread MUST NOT be the current thread.
- */
 void
-mono_thread_internal_stop (MonoInternalThread *thread)
-{
-       g_assert (thread != mono_thread_internal_current ());
-
-       if (!request_thread_stop (thread))
-               return;
-       
-       async_abort_internal (thread, TRUE);
-}
-
-void mono_thread_stop (MonoThread *thread)
+mono_thread_stop (MonoThread *thread)
 {
        MonoInternalThread *internal = thread->internal_thread;
 
-       if (!request_thread_stop (internal))
+       if (!request_thread_abort (internal, NULL))
                return;
-       
+
        if (internal == mono_thread_internal_current ()) {
                MonoError error;
                self_abort_internal (&error);
@@ -3209,22 +3164,21 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
        if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
                return FALSE;
 
-       /* The finalizer thread is not a background thread */
-       if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
-            && (thread->state & ThreadState_Background) != 0
-            && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
-       ) {
+       if (mono_native_thread_id_equals (thread_get_tid (thread), self))
+               return FALSE;
+       if (mono_gc_is_finalizer_internal_thread (thread))
+               return FALSE;
+
+       if ((thread->state & ThreadState_Background) && !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
                wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
                wait->threads[wait->num] = thread;
                wait->num++;
 
                THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
                mono_thread_internal_abort (thread);
-               return TRUE;
        }
 
-       return !mono_native_thread_id_equals (thread_get_tid (thread), self)
-               && !mono_gc_is_finalizer_internal_thread (thread);
+       return TRUE;
 }
 
 /** 
@@ -3248,13 +3202,10 @@ mono_threads_set_shutting_down (void)
 
                LOCK_THREAD (current_thread);
 
-               if ((current_thread->state & ThreadState_SuspendRequested) ||
-                   (current_thread->state & ThreadState_AbortRequested) ||
-                   (current_thread->state & ThreadState_StopRequested)) {
+               if (current_thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
                        UNLOCK_THREAD (current_thread);
                        mono_thread_execute_interruption ();
                } else {
-                       current_thread->state |= ThreadState_Stopped;
                        UNLOCK_THREAD (current_thread);
                }
 
@@ -3437,9 +3388,7 @@ void mono_thread_suspend_all_other_threads (void)
 
                        LOCK_THREAD (thread);
 
-                       if ((thread->state & ThreadState_Suspended) != 0 || 
-                               (thread->state & ThreadState_StopRequested) != 0 ||
-                               (thread->state & ThreadState_Stopped) != 0) {
+                       if (thread->state & (ThreadState_Suspended | ThreadState_Stopped)) {
                                UNLOCK_THREAD (thread);
                                mono_threads_close_thread_handle (wait->handles [i]);
                                wait->threads [i] = NULL;
@@ -3662,7 +3611,7 @@ mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_fra
        MonoDebugSourceLocation *location;
        int tindex, nthreads;
 
-       mono_error_init (error);
+       error_init (error);
        
        *out_threads = NULL;
        *out_stack_frames = NULL;
@@ -3961,39 +3910,6 @@ mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
        return TRUE;
 }
 
-static void
-clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
-{
-       MonoInternalThread *thread = (MonoInternalThread*)value;
-       MonoDomain *domain = (MonoDomain*)user_data;
-       int i;
-
-       /* No locking needed here */
-       /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
-
-       if (thread->cached_culture_info) {
-               for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
-                       MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
-                       if (obj && obj->vtable->domain == domain)
-                               mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
-               }
-       }
-}
-       
-/*
- * mono_threads_clear_cached_culture:
- *
- *   Clear the cached_current_culture from all threads if it is in the
- * given appdomain.
- */
-void
-mono_threads_clear_cached_culture (MonoDomain *domain)
-{
-       mono_threads_lock ();
-       mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
-       mono_threads_unlock ();
-}
-
 /*
  * mono_thread_get_undeniable_exception:
  *
@@ -4486,7 +4402,7 @@ mono_thread_execute_interruption (void)
 
                UNLOCK_THREAD (thread);
                return exc;
-       } else if ((thread->state & ThreadState_AbortRequested) != 0) {
+       } else if (thread->state & (ThreadState_AbortRequested)) {
                UNLOCK_THREAD (thread);
                g_assert (sys_thread->pending_exception == NULL);
                if (thread->abort_exc == NULL) {
@@ -4497,19 +4413,10 @@ mono_thread_execute_interruption (void)
                        MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
                }
                return thread->abort_exc;
-       }
-       else if ((thread->state & ThreadState_SuspendRequested) != 0) {
+       } else if (thread->state & (ThreadState_SuspendRequested)) {
                /* calls UNLOCK_THREAD (thread) */
                self_suspend_internal ();
                return NULL;
-       }
-       else if ((thread->state & ThreadState_StopRequested) != 0) {
-               /* FIXME: do this through the JIT? */
-
-               UNLOCK_THREAD (thread);
-               
-               mono_thread_exit ();
-               return NULL;
        } else if (thread->thread_interrupt_requested) {
 
                thread->thread_interrupt_requested = FALSE;
@@ -4540,12 +4447,6 @@ mono_thread_request_interruption (gboolean running_managed)
        if (thread == NULL) 
                return NULL;
 
-#ifdef HOST_WIN32
-       if (thread->interrupt_on_stop && 
-               thread->state & ThreadState_StopRequested && 
-               thread->state & ThreadState_Background)
-               ExitThread (1);
-#endif
        if (!mono_thread_set_interruption_requested (thread))
                return NULL;
        InterlockedIncrement (&thread_interruption_requested);
@@ -4583,7 +4484,7 @@ mono_thread_resume_interruption (void)
                return NULL;
 
        LOCK_THREAD (thread);
-       still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
+       still_aborting = (thread->state & (ThreadState_AbortRequested)) != 0;
        UNLOCK_THREAD (thread);
 
        /*This can happen if the protected block called Thread::ResetAbort*/
@@ -4845,13 +4746,6 @@ async_abort_critical (MonoThreadInfo *info, gpointer ud)
        if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
                return MonoResumeThread;
 
-       /*
-       The target thread is running at least one protected block, which must not be interrupted, so we give up.
-       The protected block code will give them a chance when appropriate.
-       */
-       if (mono_thread_get_abort_prot_block_count (thread) > 0)
-               return MonoResumeThread;
-
        /*someone is already interrupting it*/
        if (!mono_thread_set_interruption_requested (thread))
                return MonoResumeThread;
@@ -4904,7 +4798,7 @@ self_abort_internal (MonoError *error)
 {
        MonoException *exc;
 
-       mono_error_init (error);
+       error_init (error);
 
        /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
         * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
@@ -5002,11 +4896,33 @@ self_suspend_internal (void)
        event = thread->suspended;
 
        MONO_ENTER_GC_SAFE;
-       res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
+       res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
        g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
        MONO_EXIT_GC_SAFE;
 }
 
+static void
+suspend_for_shutdown_async_call (gpointer unused)
+{
+       for (;;)
+               mono_thread_info_yield ();
+}
+
+static SuspendThreadResult
+suspend_for_shutdown_critical (MonoThreadInfo *info, gpointer unused)
+{
+       mono_thread_info_setup_async_call (info, suspend_for_shutdown_async_call, NULL);
+       return MonoResumeThread;
+}
+
+void
+mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
+{
+       g_assert (thread != mono_thread_internal_current ());
+
+       mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
+}
+
 /*
  * mono_thread_is_foreign:
  * @thread: the thread to query
@@ -5085,7 +5001,9 @@ mono_threads_join_threads (void)
                        if (thread != pthread_self ()) {
                                MONO_ENTER_GC_SAFE;
                                /* This shouldn't block */
+                               mono_threads_join_lock ();
                                mono_native_thread_join (thread);
+                               mono_threads_join_unlock ();
                                MONO_EXIT_GC_SAFE;
                        }
                } else {
@@ -5126,13 +5044,6 @@ mono_thread_join (gpointer tid)
 #endif
 }
 
-void
-mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
-{
-       if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
-               mono_thread_interruption_checkpoint ();
-}
-
 void
 mono_thread_internal_unhandled_exception (MonoObject* exc)
 {
@@ -5279,7 +5190,7 @@ mono_threads_is_ready_to_be_interrupted (void)
 
        thread = mono_thread_internal_current ();
        LOCK_THREAD (thread);
-       if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
+       if (thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
                UNLOCK_THREAD (thread);
                return FALSE;
        }