aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2014-12-04 11:04:23 +0100
committerLukas Larsson <[email protected]>2014-12-19 10:39:52 +0100
commitb8a2313263d0f120dacbe82ced5c99545bbd15a3 (patch)
treed77376ce678171c430740e00904a32044f350bb0
parentd6d1ef4787951070dd152daf44eff2003b7f2ed2 (diff)
downloadotp-b8a2313263d0f120dacbe82ced5c99545bbd15a3.tar.gz
otp-b8a2313263d0f120dacbe82ced5c99545bbd15a3.tar.bz2
otp-b8a2313263d0f120dacbe82ced5c99545bbd15a3.zip
erts: Introduce thread suspend functions
These functions allow any thread to suspend any other thread immediately and then resume all threads. This is useful when doing a crash dump in order to get a more accurate picture of what state the system is in.
-rw-r--r--erts/emulator/beam/erl_threads.h15
-rw-r--r--erts/emulator/beam/sys.h5
-rw-r--r--erts/emulator/sys/unix/sys.c69
-rw-r--r--erts/include/internal/ethread.h1
-rw-r--r--erts/lib_src/pthread/ethread.c11
5 files changed, 97 insertions, 4 deletions
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index 1ab5418741..463271252d 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -621,11 +621,17 @@ ERTS_GLB_INLINE void erts_thr_set_main_status(int, int);
ERTS_GLB_INLINE int erts_thr_get_main_status(void);
ERTS_GLB_INLINE void erts_thr_yield(void);
+
#ifdef ETHR_HAVE_ETHR_SIG_FUNCS
#define ERTS_THR_HAVE_SIG_FUNCS 1
ERTS_GLB_INLINE void erts_thr_sigmask(int how, const sigset_t *set,
sigset_t *oset);
ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig);
+
+#ifdef USE_THREADS
+ERTS_GLB_INLINE void erts_thr_kill(erts_tid_t tid, int sig);
+#endif
+
#endif /* #ifdef HAVE_ETHR_SIG_FUNCS */
#ifdef USE_THREADS
@@ -2849,6 +2855,15 @@ ERTS_GLB_INLINE void erts_thr_yield(void)
#ifdef ETHR_HAVE_ETHR_SIG_FUNCS
ERTS_GLB_INLINE void
+erts_thr_kill(erts_tid_t tid, int sig) {
+#ifdef USE_THREADS
+ int res = ethr_kill((ethr_tid)tid, sig);
+ if (res)
+ erts_thr_fatal_error(res, "killing thread");
+#endif
+}
+
+ERTS_GLB_INLINE void
erts_thr_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
#ifdef USE_THREADS
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index c29d4b3777..bdc5237815 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -784,6 +784,11 @@ int erts_sys_unsetenv(char *key);
char *erts_read_env(char *key);
void erts_free_read_env(void *value);
+#if defined(ERTS_THR_HAVE_SIG_FUNCS) && !defined(ETHR_UNUSABLE_SIGUSRX)
+extern void sys_thr_resume(erts_tid_t tid);
+extern void sys_thr_suspend(erts_tid_t tid);
+#endif
+
/* utils.c */
/* Options to sys_alloc_opt */
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 81ed5626c2..841f0c7575 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -216,6 +216,9 @@ static erts_smp_atomic_t sys_misc_mem_sz;
#if defined(ERTS_SMP)
static void smp_sig_notify(char c);
static int sig_notify_fds[2] = {-1, -1};
+
+static int sig_suspend_fds[2] = {-1, -1};
+#define ERTS_SYS_SUSPEND_SIGNAL SIGUSR2
#elif defined(USE_THREADS)
static int async_fd[2];
#endif
@@ -789,6 +792,9 @@ prepare_crash_dump(int secs)
/* We don't want to close the signal notification pipe... */
if (i == sig_notify_fds[0] || i == sig_notify_fds[1])
continue;
+ /* We don't want to close the signal syspend pipe... */
+ if (i == sig_suspend_fds[0] || i == sig_suspend_fds[1])
+ continue;
#elif defined(USE_THREADS)
/* We don't want to close the async notification pipe... */
if (i == async_fd[0] || i == async_fd[1])
@@ -877,9 +883,23 @@ sigusr1_exit(void)
#ifdef ETHR_UNUSABLE_SIGUSRX
#warning "Unusable SIGUSR1 & SIGUSR2. Disabling use of these signals"
-#endif
-#ifndef ETHR_UNUSABLE_SIGUSRX
+#else
+
+#ifdef ERTS_SMP
+void
+sys_thr_suspend(erts_tid_t tid) {
+ erts_thr_kill(tid, ERTS_SYS_SUSPEND_SIGNAL);
+}
+
+void
+sys_thr_resume(erts_tid_t tid) {
+ int i = 0, res;
+ do {
+ res = write(sig_suspend_fds[1],&i,sizeof(i));
+ } while (res < 0 && errno == EAGAIN);
+}
+#endif
#if (defined(SIG_SIGSET) || defined(SIG_SIGNAL))
static RETSIGTYPE user_signal1(void)
@@ -894,6 +914,21 @@ static RETSIGTYPE user_signal1(int signum)
#endif
}
+#ifdef ERTS_SMP
+#if (defined(SIG_SIGSET) || defined(SIG_SIGNAL))
+static RETSIGTYPE suspend_signal(void)
+#else
+static RETSIGTYPE suspend_signal(int signum)
+#endif
+{
+ int res;
+ int buf[1];
+ do {
+ res = read(sig_suspend_fds[0], buf, sizeof(int));
+ } while (res < 0 && errno == EINTR);
+}
+#endif /* #ifdef ERTS_SMP */
+
#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
static void
@@ -944,7 +979,10 @@ void init_break_handler(void)
{
sys_sigset(SIGINT, request_break);
#ifndef ETHR_UNUSABLE_SIGUSRX
- sys_sigset(SIGUSR1, user_signal1);
+ sys_signal(SIGUSR1, user_signal1);
+#ifdef ERTS_SMP
+ sys_signal(ERTS_SYS_SUSPEND_SIGNAL, suspend_signal);
+#endif /* #ifdef ERTS_SMP */
#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
sys_sigset(SIGQUIT, do_quit);
}
@@ -963,8 +1001,13 @@ static void block_signals(void)
sys_sigblock(SIGINT);
#ifndef ETHR_UNUSABLE_SIGUSRX
sys_sigblock(SIGUSR1);
+#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
+#endif /* #ifndef ERTS_SMP */
+
+#if defined(ERTS_SMP) && !defined(ETHR_UNUSABLE_SIGUSRX)
+ sys_sigblock(ERTS_SYS_SUSPEND_SIGNAL);
#endif
-#endif
+
}
static void unblock_signals(void)
@@ -978,8 +1021,14 @@ static void unblock_signals(void)
#ifndef ETHR_UNUSABLE_SIGUSRX
sys_sigrelease(SIGUSR1);
#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
+#endif /* #ifndef ERTS_SMP */
+
+#if defined(ERTS_SMP) && !defined(ETHR_UNUSABLE_SIGUSRX)
+ sys_sigrelease(ERTS_SYS_SUSPEND_SIGNAL);
#endif
+
}
+
/************************** Time stuff **************************/
#ifdef HAVE_GETHRTIME
#ifdef GETHRTIME_WITH_CLOCK_GETTIME
@@ -3221,6 +3270,17 @@ init_smp_sig_notify(void)
NULL,
&thr_opts);
}
+
+static void
+init_smp_sig_suspend(void) {
+ if (pipe(sig_suspend_fds) < 0) {
+ erl_exit(ERTS_ABORT_EXIT,
+ "Failed to create sig_suspend pipe: %s (%d)\n",
+ erl_errno_id(errno),
+ errno);
+ }
+}
+
#ifdef __DARWIN__
int erts_darwin_main_thread_pipe[2];
@@ -3371,6 +3431,7 @@ erl_sys_args(int* argc, char** argv)
#ifdef ERTS_SMP
init_smp_sig_notify();
+ init_smp_sig_suspend();
#endif
/* Handled arguments have been marked with NULL. Slide arguments
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index 0f466dbb00..0d9a4a4305 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -537,6 +537,7 @@ void *ethr_tsd_get(ethr_tsd_key);
#include <signal.h>
int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset);
int ethr_sigwait(const sigset_t *set, int *sig);
+int ethr_kill(const ethr_tid tid, const int sig);
#endif
void ethr_compiler_barrier(void);
diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c
index 340d085428..7cf38580c5 100644
--- a/erts/lib_src/pthread/ethread.c
+++ b/erts/lib_src/pthread/ethread.c
@@ -600,6 +600,17 @@ int ethr_sigwait(const sigset_t *set, int *sig)
return 0;
}
+int ethr_kill(const ethr_tid tid, const int sig)
+{
+#if ETHR_XCHK
+ if (ethr_not_inited__) {
+ ETHR_ASSERT(0);
+ return EACCES;
+ }
+#endif
+ return pthread_kill((const pthread_t)tid, sig);
+}
+
#endif /* #if ETHR_HAVE_ETHR_SIG_FUNCS */
ETHR_IMPL_NORETURN__