#include <config.h>
#include <glib.h>
-#include <signal.h>
#include <string.h>
#include <mono/metadata/object.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/runtime.h>
#include <mono/io-layer/io-layer.h>
-#ifndef HOST_WIN32
-#include <mono/io-layer/threads.h>
-#endif
#include <mono/metadata/object-internals.h>
#include <mono/metadata/mono-debug-debugger.h>
#include <mono/utils/mono-compiler.h>
#include <mono/metadata/gc-internal.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
+#define USE_TKILL_ON_ANDROID 1
+#endif
+
#ifdef PLATFORM_ANDROID
#include <errno.h>
+#ifdef USE_TKILL_ON_ANDROID
extern int tkill (pid_t tid, int signal);
#endif
+#endif
/*#define THREAD_DEBUG(a) do { a; } while (0)*/
#define THREAD_DEBUG(a)
info = mono_thread_info_current ();
g_assert (info);
internal->thread_info = info;
-
+ internal->small_id = info->small_id;
tid=internal->tid;
SET_CURRENT_OBJECT (internal);
- mono_monitor_init_tls ();
-
/* Every thread references the appdomain which created it */
mono_thread_push_appdomain_ref (domain);
info = mono_thread_info_current ();
g_assert (info);
thread->thread_info = info;
+ thread->small_id = info->small_id;
current_thread = new_thread_with_internal (domain, thread);
SET_CURRENT_OBJECT (thread);
mono_domain_set (domain, TRUE);
- mono_monitor_init_tls ();
-
thread_adjust_static_data (thread);
init_root_domain_thread (thread, current_thread);
if ((internal->state & ThreadState_Unstarted) == 0) {
UNLOCK_THREAD (internal);
- mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
+ mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
return NULL;
}
}
}
-void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
+void
+ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
{
guint32 res;
MonoInternalThread *thread = mono_thread_internal_current ();
{
LOCK_THREAD (this_obj);
- if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
+ if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
UNLOCK_THREAD (this_obj);
mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
return;
}
+ if (this_obj->name) {
+ g_free (this_obj->name);
+ 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);
mono_thread_set_name_internal (this_obj, name, TRUE);
}
+int
+ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
+{
+ return ThreadPriority_Lowest;
+}
+
+void
+ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
+{
+}
+
/* If the array is already in the requested domain, we just return it,
otherwise we return a copy in that domain. */
static MonoArray*
return res;
}
-gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
- int ms, HANDLE thread)
+gboolean
+ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
+ int ms, HANDLE thread)
{
MonoInternalThread *cur_thread = mono_thread_internal_current ();
gboolean ret;
if ((this->state & ThreadState_Unstarted) != 0) {
UNLOCK_THREAD (this);
- mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
+ mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
return FALSE;
}
return InterlockedCompareExchange(location, value, comparand);
}
+gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
+{
+ gint32 r = InterlockedCompareExchange(location, value, comparand);
+ *success = r == comparand;
+ return r;
+}
+
MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
{
MonoObject *res;
int
mono_thread_get_abort_signal (void)
{
-#ifdef HOST_WIN32
+#if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
return -1;
#elif defined(PLATFORM_ANDROID)
return SIGUNUSED;
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
- wait_handle = wapi_prepare_interrupt_thread (thread->handle);
+ wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
/* fixme: store the state somewhere */
mono_thread_kill (thread, mono_thread_get_abort_signal ());
- wapi_finish_interrupt_thread (wait_handle);
+ mono_thread_info_finish_interrupt (wait_handle);
#endif /* HOST_WIN32 */
}
if (!was_aborting) {
const char *msg = "Unable to reset abort because no abort was requested";
- mono_raise_exception (mono_get_exception_thread_state (msg));
+ mono_set_pending_exception (mono_get_exception_thread_state (msg));
+ return;
}
thread->abort_exc = NULL;
if (thread->abort_state_handle) {
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);
- mono_raise_exception (invalid_op_exc);
+ mono_set_pending_exception (invalid_op_exc);
+ return NULL;
}
return deserialized;
void
ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
{
- if (!mono_thread_suspend (thread))
- mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
+ if (!mono_thread_suspend (thread)) {
+ mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
+ return;
+ }
}
static gboolean
void
ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
{
- if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
- mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
+ if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
+ mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
+ return;
+ }
}
static gboolean
* 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 HOST_WIN32
mono_thread_info_yield ();
-#endif
}
static void terminate_thread (gpointer key, gpointer value, gpointer user)
return FALSE;
}
-static void
-print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
+static SuspendThreadResult
+print_thread_dump (MonoThreadInfo *info, gpointer ud)
{
+ MonoInternalThread *thread = ud;
GString* text = g_string_new (0);
char *name;
GError *error = NULL;
#endif
#endif
- mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
- mono_thread_info_finish_suspend_and_resume (info);
+ mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
fprintf (stdout, "%s", text->str);
g_string_free (text, TRUE);
fflush (stdout);
+ return MonoResumeThread;
}
static void
dump_thread (gpointer key, gpointer value, gpointer user)
{
MonoInternalThread *thread = (MonoInternalThread *)value;
- MonoThreadInfo *info;
if (thread == mono_thread_internal_current ())
return;
We probably should loop a bit around trying to get it to either managed code
or WSJ state.
*/
- info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
-
- if (!info)
- return;
-
- print_thread_dump (thread, info);
+ mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
}
void
printf ("Full thread dump:\n");
- /*
- * Make a copy of the hashtable since we can't do anything with
- * threads while threads_mutex is held.
- */
+ /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
+ something needs then in the process.
+ */
+ mono_loader_lock ();
+ mono_domain_lock (mono_get_root_domain ());
+
mono_threads_lock ();
mono_g_hash_table_foreach (threads, dump_thread, NULL);
mono_threads_unlock ();
+ mono_domain_unlock (mono_get_root_domain ());
+ mono_loader_unlock ();
+
thread_dump_requested = FALSE;
}
return tls_offset;
}
-void
-mono_thread_destroy_tls (uint32_t tls_offset)
+static void
+destroy_tls (MonoDomain *domain, uint32_t tls_offset)
{
MonoTlsDataRecord *prev = NULL;
MonoTlsDataRecord *cur;
guint32 size = 0;
- MonoDomain *domain = mono_domain_get ();
+
mono_domain_lock (domain);
cur = domain->tlsrec_list;
while (cur) {
mono_special_static_data_free_slot (tls_offset, size);
}
+void
+mono_thread_destroy_tls (uint32_t tls_offset)
+{
+ destroy_tls (mono_domain_get (), tls_offset);
+}
+
/*
* This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
*/
mono_thread_destroy_domain_tls (MonoDomain *domain)
{
while (domain->tlsrec_list)
- mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
+ destroy_tls (domain, domain->tlsrec_list->tls_offset);
}
static MonoClassField *local_slots = NULL;
* Performs the operation that the requested thread state requires (abort,
* suspend or stop)
*/
-static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
+static MonoException*
+mono_thread_execute_interruption (MonoInternalThread *thread)
{
LOCK_THREAD (thread);
WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
#endif
InterlockedDecrement (&thread_interruption_requested);
-#ifndef HOST_WIN32
/* Clear the interrupted flag of the thread so it can wait again */
- wapi_clear_interruption ();
-#endif
+ mono_thread_info_clear_interruption ();
}
if ((thread->state & ThreadState_AbortRequested) != 0) {
if (mono_thread_notify_pending_exc_fn && !running_managed)
/* The JIT will notify the thread about the interruption */
/* This shouldn't take any locks */
- mono_thread_notify_pending_exc_fn ();
+ mono_thread_notify_pending_exc_fn (NULL);
/* this will awake the thread if it is in WaitForSingleObject
or similar */
#ifdef HOST_WIN32
QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
#else
- wapi_self_interrupt ();
+ mono_thread_info_self_interrupt ();
#endif
return NULL;
}
return NULL;
InterlockedIncrement (&thread_interruption_requested);
-#ifndef HOST_WIN32
- wapi_self_interrupt ();
-#endif
+ mono_thread_info_self_interrupt ();
+
return mono_thread_execute_interruption (thread);
}
return FALSE;
}
-static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
+static MonoException*
+mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
{
MonoInternalThread *thread = mono_thread_internal_current ();
/* The thread may already be stopping */
if (thread == NULL)
- return;
+ return NULL;
if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
MonoException* exc = mono_thread_execute_interruption (thread);
- if (exc) mono_raise_exception (exc);
+ if (exc)
+ return exc;
}
+ return NULL;
}
/*
* Performs the interruption of the current thread, if one has been requested,
* and the thread is not running a protected wrapper.
+ * Return the exception which needs to be thrown, if any.
*/
-void mono_thread_interruption_checkpoint ()
+MonoException*
+mono_thread_interruption_checkpoint (void)
{
- mono_thread_interruption_checkpoint_request (FALSE);
+ return mono_thread_interruption_checkpoint_request (FALSE);
}
/*
* Performs the interruption of the current thread, if one has been requested.
+ * Return the exception which needs to be thrown, if any.
*/
-void mono_thread_force_interruption_checkpoint ()
+MonoException*
+mono_thread_force_interruption_checkpoint_noraise (void)
{
- mono_thread_interruption_checkpoint_request (TRUE);
+ return mono_thread_interruption_checkpoint_request (TRUE);
+}
+
+/*
+ * Performs the interruption of the current thread, if one has been requested.
+ * Throw the exception which needs to be thrown, if any.
+ */
+void
+mono_thread_force_interruption_checkpoint (void)
+{
+ MonoException *ex;
+
+ ex = mono_thread_interruption_checkpoint_request (TRUE);
+ if (ex)
+ mono_raise_exception (ex);
}
/*
/* Workaround pthread_kill abort() in NaCl glibc. */
return -1;
#endif
-#ifdef HOST_WIN32
+#if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
/* 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
+# ifdef USE_TKILL_ON_ANDROID
if (thread->android_tid != 0) {
int ret;
int old_errno = errno;
MonoThreadInfo *info = mono_thread_info_current ();
MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
- mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
+ mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
}
MonoJitInfo *ji = NULL;
if (!info)
return NULL;
- mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
+ mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
return ji;
}
-static void
-abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
+typedef struct {
+ MonoInternalThread *thread;
+ gboolean install_async_abort;
+ gpointer interrupt_handle;
+} AbortThreadData;
+
+static SuspendThreadResult
+abort_thread_critical (MonoThreadInfo *info, gpointer ud)
{
- MonoJitInfo *ji;
- MonoThreadInfo *info = NULL;
+ AbortThreadData *data = ud;
+ MonoInternalThread *thread = data->thread;
+ MonoJitInfo *ji = NULL;
gboolean protected_wrapper;
gboolean running_managed;
- if (!mono_thread_info_new_interrupt_enabled ()) {
- signal_thread_state_change (thread);
- return;
- }
-
- /*
- 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
- */
- if (thread == mono_thread_internal_current ()) {
- /* Do it synchronously */
- MonoException *exc = mono_thread_request_interruption (can_raise_exception);
- if (exc)
- mono_raise_exception (exc);
-#ifndef HOST_WIN32
- wapi_interrupt_thread (thread->handle);
-#endif
- return;
- }
-
- /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
- if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
- return;
- }
-
- if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
- mono_thread_info_finish_suspend_and_resume (info);
- return;
- }
+ if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
+ return MonoResumeThread;
/*someone is already interrupting it*/
- if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
- mono_thread_info_finish_suspend_and_resume (info);
- return;
- }
+ if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+ return MonoResumeThread;
+
InterlockedIncrement (&thread_interruption_requested);
ji = mono_thread_info_get_last_managed (info);
protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
- running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
+ running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
if (!protected_wrapper && running_managed) {
/*We are in managed code*/
/*Set the thread to call */
- if (install_async_abort)
+ if (data->install_async_abort)
mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
- mono_thread_info_finish_suspend_and_resume (info);
+ return MonoResumeThread;
} else {
+ if (mono_thread_notify_pending_exc_fn)
+ /* The JIT will notify the thread about the interruption */
+ mono_thread_notify_pending_exc_fn (info);
+
/*
* This will cause waits to be broken.
* It will also prevent the thread from entering a wait, so if the thread returns
* functions in the io-layer until the signal handler calls QueueUserAPC which will
* make it return.
*/
-#ifndef HOST_WIN32
- gpointer interrupt_handle;
- interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
-#endif
- mono_thread_info_finish_suspend_and_resume (info);
-#ifndef HOST_WIN32
- wapi_finish_interrupt_thread (interrupt_handle);
-#endif
+ data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ return MonoResumeThread;
}
- /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
}
static void
-transition_to_suspended (MonoInternalThread *thread, MonoThreadInfo *info)
+abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
{
- if ((thread->state & ThreadState_SuspendRequested) == 0) {
- g_assert (0); /*FIXME we should not reach this */
- /*Make sure we balance the suspend count.*/
- if (info)
- mono_thread_info_finish_suspend_and_resume (info);
- } else {
+ AbortThreadData data = { 0 };
+ data.thread = thread;
+ data.install_async_abort = install_async_abort;
+
+ if (!mono_thread_info_new_interrupt_enabled ()) {
+ signal_thread_state_change (thread);
+ return;
+ }
+
+ /*
+ 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
+ */
+ if (thread == mono_thread_internal_current ()) {
+ /* Do it synchronously */
+ MonoException *exc = mono_thread_request_interruption (can_raise_exception);
+ if (exc)
+ mono_raise_exception (exc);
+ mono_thread_info_interrupt (thread->handle);
+ return;
+ }
+
+ mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
+ if (data.interrupt_handle)
+ mono_thread_info_finish_interrupt (data.interrupt_handle);
+ /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
+}
+
+typedef struct{
+ MonoInternalThread *thread;
+ gboolean interrupt;
+ gpointer interrupt_handle;
+} SuspendThreadData;
+
+static SuspendThreadResult
+suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
+{
+ SuspendThreadData *data = ud;
+ MonoInternalThread *thread = data->thread;
+ MonoJitInfo *ji = NULL;
+ gboolean protected_wrapper;
+ gboolean running_managed;
+
+ ji = mono_thread_info_get_last_managed (info);
+ protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+ running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
+
+ if (running_managed && !protected_wrapper) {
thread->state &= ~ThreadState_SuspendRequested;
thread->state |= ThreadState_Suspended;
- if (info)
- mono_thread_info_finish_suspend (info);
+ return KeepSuspended;
+ } else {
+ if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
+ InterlockedIncrement (&thread_interruption_requested);
+ if (data->interrupt)
+ data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+
+ if (mono_thread_notify_pending_exc_fn && !running_managed)
+ /* The JIT will notify the thread about the interruption */
+ mono_thread_notify_pending_exc_fn (info);
+ return MonoResumeThread;
}
- UNLOCK_THREAD (thread);
}
-
+
static void
suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
{
LOCK_THREAD (thread);
if (thread == mono_thread_internal_current ()) {
- transition_to_suspended (thread, NULL);
- mono_thread_info_self_suspend ();
+ mono_thread_info_begin_self_suspend ();
+ //XXX replace this with better named functions
+ thread->state &= ~ThreadState_SuspendRequested;
+ thread->state |= ThreadState_Suspended;
+ UNLOCK_THREAD (thread);
+ mono_thread_info_end_self_suspend ();
} else {
- MonoThreadInfo *info;
- MonoJitInfo *ji;
- gboolean protected_wrapper;
- gboolean running_managed;
-
- /*A null info usually means the thread is already dead. */
- if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
- UNLOCK_THREAD (thread);
- return;
- }
-
- ji = mono_thread_info_get_last_managed (info);
- protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
- running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
-
- if (running_managed && !protected_wrapper) {
- transition_to_suspended (thread, info);
- } else {
-#ifndef HOST_WIN32
- gpointer interrupt_handle;
-#endif
+ SuspendThreadData data = { 0 };
+ data.thread = thread;
+ data.interrupt = interrupt;
- if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
- InterlockedIncrement (&thread_interruption_requested);
-#ifndef HOST_WIN32
- if (interrupt)
- interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
-#endif
- mono_thread_info_finish_suspend_and_resume (info);
-#ifndef HOST_WIN32
- if (interrupt)
- wapi_finish_interrupt_thread (interrupt_handle);
-#endif
- UNLOCK_THREAD (thread);
- }
+ mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
+ if (data.interrupt_handle)
+ mono_thread_info_finish_interrupt (data.interrupt_handle);
+ UNLOCK_THREAD (thread);
}
}
return;
}
- transition_to_suspended (thread, NULL);
- mono_thread_info_self_suspend ();
+ mono_thread_info_begin_self_suspend ();
+ thread->state &= ~ThreadState_SuspendRequested;
+ thread->state |= ThreadState_Suspended;
+ UNLOCK_THREAD (thread);
+ mono_thread_info_end_self_suspend ();
}
/*This is called with @thread synch_cs held and it must release it*/