#include <errno.h>
#include <signal.h>
-#include "mono-threads-posix-signals.h"
+#include "mono-threads-debug.h"
#if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#define DEFAULT_SUSPEND_SIGNAL SIGXFSZ
#endif
#define DEFAULT_RESTART_SIGNAL SIGXCPU
-static int suspend_signal_num;
-static int restart_signal_num;
static int abort_signal_num;
static sigset_t suspend_signal_mask;
static sigset_t suspend_ack_signal_mask;
-//Can't avoid the circular dep on this. Will be gone pretty soon
-extern int mono_gc_get_suspend_signal (void);
-
-int
-mono_threads_posix_signal_search_alternative (int min_signal)
+gint
+mono_threads_suspend_search_alternative_signal (void)
{
#if !defined (SIGRTMIN)
g_error ("signal search only works with RTMIN");
#else
int i;
/* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
- for (i = MAX (min_signal, SIGRTMIN) + 1; i < SIGRTMAX; ++i) {
+ for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
struct sigaction sinfo;
sigaction (i, NULL, &sinfo);
if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
static void
signal_add_handler (int signo, gpointer handler, int flags)
{
-#if !defined(__native_client__)
+#if defined(__native_client__)
+ g_assert_not_reached ();
+#else
/*FIXME, move the code from mini to utils and do the right thing!*/
struct sigaction sa;
struct sigaction previous_sa;
#endif
}
-static int
-suspend_signal_get (void)
-{
-#if defined(PLATFORM_ANDROID)
- return SIGUNUSED;
-#elif !defined (SIGRTMIN)
-#ifdef SIGUSR1
- return SIGUSR1;
-#else
- return -1;
-#endif /* SIGUSR1 */
-#else
- static int suspend_signum = -1;
- if (suspend_signum == -1)
- suspend_signum = mono_threads_posix_signal_search_alternative (-1);
- return suspend_signum;
-#endif /* SIGRTMIN */
-}
-
-static int
-restart_signal_get (void)
-{
-#if defined(PLATFORM_ANDROID)
- return SIGTTOU;
-#elif !defined (SIGRTMIN)
-#ifdef SIGUSR2
- return SIGUSR2;
-#else
- return -1;
-#endif /* SIGUSR1 */
-#else
- static int resume_signum = -1;
- if (resume_signum == -1)
- resume_signum = mono_threads_posix_signal_search_alternative (suspend_signal_get () + 1);
- return resume_signum;
-#endif /* SIGRTMIN */
-}
-
-
static int
abort_signal_get (void)
{
#if defined(PLATFORM_ANDROID)
return SIGTTIN;
-#elif !defined (SIGRTMIN)
-#ifdef SIGTTIN
- return SIGTTIN;
-#else
- return -1;
-#endif /* SIGRTMIN */
-#else
+#elif defined (SIGRTMIN)
static int abort_signum = -1;
if (abort_signum == -1)
- abort_signum = mono_threads_posix_signal_search_alternative (restart_signal_get () + 1);
+ abort_signum = mono_threads_suspend_search_alternative_signal ();
return abort_signum;
-#endif /* SIGRTMIN */
+#elif defined (SIGTTIN)
+ return SIGTTIN;
+#else
+ return -1;
+#endif
}
static void
int old_errno = errno;
info = mono_thread_info_current ();
- info->signal = restart_signal_num;
+ info->signal = DEFAULT_RESTART_SIGNAL;
errno = old_errno;
#endif
}
goto done;
}
- ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], context);
-
- /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
- current->suspend_can_continue = ret;
-
- /* This thread is doomed, all we can do is give up and let the suspender recover. */
- if (!ret) {
- THREADS_SUSPEND_DEBUG ("\tThread is dying, failed to capture state %p\n", mono_thread_info_get_tid (current));
- mono_threads_transition_async_suspend_compensation (current);
-
- /* We're done suspending */
- mono_threads_notify_initiator_of_suspend (current);
-
- goto done;
- }
+ /*
+ * If the thread is starting, then thread_state_init_from_sigctx returns FALSE,
+ * as the thread might have been attached without the domain or lmf having been
+ * initialized yet.
+ *
+ * One way to fix that is to keep the thread suspended (wait for the restart
+ * signal), and make sgen aware that even if a thread might be suspended, there
+ * would be cases where you cannot scan its stack/registers. That would in fact
+ * consist in removing the async suspend compensation, and treat the case directly
+ * in sgen. That's also how it was done in the sgen specific suspend code.
+ */
+
+ /* thread_state_init_from_sigctx return FALSE if the current thread is starting or detaching and suspend can't continue. */
+ current->suspend_can_continue = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (¤t->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], context);
+
+ if (!current->suspend_can_continue)
+ THREADS_SUSPEND_DEBUG ("\tThread is starting or detaching, failed to capture state %p\n", mono_thread_info_get_tid (current));
/*
Block the restart signal.
do {
current->signal = 0;
sigsuspend (&suspend_signal_mask);
- } while (current->signal != restart_signal_num);
+ } while (current->signal != DEFAULT_RESTART_SIGNAL);
/* Unblock the restart signal. */
pthread_sigmask (SIG_UNBLOCK, &suspend_ack_signal_mask, NULL);
#endif
}
-static void
-abort_signal_handler (int _dummy, siginfo_t *info, void *context)
-{
-#if defined(__native_client__)
- g_assert_not_reached ();
-#else
- suspend_signal_handler (_dummy, info, context);
-#endif
-}
-
void
-mono_threads_posix_init_signals (MonoThreadPosixInitSignals signals)
+mono_threads_suspend_init_signals (void)
{
sigset_t signal_set;
- g_assert ((signals == MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART) ^ (signals == MONO_THREADS_POSIX_INIT_SIGNALS_ABORT));
-
sigemptyset (&signal_set);
- switch (signals) {
- case MONO_THREADS_POSIX_INIT_SIGNALS_SUSPEND_RESTART: {
- if (mono_thread_info_unified_management_enabled ()) {
- suspend_signal_num = DEFAULT_SUSPEND_SIGNAL;
- restart_signal_num = DEFAULT_RESTART_SIGNAL;
- } else {
- suspend_signal_num = suspend_signal_get ();
- restart_signal_num = restart_signal_get ();
- }
-
- sigfillset (&suspend_signal_mask);
- sigdelset (&suspend_signal_mask, restart_signal_num);
- if (!mono_thread_info_unified_management_enabled ())
- sigdelset (&suspend_signal_mask, mono_gc_get_suspend_signal ());
-
- sigemptyset (&suspend_ack_signal_mask);
- sigaddset (&suspend_ack_signal_mask, restart_signal_num);
+ sigfillset (&suspend_signal_mask);
+ sigdelset (&suspend_signal_mask, DEFAULT_RESTART_SIGNAL);
- signal_add_handler (suspend_signal_num, suspend_signal_handler, SA_RESTART);
- signal_add_handler (restart_signal_num, restart_signal_handler, SA_RESTART);
+ sigemptyset (&suspend_ack_signal_mask);
+ sigaddset (&suspend_ack_signal_mask, DEFAULT_RESTART_SIGNAL);
- sigaddset (&signal_set, suspend_signal_num);
- sigaddset (&signal_set, restart_signal_num);
+ signal_add_handler (DEFAULT_SUSPEND_SIGNAL, suspend_signal_handler, SA_RESTART);
+ signal_add_handler (DEFAULT_RESTART_SIGNAL, restart_signal_handler, SA_RESTART);
- break;
- }
- case MONO_THREADS_POSIX_INIT_SIGNALS_ABORT: {
- abort_signal_num = abort_signal_get ();
+ sigaddset (&signal_set, DEFAULT_SUSPEND_SIGNAL);
+ sigaddset (&signal_set, DEFAULT_RESTART_SIGNAL);
- signal_add_handler (abort_signal_num, abort_signal_handler, 0);
+ abort_signal_num = abort_signal_get ();
- sigaddset (&signal_set, abort_signal_num);
+ /* the difference between abort and suspend here is made by not
+ * passing SA_RESTART, meaning we won't restart the syscall when
+ * receiving a signal */
+ signal_add_handler (abort_signal_num, suspend_signal_handler, 0);
- break;
- }
- default: g_assert_not_reached ();
- }
+ sigaddset (&signal_set, abort_signal_num);
/* ensure all the new signals are unblocked */
sigprocmask (SIG_UNBLOCK, &signal_set, NULL);
}
gint
-mono_threads_posix_get_suspend_signal (void)
+mono_threads_suspend_get_suspend_signal (void)
{
- return suspend_signal_num;
+ return DEFAULT_SUSPEND_SIGNAL;
}
gint
-mono_threads_posix_get_restart_signal (void)
+mono_threads_suspend_get_restart_signal (void)
{
- return restart_signal_num;
+ return DEFAULT_RESTART_SIGNAL;
}
gint
-mono_threads_posix_get_abort_signal (void)
+mono_threads_suspend_get_abort_signal (void)
{
return abort_signal_num;
}