summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2021-03-29 15:12:49 +0200
committerErlang/OTP <otp@erlang.org>2021-03-29 15:12:49 +0200
commitddcda22c41dfe5b595036a42ab5d42dcb1957b1b (patch)
tree8a5589447f599daacaebb28c9e5f4e53811f5c74
parentfd8d1e319f645edd9136ee86d48d609bd46cb4a5 (diff)
parentec5357bb04f13ef3e3206816dd477c54febd7c7d (diff)
downloaderlang-ddcda22c41dfe5b595036a42ab5d42dcb1957b1b.tar.gz
Merge branch 'rickard/multizero-timeout-in-timeout-fix/21/OTP-17253' into maint-21
* rickard/multizero-timeout-in-timeout-fix/21/OTP-17253: erts: Fix bug in timer wheel at cancel during bump yield erts: Tidy up some harmless code typos Fix multi-zero timeout callback handling in timer wheel
-rw-r--r--erts/emulator/beam/erl_bif_info.c34
-rw-r--r--erts/emulator/beam/time.c13
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl26
3 files changed, 67 insertions, 6 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..73538dc375 100644
--- a/erts/emulator/beam/time.c
+++ b/erts/emulator/beam/time.c
@@ -316,7 +316,7 @@ struct ErtsTimerWheel_ {
#define ERTS_TW_SLOT_AT_ONCE (-1)
#define ERTS_TW_BUMP_LATER_WHEEL(TIW) \
- ((tiw)->pos + ERTS_TW_LATER_WHEEL_SLOT_SIZE >= (TIW)->later.pos)
+ ((TIW)->pos + ERTS_TW_LATER_WHEEL_SLOT_SIZE >= (TIW)->later.pos)
static int bump_later_wheel(ErtsTimerWheel *tiw, int *yield_count_p);
@@ -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 */
@@ -701,7 +703,8 @@ remove_timer(ErtsTimerWheel *tiw, ErtsTWheelTimer *p)
if (slot < ERTS_TW_SOON_WHEEL_END_SLOT) {
if (empty_slot
&& tiw->true_next_timeout_time
- && p->timeout_pos == tiw->next_timeout_pos) {
+ && p->timeout_pos == tiw->next_timeout_pos
+ && tiw->yield_slot == ERTS_TW_SLOT_INACTIVE) {
tiw->true_next_timeout_time = 0;
}
if (--tiw->soon.nto == 0)
@@ -714,7 +717,8 @@ remove_timer(ErtsTimerWheel *tiw, ErtsTWheelTimer *p)
ErtsMonotonicTime tpos = tiw->later.min_tpos;
tpos &= ERTS_TW_LATER_WHEEL_POS_MASK;
tpos -= ERTS_TW_LATER_WHEEL_SLOT_SIZE;
- if (tpos == tiw->next_timeout_pos)
+ if (tpos == tiw->next_timeout_pos
+ && tiw->yield_slot == ERTS_TW_SLOT_INACTIVE)
tiw->true_next_timeout_time = 0;
}
if (--tiw->later.nto == 0) {
@@ -864,6 +868,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;
}
@@ -908,7 +914,6 @@ erts_bump_timers(ErtsTimerWheel *tiw, ErtsMonotonicTime curr_time)
{
ErtsMonotonicTime tmp_slots = bump_to - tiw->pos;
- tmp_slots = (bump_to - tiw->pos);
if (tmp_slots < ERTS_TW_SOON_WHEEL_SIZE)
slots = (int) tmp_slots;
else
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}).