aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_bif_port.c
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2014-09-30 17:00:37 +0200
committerSverker Eriksson <[email protected]>2014-09-30 20:52:48 +0200
commitb7801392325784027e93e3488e7e28d596e6b658 (patch)
tree62d48d5cbf62bac466240a77627a73230942d55f /erts/emulator/beam/erl_bif_port.c
parentbfc6a9b3325969a7bc1d0c228766537049a4f637 (diff)
downloadotp-b7801392325784027e93e3488e7e28d596e6b658.tar.gz
otp-b7801392325784027e93e3488e7e28d596e6b658.tar.bz2
otp-b7801392325784027e93e3488e7e28d596e6b658.zip
erts: Fix race between port_set_data, port_get_data and port termination
Always update prt->data with atomic xchg-op. Check for NULL data to detect racing port terminator. Use NULL, as THE_NON_VALUE can be a valid pointer on debug VM.
Diffstat (limited to 'erts/emulator/beam/erl_bif_port.c')
-rw-r--r--erts/emulator/beam/erl_bif_port.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 8a622e5e6e..64bd598ba6 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -493,8 +493,8 @@ void
erts_cleanup_port_data(Port *prt)
{
ASSERT(erts_atomic32_read_nob(&prt->state) & ERTS_PORT_SFLGS_INVALID_LOOKUP);
- cleanup_old_port_data(erts_smp_atomic_read_nob(&prt->data));
- erts_smp_atomic_set_nob(&prt->data, (erts_aint_t) THE_NON_VALUE);
+ cleanup_old_port_data(erts_smp_atomic_xchg_nob(&prt->data,
+ (erts_aint_t) NULL));
}
Uint
@@ -562,8 +562,14 @@ BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
data = erts_smp_atomic_xchg_wb(&prt->data, data);
+ if (data == (erts_aint_t)NULL) {
+ /* Port terminated by racing thread */
+ data = erts_smp_atomic_xchg_wb(&prt->data, data);
+ ASSERT(data != (erts_aint_t)NULL);
+ cleanup_old_port_data(data);
+ BIF_ERROR(BIF_P, BADARG);
+ }
cleanup_old_port_data(data);
-
BIF_RET(am_true);
}
@@ -582,6 +588,8 @@ BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
BIF_ERROR(BIF_P, BADARG);
data = erts_smp_atomic_read_ddrb(&prt->data);
+ if (data == (erts_aint_t)NULL)
+ BIF_ERROR(BIF_P, BADARG); /* Port terminated by racing thread */
if ((data & 0x3) != 0) {
res = (Eterm) (UWord) data;