Merge pull request #3038 from lambdageek/dev/monoerror-threads
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Wed, 25 May 2016 14:36:20 +0000 (10:36 -0400)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Wed, 25 May 2016 14:36:20 +0000 (10:36 -0400)
[threadpool-ms] Assert if queuing work items fails in the IO selector

1  2 
mono/metadata/threads.c

diff --combined mono/metadata/threads.c
index c245f524eae9b6745d639d4dbc59d17b93df2b48,d7820a8a97f6195a1d31a0ffb671b5c630951e3b..cc6bbad33f8a8cf735194172a87deda93ebc1002
@@@ -81,6 -81,15 +81,6 @@@ extern int tkill (pid_t tid, int signal
  #define LOCK_THREAD(thread) lock_thread((thread))
  #define UNLOCK_THREAD(thread) unlock_thread((thread))
  
 -/* Provide this for systems with glib < 2.6 */
 -#ifndef G_GSIZE_FORMAT
 -#   if GLIB_SIZEOF_LONG == 8
 -#       define G_GSIZE_FORMAT "lu"
 -#   else
 -#       define G_GSIZE_FORMAT "u"
 -#   endif
 -#endif
 -
  typedef struct
  {
        guint32 (*func)(void *);
@@@ -197,7 -206,7 +197,7 @@@ static void mono_init_static_data_info 
  static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
  static gboolean mono_thread_resume (MonoInternalThread* thread);
  static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
 -static void self_abort_internal (void);
 +static void self_abort_internal (MonoError *error);
  static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
  static void self_suspend_internal (void);
  
@@@ -574,22 -583,21 +574,22 @@@ set_current_thread_for_domain (MonoDoma
  }
  
  static MonoThread*
 -create_thread_object (MonoDomain *domain, MonoError *error)
 +create_thread_object (MonoDomain *domain)
  {
 +      MonoError error;
        MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
 -      MonoThread *t = (MonoThread*)mono_object_new_mature (vt, error);
 +      MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
 +      /* only possible failure mode is OOM, from which we don't expect to recover. */
 +      mono_error_assert_ok (&error);
        return t;
  }
  
  static MonoThread*
 -new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal, MonoError *error)
 +new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
  {
        MonoThread *thread;
  
 -      thread = create_thread_object (domain, error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      thread = create_thread_object (domain);
  
        MONO_OBJECT_SETREF (thread, internal_thread, internal);
  
  }
  
  static MonoInternalThread*
 -create_internal_thread (MonoError *error)
 +create_internal_thread (void)
  {
 +      MonoError error;
        MonoInternalThread *thread;
        MonoVTable *vt;
  
        vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
 -      thread = (MonoInternalThread*) mono_object_new_mature (vt, error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
 +      /* only possible failure mode is OOM, from which we don't exect to recover */
 +      mono_error_assert_ok (&error);
  
        thread->synch_cs = g_new0 (MonoCoopMutex, 1);
        mono_coop_mutex_init_recursive (thread->synch_cs);
  }
  
  static gboolean
 -init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate, MonoError *error)
 +init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
  {
        MonoDomain *domain = mono_get_root_domain ();
  
 -      mono_error_init (error);
        if (!candidate || candidate->obj.vtable->domain != domain) {
 -              candidate = new_thread_with_internal (domain, thread, error);
 -              return_val_if_nok (error, FALSE);
 +              candidate = new_thread_with_internal (domain, thread);
        }
        set_current_thread_for_domain (domain, thread, candidate);
        g_assert (!thread->root_domain_thread);
@@@ -686,7 -695,8 +686,7 @@@ static guint32 WINAPI start_wrapper_int
        /* 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, start_info->obj, &error);
 -      mono_error_raise_exception (&error); /* FIXME don't raise here */
 +      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
@@@ -926,9 -936,11 +926,9 @@@ mono_thread_create_internal (MonoDomai
  
        mono_error_init (error);
  
 -      thread = create_thread_object (domain, error);
 -      return_val_if_nok (error, NULL);
 +      thread = create_thread_object (domain);
  
 -      internal = create_internal_thread (error);
 -      return_val_if_nok (error, NULL);
 +      internal = create_internal_thread ();
  
        MONO_OBJECT_SETREF (thread, internal_thread, internal);
  
@@@ -966,13 -978,15 +966,13 @@@ mono_thread_create_checked (MonoDomain 
  MonoThread *
  mono_thread_attach (MonoDomain *domain)
  {
 -      MonoError error;
 -      MonoThread *thread = mono_thread_attach_full (domain, FALSE, &error);
 -      mono_error_raise_exception (&error);
 +      MonoThread *thread = mono_thread_attach_full (domain, FALSE);
  
        return thread;
  }
  
  MonoThread *
 -mono_thread_attach_full (MonoDomain *domain, gboolean force_attach, MonoError *error)
 +mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
  {
        MonoThreadInfo *info;
        MonoInternalThread *thread;
        HANDLE thread_handle;
        MonoNativeThreadId tid;
  
 -      mono_error_init (error);
 -
        if ((thread = mono_thread_internal_current ())) {
                if (domain != mono_domain_get ())
                        mono_domain_set (domain, TRUE);
                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 ());
        }
  
 -      thread = create_internal_thread (error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      thread = create_internal_thread ();
  
        thread_handle = mono_thread_info_open_handle ();
        g_assert (thread_handle);
        thread->thread_info = info;
        thread->small_id = info->small_id;
  
 -      current_thread = new_thread_with_internal (domain, thread, error);
 -      if (!mono_error_ok (error))
 -              return NULL;
 +      current_thread = new_thread_with_internal (domain, thread);
  
        if (!handle_store (current_thread, force_attach)) {
                /* Mono is shutting down, so just wait for the end */
  
        thread_adjust_static_data (thread);
  
 -      init_root_domain_thread (thread, current_thread, error);
 -      return_val_if_nok (error, NULL);
 +      init_root_domain_thread (thread, current_thread);
  
        if (domain != mono_get_root_domain ())
                set_current_thread_for_domain (domain, thread, current_thread);
@@@ -1116,9 -1137,12 +1116,9 @@@ mono_thread_exit (
  void
  ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
  {
 -      MonoError error;
        MonoInternalThread *internal;
  
 -      internal = create_internal_thread (&error);
 -      if (mono_error_set_pending_exception (&error))
 -              return;
 +      internal = create_internal_thread ();
  
        internal->state = ThreadState_Unstarted;
  
@@@ -1213,8 -1237,7 +1213,8 @@@ ves_icall_System_Threading_Thread_Sleep
  
        THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
  
 -      mono_thread_current_check_pending_interrupt ();
 +      if (mono_thread_current_check_pending_interrupt ())
 +              return;
  
        while (TRUE) {
                gboolean alerted = FALSE;
@@@ -1477,6 -1500,7 +1477,6 @@@ ves_icall_System_Threading_Thread_ByteA
  MonoThread *
  mono_thread_current (void)
  {
 -      MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoInternalThread *internal = mono_thread_internal_current ();
        MonoThread **current_thread_ptr;
  
        if (!*current_thread_ptr) {
                g_assert (domain != mono_get_root_domain ());
 -              *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
 -              mono_error_raise_exception (&error); /* FIXME don't raise here */
 +              *current_thread_ptr = new_thread_with_internal (domain, internal);
        }
        return *current_thread_ptr;
  }
  static MonoThread *
  mono_thread_current_for_thread (MonoInternalThread *internal)
  {
 -      MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoThread **current_thread_ptr;
  
  
        if (!*current_thread_ptr) {
                g_assert (domain != mono_get_root_domain ());
 -              *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
 -              mono_error_raise_exception (&error); /* FIXME don't raise here */
 +              *current_thread_ptr = new_thread_with_internal (domain, internal);
        }
        return *current_thread_ptr;
  }
@@@ -1524,8 -1551,7 +1524,8 @@@ ves_icall_System_Threading_Thread_Join_
        MonoInternalThread *cur_thread = mono_thread_internal_current ();
        gboolean ret;
  
 -      mono_thread_current_check_pending_interrupt ();
 +      if (mono_thread_current_check_pending_interrupt ())
 +              return FALSE;
  
        LOCK_THREAD (thread);
        
        return(FALSE);
  }
  
 +#define MANAGED_WAIT_FAILED 0x7fffffff
 +
 +static gint32
 +map_native_wait_result_to_managed (gint32 val)
 +{
 +      /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
 +      return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
 +}
 +
  static gint32
 -mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
 +mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
  {
        MonoException *exc;
        guint32 ret;
        gint32 diff_ms;
        gint32 wait = ms;
  
 +      mono_error_init (error);
 +
        start = (ms == -1) ? 0 : mono_100ns_ticks ();
        do {
                MONO_ENTER_GC_SAFE;
 -                      if (multiple)
 -                      ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
 +              if (numhandles != 1)
 +                      ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
                else
 -                      ret = WaitForSingleObjectEx (handles [0], ms, alertable);
 +                      ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
                MONO_EXIT_GC_SAFE;
  
                if (ret != WAIT_IO_COMPLETION)
                        break;
  
                exc = mono_thread_execute_interruption ();
 -              if (exc)
 -                      mono_raise_exception (exc);
 +              if (exc) {
 +                      mono_error_set_exception_instance (error, exc);
 +                      break;
 +              }
  
                if (ms == -1)
                        continue;
  
  gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
  {
 +      MonoError error;
        HANDLE *handles;
        guint32 numhandles;
        guint32 ret;
        MonoInternalThread *thread = mono_thread_internal_current ();
  
        /* Do this WaitSleepJoin check before creating objects */
 -      mono_thread_current_check_pending_interrupt ();
 +      if (mono_thread_current_check_pending_interrupt ())
 +              return map_native_wait_result_to_managed (WAIT_FAILED);
  
        /* We fail in managed if the array has more than 64 elements */
        numhandles = (guint32)mono_array_length(mono_handles);
        }
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
 -      
 -      ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
 +
 +      ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
  
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
  
        g_free(handles);
  
 +      mono_error_set_pending_exception (&error);
 +
        /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
 -      return ret == WAIT_FAILED ? 0x7fffffff : ret;
 +      return map_native_wait_result_to_managed (ret);
  }
  
  gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
  {
 +      MonoError error;
        HANDLE handles [MAXIMUM_WAIT_OBJECTS];
        uintptr_t numhandles;
        guint32 ret;
        MonoInternalThread *thread = mono_thread_internal_current ();
  
        /* Do this WaitSleepJoin check before creating objects */
 -      mono_thread_current_check_pending_interrupt ();
 +      if (mono_thread_current_check_pending_interrupt ())
 +              return map_native_wait_result_to_managed (WAIT_FAILED);
  
        numhandles = mono_array_length(mono_handles);
        if (numhandles > MAXIMUM_WAIT_OBJECTS)
 -              return WAIT_FAILED;
 +              return map_native_wait_result_to_managed (WAIT_FAILED);
  
        for(i = 0; i < numhandles; i++) {       
                waitHandle = mono_array_get(mono_handles, MonoObject*, i);
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
  
 -      ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
 +      ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
  
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
  
        THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
  
 +      mono_error_set_pending_exception (&error);
        /*
         * These need to be here.  See MSDN dos on WaitForMultipleObjects.
         */
        if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
 -              return ret - WAIT_OBJECT_0;
 +              return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
        }
        else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
 -              return ret - WAIT_ABANDONED_0;
 +              return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
        }
        else {
                /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
 -              return ret == WAIT_FAILED ? 0x7fffffff : ret;
 +              return map_native_wait_result_to_managed (ret);
        }
  }
  
  gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
  {
 +      MonoError error;
        guint32 ret;
        MonoInternalThread *thread = mono_thread_internal_current ();
  
                ms=INFINITE;
        }
        
 -      mono_thread_current_check_pending_interrupt ();
 +      if (mono_thread_current_check_pending_interrupt ())
 +              return map_native_wait_result_to_managed (WAIT_FAILED);
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
        
 -      ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
 +      ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
        
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
 -      
 -      /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
 -      return ret == WAIT_FAILED ? 0x7fffffff : ret;
 +
 +      mono_error_set_pending_exception (&error);
 +      return map_native_wait_result_to_managed (ret);
  }
  
  gint32
@@@ -1741,8 -1745,7 +1741,8 @@@ ves_icall_System_Threading_WaitHandle_S
        if (ms == -1)
                ms = INFINITE;
  
 -      mono_thread_current_check_pending_interrupt ();
 +      if (mono_thread_current_check_pending_interrupt ())
 +              return map_native_wait_result_to_managed (WAIT_FAILED);
  
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
        
        
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
  
 -      /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
 -      return ret == WAIT_FAILED ? 0x7fffffff : ret;
 +      return map_native_wait_result_to_managed (ret);
  }
  
  HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
@@@ -2183,15 -2187,7 +2183,15 @@@ void ves_icall_System_Threading_Thread_
        }
  }
  
 -void mono_thread_current_check_pending_interrupt ()
 +/**
 + * mono_thread_current_check_pending_interrupt:
 + *
 + * Checks if there's a interruption request and set the pending exception if so.
 + *
 + * @returns true if a pending exception was set
 + */
 +gboolean
 +mono_thread_current_check_pending_interrupt (void)
  {
        MonoInternalThread *thread = mono_thread_internal_current ();
        gboolean throw_ = FALSE;
        
        UNLOCK_THREAD (thread);
  
 -      if (throw_) {
 -              mono_raise_exception (mono_get_exception_thread_interrupted ());
 -      }
 +      if (throw_)
 +              mono_set_pending_exception (mono_get_exception_thread_interrupted ());
 +      return throw_;
  }
  
 -void
 -ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
 +static gboolean
 +request_thread_abort (MonoInternalThread *thread, MonoObject *state)
  {
        LOCK_THREAD (thread);
        
                (thread->state & ThreadState_Stopped) != 0)
        {
                UNLOCK_THREAD (thread);
 -              return;
 +              return FALSE;
        }
  
        if ((thread->state & ThreadState_Unstarted) != 0) {
                thread->state |= ThreadState_Aborted;
                UNLOCK_THREAD (thread);
 -              return;
 +              return FALSE;
        }
  
        thread->state |= ThreadState_AbortRequested;
                mono_thread_resume (thread);
  
        UNLOCK_THREAD (thread);
 +      return TRUE;
 +}
  
 -      if (thread == mono_thread_internal_current ())
 -              self_abort_internal ();
 -      else
 +void
 +ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
 +{
 +      if (!request_thread_abort (thread, state))
 +              return;
 +
 +      if (thread == mono_thread_internal_current ()) {
 +              MonoError error;
 +              self_abort_internal (&error);
 +              mono_error_set_pending_exception (&error);
 +      } else {
                async_abort_internal (thread, TRUE);
 +      }
 +}
 +
 +/**
 + * mono_thread_internal_abort:
 + *
 + * Request thread @thread to be aborted.
 + *
 + * @thread MUST NOT be the current thread.
 + */
 +void
 +mono_thread_internal_abort (MonoInternalThread *thread)
 +{
 +      g_assert (thread != mono_thread_internal_current ());
 +
 +      if (!request_thread_abort (thread, NULL))
 +              return;
 +      async_abort_internal (thread, TRUE);
  }
  
  void
@@@ -2480,8 -2448,7 +2480,8 @@@ is_running_protected_wrapper (void
        return found;
  }
  
 -void mono_thread_internal_stop (MonoInternalThread *thread)
 +static gboolean
 +request_thread_stop (MonoInternalThread *thread)
  {
        LOCK_THREAD (thread);
  
                (thread->state & ThreadState_Stopped) != 0)
        {
                UNLOCK_THREAD (thread);
 -              return;
 +              return FALSE;
        }
        
        /* Make sure the thread is awake */
        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;
        
 -      if (thread == mono_thread_internal_current ())
 -              self_abort_internal ();
 -      else
 -              async_abort_internal (thread, TRUE);
 +      async_abort_internal (thread, TRUE);
  }
  
  void mono_thread_stop (MonoThread *thread)
  {
 -      mono_thread_internal_stop (thread->internal_thread);
 +      MonoInternalThread *internal = thread->internal_thread;
 +
 +      if (!request_thread_stop (internal))
 +              return;
 +      
 +      if (internal == mono_thread_internal_current ()) {
 +              MonoError error;
 +              self_abort_internal (&error);
 +              /*
 +              This function is part of the embeding API and has no way to return the exception
 +              to be thrown. So what we do is keep the old behavior and raise the exception.
 +              */
 +              mono_error_raise_exception (&error);
 +      } else {
 +              async_abort_internal (internal, TRUE);
 +      }
  }
  
  gint8
@@@ -3596,10 -3534,9 +3596,9 @@@ mono_threads_perform_thread_dump (void
  }
  
  /* Obtain the thread dump of all threads */
- static void
- mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
+ static gboolean
+ mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
  {
-       MonoError error;
  
        ThreadDumpUserData ud;
        MonoInternalThread *thread_array [128];
        MonoDebugSourceLocation *location;
        int tindex, nthreads;
  
-       mono_error_init (&error);
+       mono_error_init (error);
        
        *out_threads = NULL;
        *out_stack_frames = NULL;
        ud.frames = g_new0 (MonoStackFrameInfo, 256);
        ud.max_frames = 256;
  
-       *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, &error);
-       if (!is_ok (&error))
+       *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
+       if (!is_ok (error))
                goto leave;
-       *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, &error);
-       if (!is_ok (&error))
+       *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
+       if (!is_ok (error))
                goto leave;
  
        for (tindex = 0; tindex < nthreads; ++tindex) {
  
                mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
  
-               thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, &error);
-               if (!is_ok (&error))
+               thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
+               if (!is_ok (error))
                        goto leave;
                mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
  
                for (i = 0; i < ud.nframes; ++i) {
                        MonoStackFrameInfo *frame = &ud.frames [i];
                        MonoMethod *method = NULL;
-                       MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
-                       if (!mono_error_ok (&error))
+                       MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
+                       if (!is_ok (error))
                                goto leave;
  
                        sf->native_offset = frame->native_offset;
                        if (method) {
                                sf->method_address = (gsize) frame->ji->code_start;
  
-                               MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
-                               mono_error_raise_exception (&error); /* FIXME don't raise here */
+                               MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
+                               if (!is_ok (error))
+                                       goto leave;
                                MONO_OBJECT_SETREF (sf, method, rm);
  
                                location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
  
  leave:
        g_free (ud.frames);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       return is_ok (error);
  }
  
  /**
@@@ -3885,7 -3823,7 +3885,7 @@@ mono_threads_abort_appdomain_threads (M
                if (user_data.wait.num > 0) {
                        /* Abort the threads outside the threads lock */
                        for (i = 0; i < user_data.wait.num; ++i)
 -                              ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
 +                              mono_thread_internal_abort (user_data.wait.threads [i]);
  
                        /*
                         * We should wait for the threads either to abort, or to leave the
@@@ -4403,6 -4341,17 +4403,6 @@@ mono_alloc_special_static_data_free (GH
        mono_threads_unlock ();
  }
  
 -static void
 -mono_special_static_data_free_slot (guint32 offset, guint32 size)
 -{
 -      /* Only ever called for ThreadLocal instances */
 -      g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
 -
 -      mono_threads_lock ();
 -      do_free_special_slot (offset, size);
 -      mono_threads_unlock ();
 -}
 -
  #ifdef HOST_WIN32
  static void CALLBACK dummy_apc (ULONG_PTR param)
  {
@@@ -4831,20 -4780,18 +4831,20 @@@ async_abort_internal (MonoInternalThrea
  }
  
  static void
 -self_abort_internal (void)
 +self_abort_internal (MonoError *error)
  {
        MonoException *exc;
  
 +      mono_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 */
  
        exc = mono_thread_request_interruption (TRUE);
        if (exc)
 -              mono_raise_exception (exc);
 -
 -      mono_thread_info_self_interrupt ();
 +              mono_error_set_exception_instance (error, exc);
 +      else
 +              mono_thread_info_self_interrupt ();
  }
  
  typedef struct {
@@@ -5067,7 -5014,9 +5067,9 @@@ mono_thread_internal_unhandled_exceptio
  void
  ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
  {
-       mono_threads_get_thread_dump (out_threads, out_stack_traces);
+       MonoError error;
+       mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
+       mono_error_set_pending_exception (&error);
  }
  
  /*
  gpointer
  mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
  {
 -      MonoError error;
        MonoDomain *orig;
        gboolean fresh_thread;
  
        }
  
        if (!mono_thread_internal_current ()) {
 -              mono_thread_attach_full (domain, FALSE, &error);
 -              mono_error_assert_ok (&error);
 +              mono_thread_attach_full (domain, FALSE);
  
                // #678164
                mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);