#include <signal.h>
#endif
-#if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64)
+#if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
#define USE_TKILL_ON_ANDROID 1
#endif
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 ();
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, gboolean *success)
+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;
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;
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
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
* 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);
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.
+ */
+MonoException*
+mono_thread_interruption_checkpoint (void)
+{
+ 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_interruption_checkpoint ()
+MonoException*
+mono_thread_force_interruption_checkpoint_noraise (void)
{
- mono_thread_interruption_checkpoint_request (FALSE);
+ 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
+mono_thread_force_interruption_checkpoint (void)
{
- mono_thread_interruption_checkpoint_request (TRUE);
+ 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
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);
- mono_thread_info_interrupt (thread->handle);
- 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.
*/
- gpointer interrupt_handle;
+ data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+ return MonoResumeThread;
+ }
+}
- if (mono_thread_notify_pending_exc_fn)
- /* The JIT will notify the thread about the interruption */
- mono_thread_notify_pending_exc_fn (info);
+static void
+abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
+{
+ AbortThreadData data = { 0 };
+ data.thread = thread;
+ data.install_async_abort = install_async_abort;
- interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
- mono_thread_info_finish_suspend_and_resume (info);
- mono_thread_info_finish_interrupt (interrupt_handle);
+ 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*/
}
-static void
-transition_to_suspended (MonoInternalThread *thread, MonoThreadInfo *info)
+typedef struct{
+ MonoInternalThread *thread;
+ gboolean interrupt;
+ gpointer interrupt_handle;
+} SuspendThreadData;
+
+static SuspendThreadResult
+suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
{
- 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 {
+ 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;
- }
+ SuspendThreadData data = { 0 };
+ data.thread = thread;
+ data.interrupt = interrupt;
- 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 {
- gpointer interrupt_handle;
-
- if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
- InterlockedIncrement (&thread_interruption_requested);
- if (interrupt)
- 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);
- mono_thread_info_finish_suspend_and_resume (info);
- if (interrupt)
- mono_thread_info_finish_interrupt (interrupt_handle);
- 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*/