summaryrefslogtreecommitdiff
path: root/erts/emulator
diff options
context:
space:
mode:
authorRickard Green <rickard@erlang.org>2021-05-28 20:36:26 +0200
committerRickard Green <rickard@erlang.org>2021-05-28 20:36:26 +0200
commitc4d7e1007c1ee35b834ab155b09d0f924917ad1c (patch)
treedfe1ac9bc07b7d36e337665ecb4f33897a804519 /erts/emulator
parentae4f8649c0ed90abf177124a5c974abf89dd70e3 (diff)
parent294a063233c27d966919bcf50c5a0ac53f78779b (diff)
downloaderlang-c4d7e1007c1ee35b834ab155b09d0f924917ad1c.tar.gz
Merge branch 'rickard/signal-handling-fix/GH-4885/OTP-17462' into rickard/signal-handling-fix/24/GH-4885/OTP-17462
* rickard/signal-handling-fix/GH-4885/OTP-17462: Fix signal handling of dirty executing process Fix etp-commands
Diffstat (limited to 'erts/emulator')
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c98
-rw-r--r--erts/emulator/beam/erl_process.h4
2 files changed, 100 insertions, 2 deletions
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index d31813aaa7..a119b72d0e 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -220,6 +220,9 @@ typedef struct {
Eterm request_id;
} ErtsCLAData;
+static void wait_handle_signals(Process *c_p);
+static void wake_handle_signals(Process *proc);
+
static int handle_msg_tracing(Process *c_p,
ErtsSigRecvTracing *tracing,
ErtsMessage ***next_nm_sig);
@@ -4926,6 +4929,12 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
ErtsMessage *sig, ***next_nm_sig;
ErtsSigRecvTracing tracing;
+ ASSERT(!(c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS));
+ if (c_p->sig_qs.flags & FS_HANDLING_SIGS)
+ wait_handle_signals(c_p);
+ else
+ c_p->sig_qs.flags |= FS_HANDLING_SIGS;
+
ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0);
ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p));
@@ -4945,11 +4954,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
if (!c_p->sig_qs.cont) {
*statep = state;
+ ASSERT(!(c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS));
+ c_p->sig_qs.flags &= ~FS_HANDLING_SIGS;
return !0;
}
if (state & ERTS_PSFLG_EXITING) {
*statep = state;
+ ASSERT(!(c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS));
+ c_p->sig_qs.flags &= ~FS_HANDLING_SIGS;
return 0;
}
@@ -5664,6 +5677,11 @@ stop: {
*redsp = max_reds;
}
+ if (c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS)
+ wake_handle_signals(c_p);
+ else
+ c_p->sig_qs.flags &= ~FS_HANDLING_SIGS;
+
return res;
}
}
@@ -7120,6 +7138,8 @@ erts_internal_dirty_process_handle_signals_1(BIF_ALIST_1)
res = am_noproc;
else if (!dirty)
res = am_normal; /* will handle signals itself... */
+ else if (rp->sig_qs.flags & FS_HANDLING_SIGS)
+ res = am_busy;
else {
reds = ERTS_BIF_REDS_LEFT(BIF_P);
done = erts_proc_sig_handle_incoming(rp, &state, &reds,
@@ -7178,6 +7198,84 @@ erts_proc_sig_cleanup_queues(Process *c_p)
/* Debug */
static void
+wait_handle_signals(Process *c_p)
+{
+ /*
+ * Process needs to wait on a dirty process signal
+ * handler before it can handle signals by itself...
+ *
+ * This should be a quite rare event. This only occurs
+ * when all of the following occurs:
+ * * The process is executing dirty and receives a
+ * signal.
+ * * A dirty process signal handler starts handling
+ * signals for the process and unlocks the main
+ * lock while doing so. This can currently only
+ * occur if handling an 'unlink' signal from a port.
+ * * While the dirty process signal handler is handling
+ * signals for the process, the process stops executing
+ * dirty, gets scheduled on a normal scheduler, and
+ * then tries to handle signals itself.
+ *
+ * If the above happens, the normal sceduler executing
+ * the process will wait here until the dirty process
+ * signal handler is done with the process...
+ */
+ erts_tse_t *event;
+
+ ASSERT(c_p = erts_get_current_process());
+ ASSERT(c_p->scheduler_data);
+ ASSERT(c_p->scheduler_data->aux_work_data.ssi);
+ ASSERT(c_p->scheduler_data->aux_work_data.ssi->event);
+ ASSERT(c_p->sig_qs.flags & FS_HANDLING_SIGS);
+ ASSERT(!(c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS));
+
+ event = c_p->scheduler_data->aux_work_data.ssi->event;
+ c_p->sig_qs.flags |= FS_WAIT_HANDLE_SIGS;
+
+ erts_tse_use(event);
+
+ do {
+ ASSERT(c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS);
+ erts_tse_reset(event);
+ erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
+ erts_tse_wait(event);
+ erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
+ } while (c_p->sig_qs.flags & FS_HANDLING_SIGS);
+
+ erts_tse_return(event);
+
+ c_p->sig_qs.flags &= ~FS_WAIT_HANDLE_SIGS;
+ c_p->sig_qs.flags |= FS_HANDLING_SIGS;
+}
+
+static void
+wake_handle_signals(Process *proc)
+{
+ /*
+ * Wake scheduler sleeping in wait_handle_signals()
+ * (above)...
+ *
+ * This function should only be called by a dirty process
+ * signal handler process...
+ */
+#ifdef DEBUG
+ Process *c_p = erts_get_current_process();
+ ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(proc));
+ ASSERT(c_p->sig_qs.flags & FS_WAIT_HANDLE_SIGS);
+ ERTS_ASSERT(c_p == erts_dirty_process_signal_handler_max
+ || c_p == erts_dirty_process_signal_handler_high
+ || erts_dirty_process_signal_handler);
+ ASSERT(proc->scheduler_data);
+ ASSERT(proc->scheduler_data->aux_work_data.ssi);
+ ASSERT(proc->scheduler_data->aux_work_data.ssi->event);
+#endif
+
+ proc->sig_qs.flags &= ~FS_HANDLING_SIGS;
+ erts_tse_set(proc->scheduler_data->aux_work_data.ssi->event);
+}
+
+static void
debug_foreach_sig_heap_frags(ErlHeapFragment *hfrag,
void (*oh_func)(ErlOffHeap *, void *),
void *arg)
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index b98f497af0..4777d9d1ce 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1547,8 +1547,8 @@ extern int erts_system_profile_ts_type;
#define FS_ON_HEAP_MSGQ (1 << 1) /* On heap msg queue */
#define FS_OFF_HEAP_MSGQ_CHNG (1 << 2) /* Off heap msg queue changing */
#define FS_LOCAL_SIGS_ONLY (1 << 3) /* Handle privq sigs only */
-#define FS_UNUSED1 (1 << 4) /* */
-#define FS_UNUSED2 (1 << 5) /* */
+#define FS_HANDLING_SIGS (1 << 4) /* Process is handling signals */
+#define FS_WAIT_HANDLE_SIGS (1 << 5) /* Process is waiting to handle signals */
#define FS_DELAYED_PSIGQS_LEN (1 << 6) /* Delayed update of sig_qs.len */
/*