diff options
author | Sverker Eriksson <[email protected]> | 2018-04-04 14:36:59 +0200 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2018-04-04 14:36:59 +0200 |
commit | a5dc5af3fe3b1e25f0596d71d3ac36291b0099dc (patch) | |
tree | 36c6c1eebceeb16f84ea6fe18b6431c2e37a742e /erts/emulator | |
parent | db1447e1423aaaafa02d52ca0b57115631990780 (diff) | |
parent | 07ec39c2eec59a547cf88ab91dae506c44d27f56 (diff) | |
download | otp-a5dc5af3fe3b1e25f0596d71d3ac36291b0099dc.tar.gz otp-a5dc5af3fe3b1e25f0596d71d3ac36291b0099dc.tar.bz2 otp-a5dc5af3fe3b1e25f0596d71d3ac36291b0099dc.zip |
Merge branch 'sverker/monitor-frenzy-fix'
Diffstat (limited to 'erts/emulator')
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index e8d9302505..a0aef60cf1 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2859,7 +2859,7 @@ unsigned rand_bits(struct frenzy_rand_bits* rnd, unsigned int nbits) struct frenzy_monitor { ErlNifMutex* lock; - enum { + volatile enum { MON_FREE, MON_FREE_DOWN, MON_FREE_DEMONITOR, MON_TRYING, MON_ACTIVE, MON_PENDING } state; @@ -3221,13 +3221,24 @@ static void frenzy_resource_down(ErlNifEnv* env, void* obj, ErlNifPid* pid, DBG_TRACE3("DOWN pid=%T, r=%p rix=%u\n", pid->pid, r, r->rix); for (mix = 0; mix < FRENZY_MONITORS_MAX; mix++) { - if (r->monv[mix].pid.pid == pid->pid && r->monv[mix].state >= MON_TRYING) { + int state1 = r->monv[mix].state; + /* First do dirty access of pid and state without the lock */ + if (r->monv[mix].pid.pid == pid->pid && state1 >= MON_TRYING) { + int state2; enif_mutex_lock(r->monv[mix].lock); - if (enif_compare_monitors(mon, &r->monv[mix].mon) == 0) { - assert(r->monv[mix].state >= MON_ACTIVE); - r->monv[mix].state = MON_FREE_DOWN; - enif_mutex_unlock(r->monv[mix].lock); - return; + state2 = r->monv[mix].state; + if (state2 >= MON_ACTIVE) { + if (enif_compare_monitors(mon, &r->monv[mix].mon) == 0) { + r->monv[mix].state = MON_FREE_DOWN; + enif_mutex_unlock(r->monv[mix].lock); + return; + } + } + else { + assert(state2 != MON_TRYING); + assert(state1 == MON_TRYING || /* racing monitor failed */ + state2 == MON_FREE_DEMONITOR || /* racing demonitor */ + state2 == MON_FREE_DOWN); /* racing down */ } enif_mutex_unlock(r->monv[mix].lock); } |