summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
authorSverker Eriksson <sverker@erlang.org>2016-04-01 20:11:34 +0200
committerSverker Eriksson <sverker@erlang.org>2016-04-01 20:11:34 +0200
commitc048886458ce68280ba32647a93a04902c929988 (patch)
tree0f61bf30bef3049ebff71b9e566c256b7d07efd7 /erts
parent6d4001de141a00b3bf37b8f7b24c5bde2b4f4015 (diff)
downloaderlang-c048886458ce68280ba32647a93a04902c929988.tar.gz
erts: Fix race for process_flag(trap_exit,true)
and a concurrent exit signal. We now actually guarantee that the process will not die from exit signal *after* the call to process_flag(trap_exit,true) has returned. The race is narrow and probably quite hard to observe even if you manage to provoke it. Has only been confirmed with the help of return trace and a sleep in send_exit_signal(). Solution: Seize status lock to prevent send_exit_signal() from reading an old status (without TRAP_EXIT) and then writing PENDING_EXIT after TRAP_EXIT has been set by process_flag_2().
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/bif.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index b43137597e..11c694233f 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1566,14 +1566,17 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
* true. For more info, see implementation of
* erts_send_exit_signal().
*/
+ erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND);
if (trap_exit)
state = erts_smp_atomic32_read_bor_mb(&BIF_P->state,
ERTS_PSFLG_TRAP_EXIT);
else
state = erts_smp_atomic32_read_band_mb(&BIF_P->state,
~ERTS_PSFLG_TRAP_EXIT);
+ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND);
+
#ifdef ERTS_SMP
- if (ERTS_PROC_PENDING_EXIT(BIF_P)) {
+ if (state & ERTS_PSFLG_PENDING_EXIT) {
erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
ERTS_BIF_EXITED(BIF_P);
}