diff options
author | Maxim Fedorov <[email protected]> | 2018-11-19 14:15:43 -0800 |
---|---|---|
committer | Maxim Fedorov <[email protected]> | 2018-11-26 11:27:12 -0800 |
commit | 63077f5bb3011ec9a14aa9b9e39ed31e4525078b (patch) | |
tree | d8399c688de7e1cfda7655f0f2dfc6b2bbb75755 /erts | |
parent | d743f51960384dd17ae3cb905ec57e8012c3abd7 (diff) | |
download | otp-63077f5bb3011ec9a14aa9b9e39ed31e4525078b.tar.gz otp-63077f5bb3011ec9a14aa9b9e39ed31e4525078b.tar.bz2 otp-63077f5bb3011ec9a14aa9b9e39ed31e4525078b.zip |
erts: fix attempt to start timer when executing on dirty scheduler
Since OTP R20, there is a possibility for MAJOR garbage collection to
run on dirty scheduler. So DistEntry destructor is being called on
dirty scheduler as well. This, in turn, leads to an attempt to schedule
timer on a dirty scheduler too, which is impossible (and will assert
on debug build, but does succeed for release build, creating an
infinite busy loop, since aux work wakes scheduler up, but dirty
scheduler cannot execute aus work).
There is a similar method in erl_hl_timer, see erts_start_timer_callback.
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/beam/erl_node_tables.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index f4dc60941a..18ed782ae3 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -421,8 +421,25 @@ static void schedule_delete_dist_entry(DistEntry* dep) * * Note that timeouts do not guarantee thread progress. */ - erts_schedule_thr_prgr_later_op(start_timer_delete_dist_entry, - dep, &dep->later_op); + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + if (esdp && !ERTS_SCHEDULER_IS_DIRTY(esdp)) { + erts_schedule_thr_prgr_later_op(start_timer_delete_dist_entry, + dep, &dep->later_op); + } else { + /* + * Since OTP 20, it's possible that destructor is executed on + * a dirty scheduler. Aux work cannot be done on a dirty + * scheduler, and scheduling any aux work on a dirty scheduler + * makes the scheduler to loop infinitely. + * To avoid this, make a spot jump: schedule this function again + * on a first normal scheduler. It is guaranteed to be always + * online. Since it's a rare event, this shall not pose a big + * utilisation hit. + */ + erts_schedule_misc_aux_work(1, + (void (*)(void *))schedule_delete_dist_entry, + (void *) dep); + } } static void |