diff options
author | Rickard Green <rickard@erlang.org> | 2021-03-04 23:11:05 +0100 |
---|---|---|
committer | Rickard Green <rickard@erlang.org> | 2021-03-04 23:11:05 +0100 |
commit | 6dd336af1f02778f6870f8bd54a03e9166e6aa2d (patch) | |
tree | a84c58669ae5b636d2d86c877cf743a4e48a3a32 | |
parent | 67d0dd0997c3ac162b180cf86a084b34cabb9e0b (diff) | |
parent | 8d3393e8bfec37842003ef808e760af850637a3c (diff) | |
download | erlang-6dd336af1f02778f6870f8bd54a03e9166e6aa2d.tar.gz |
Merge branch 'rickard/multizero-timeout-in-timeout-fix/OTP-17253' into rickard/multizero-timeout-in-timeout-fix/21/OTP-17253
* rickard/multizero-timeout-in-timeout-fix/OTP-17253:
Fix multi-zero timeout callback handling in timer wheel
-rw-r--r-- | erts/emulator/beam/erl_bif_info.c | 34 | ||||
-rw-r--r-- | erts/emulator/beam/time.c | 4 | ||||
-rw-r--r-- | erts/emulator/test/timer_bif_SUITE.erl | 26 |
3 files changed, 62 insertions, 2 deletions
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 51af067908..27bd734490 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -4416,6 +4416,28 @@ static void broken_halt_test(Eterm bif_arg_2) erts_exit(ERTS_DUMP_EXIT, "%T", bif_arg_2); } +static void +test_multizero_timeout_in_timeout3(void *vproc) +{ + Process *proc = (Process *) vproc; + ErtsMessage *mp = erts_alloc_message(0, NULL); + ERTS_DECL_AM(multizero_timeout_in_timeout_done); + erts_queue_message(proc, 0, mp, AM_multizero_timeout_in_timeout_done, am_system); + erts_proc_dec_refc(proc); +} + +static void +test_multizero_timeout_in_timeout2(void *vproc) +{ + erts_start_timer_callback(0, test_multizero_timeout_in_timeout3, vproc); +} + +static void +test_multizero_timeout_in_timeout(void *vproc) +{ + erts_start_timer_callback(0, test_multizero_timeout_in_timeout2, vproc); +} + BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) { /* @@ -4740,6 +4762,18 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) BIF_P->mbuf_sz += sz; BIF_RET(copy); } + else if (ERTS_IS_ATOM_STR("multizero_timeout_in_timeout", BIF_ARG_1)) { + Sint64 timeout; + if (term_to_Sint64(BIF_ARG_2, &timeout)) { + if (timeout < 0) + timeout = 0; + erts_proc_inc_refc(BIF_P); + erts_start_timer_callback((ErtsMonotonicTime) timeout, + test_multizero_timeout_in_timeout, + (void *) BIF_P); + BIF_RET(am_ok); + } + } } BIF_ERROR(BIF_P, BADARG); diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index a3069e419a..6c528a362b 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -480,6 +480,8 @@ find_next_timeout(ErtsSchedulerData *esdp, ErtsTimerWheel *tiw) ERTS_HARD_DBG_CHK_WHEELS(tiw, 0); + ERTS_TW_ASSERT(tiw->at_once.nto == 0); + ERTS_TW_ASSERT(tiw->nto == tiw->soon.nto + tiw->later.nto); ERTS_TW_ASSERT(tiw->yield_slot == ERTS_TW_SLOT_INACTIVE); if (tiw->nto == 0) { /* no timeouts in wheel */ @@ -864,6 +866,8 @@ erts_bump_timers(ErtsTimerWheel *tiw, ErtsMonotonicTime curr_time) } if (tiw->pos >= bump_to) { + if (tiw->at_once.nto) + continue; ERTS_MSACC_POP_STATE_M_X(); break; } diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl index 4c25f067aa..71ab84edd6 100644 --- a/erts/emulator/test/timer_bif_SUITE.erl +++ b/erts/emulator/test/timer_bif_SUITE.erl @@ -31,7 +31,8 @@ same_time_yielding_with_cancel/1, same_time_yielding_with_cancel_other/1, % same_time_yielding_with_cancel_other_accessor/1, auto_cancel_yielding/1, - suspended_scheduler_timeout/1]). + suspended_scheduler_timeout/1, + multizero_timeout_in_timeout/1]). -include_lib("common_test/include/ct.hrl"). @@ -70,7 +71,8 @@ all() -> same_time_yielding_with_cancel_other, % same_time_yielding_with_cancel_other_accessor, auto_cancel_yielding, - suspended_scheduler_timeout]. + suspended_scheduler_timeout, + multizero_timeout_in_timeout]. %% Basic start_timer/3 functionality @@ -657,6 +659,26 @@ suspended_scheduler_timeout(Config) when is_list(Config) -> end, ok. +multizero_timeout_in_timeout(Config) when is_list(Config) -> + Timeout = 500, + MaxTimeoutDiff = 1000, + + %% We want to operate on the same timer wheel all the time... + process_flag(scheduler, erlang:system_info(schedulers_online)), + + erlang:send_after(5*(Timeout+MaxTimeoutDiff), self(), pling), + erlang:yield(), + Start = erlang:monotonic_time(), + erts_debug:set_internal_state(multizero_timeout_in_timeout, Timeout), + receive multizero_timeout_in_timeout_done -> ok end, + End = erlang:monotonic_time(), + Time = erlang:convert_time_unit(End-Start, native, millisecond), + io:format("Time=~p~n", [Time]), + true = Time < Timeout + MaxTimeoutDiff, + ok. + + + process_is_cleaned_up(P) when is_pid(P) -> undefined == erts_debug:get_internal_state({process_status, P}). |