diff options
author | Rickard Green <rickard@erlang.org> | 2021-05-28 20:36:26 +0200 |
---|---|---|
committer | Rickard Green <rickard@erlang.org> | 2021-05-28 20:36:26 +0200 |
commit | c4d7e1007c1ee35b834ab155b09d0f924917ad1c (patch) | |
tree | dfe1ac9bc07b7d36e337665ecb4f33897a804519 /erts/emulator | |
parent | ae4f8649c0ed90abf177124a5c974abf89dd70e3 (diff) | |
parent | 294a063233c27d966919bcf50c5a0ac53f78779b (diff) | |
download | erlang-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.c | 98 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 4 |
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 */ /* |