From e9ffa6bab3583a4ddabe4f41218579503c8d4b95 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 1 Jun 2010 13:52:51 +0000 Subject: OTP-8612 Fix potential premature destruction of port locks Port locks could be prematurely destroyed. --- erts/emulator/beam/erl_port_task.c | 8 ++++---- erts/emulator/beam/global.h | 3 +-- erts/emulator/beam/io.c | 26 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 0b6bb0d8e9..967a14f0d1 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -969,11 +969,11 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) erts_port_release(pp); #else { - long refc = erts_smp_atomic_dectest(&pp->refc); + long refc; + erts_smp_mtx_unlock(pp->lock); + refc = erts_smp_atomic_dectest(&pp->refc); ASSERT(refc >= 0); - if (refc > 0) - erts_smp_mtx_unlock(pp->lock); - else { + if (refc == 0) { erts_smp_runq_unlock(runq); erts_port_cleanup(pp); /* Might aquire runq lock */ erts_smp_runq_lock(runq); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 7c3ba69a65..d5d63631ff 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1192,12 +1192,11 @@ erts_smp_port_unlock(Port *prt) { #ifdef ERTS_SMP long refc; + erts_smp_mtx_unlock(prt->lock); refc = erts_smp_atomic_dectest(&prt->refc); ASSERT(refc >= 0); if (refc == 0) erts_port_cleanup(prt); - else - erts_smp_mtx_unlock(prt->lock); #endif } diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 10f1082039..68625801cf 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -280,9 +280,35 @@ erts_test_next_port(int set, Uint next) return res; } + +static void port_cleanup(Port *prt); + +#ifdef ERTS_SMP + +static void +sched_port_cleanup(void *vprt) +{ + Port *prt = (Port *) vprt; + erts_smp_mtx_lock(prt->lock); + port_cleanup(prt); +} + +#endif + void erts_port_cleanup(Port *prt) { +#ifdef ERTS_SMP + if (erts_smp_mtx_trylock(prt->lock) == EBUSY) + erts_schedule_misc_op(sched_port_cleanup, (void *) prt); + else +#endif + port_cleanup(prt); +} + +void +port_cleanup(Port *prt) +{ #ifdef ERTS_SMP Uint32 port_specific; erts_smp_mtx_t *mtx; -- cgit v1.2.3