diff options
author | Erlang/OTP <otp@erlang.org> | 2020-01-13 10:45:40 +0100 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2020-01-13 10:45:40 +0100 |
commit | d14004fa67591adb73be481ecd5b423ab4afd6d6 (patch) | |
tree | 5523d65cc49f231538dd4e2e5108543a96d02b4c /erts | |
parent | d9a88a6e9a89e54724252dce8b612a5eb5b59444 (diff) | |
parent | d6066510d20838ec85981114e8b37b64e7bf5103 (diff) | |
download | erlang-d14004fa67591adb73be481ecd5b423ab4afd6d6.tar.gz |
Merge branch 'rickard/suspended-sched-timeout/OTP-16371' into maint-22
* rickard/suspended-sched-timeout/OTP-16371:
Fix timeout handling for suspended schedulers
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/beam/erl_process.c | 44 | ||||
-rw-r--r-- | erts/emulator/test/timer_bif_SUITE.erl | 31 |
2 files changed, 60 insertions, 15 deletions
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 4c91c60220..acb5ebdfd3 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -7462,11 +7462,16 @@ msb_scheduler_type_switch(ErtsSchedType sched_type, } static ERTS_INLINE void -suspend_normal_scheduler_sleep(ErtsSchedulerData *esdp) +suspend_scheduler_sleep(ErtsSchedulerData *esdp, + int normal_sched, + ErtsMonotonicTime initial_time, + ErtsMonotonicTime timeout_time) { ErtsSchedulerSleepInfo *ssi = esdp->ssi; erts_aint32_t flgs = sched_spin_suspended(ssi, ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT); + ASSERT(!normal_sched || esdp->type == ERTS_SCHED_NORMAL); + ASSERT(esdp->type != ERTS_SCHED_NORMAL || normal_sched); if (flgs == (ERTS_SSI_FLG_SLEEPING | ERTS_SSI_FLG_WAITING | ERTS_SSI_FLG_SUSPENDED)) { @@ -7475,21 +7480,34 @@ suspend_normal_scheduler_sleep(ErtsSchedulerData *esdp) | ERTS_SSI_FLG_TSE_SLEEPING | ERTS_SSI_FLG_WAITING | ERTS_SSI_FLG_SUSPENDED)) { - int res; + if (!normal_sched) { + while (1) { + int res = erts_tse_wait(ssi->event); + if (res != EINTR) + break; + } + } + else { + ErtsMonotonicTime current_time = initial_time; + while (1) { + int res; + Sint64 timeout; - do { - res = erts_tse_wait(ssi->event); - } while (res == EINTR); + timeout = ERTS_MONOTONIC_TO_NSEC(timeout_time + - current_time + - 1) + 1; + res = erts_tse_twait(ssi->event, timeout); + if (res != EINTR) + break; + current_time = erts_get_monotonic_time(esdp); + if (current_time >= timeout_time) + break; + } + } } } } -static ERTS_INLINE void -suspend_dirty_scheduler_sleep(ErtsSchedulerData *esdp) -{ - suspend_normal_scheduler_sleep(esdp); -} - static void suspend_scheduler(ErtsSchedulerData *esdp) { @@ -7684,7 +7702,7 @@ suspend_scheduler(ErtsSchedulerData *esdp) while (1) { if (sched_type != ERTS_SCHED_NORMAL) - suspend_dirty_scheduler_sleep(esdp); + suspend_scheduler_sleep(esdp, 0, 0, 0); else { ErtsMonotonicTime current_time, timeout_time; @@ -7729,7 +7747,7 @@ suspend_scheduler(ErtsSchedulerData *esdp) sched_wall_time_change(esdp, 0); } erts_thr_progress_prepare_wait(erts_thr_prgr_data(NULL)); - suspend_normal_scheduler_sleep(esdp); + suspend_scheduler_sleep(esdp, !0, current_time, timeout_time); erts_thr_progress_finalize_wait(erts_thr_prgr_data(NULL)); current_time = erts_get_monotonic_time(esdp); } diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl index 15fe13c8c0..cdfc4f2882 100644 --- a/erts/emulator/test/timer_bif_SUITE.erl +++ b/erts/emulator/test/timer_bif_SUITE.erl @@ -30,7 +30,8 @@ cleanup/1, evil_timers/1, registered_process/1, same_time_yielding/1, 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]). + auto_cancel_yielding/1, + suspended_scheduler_timeout/1]). -include_lib("common_test/include/ct.hrl"). @@ -68,7 +69,8 @@ all() -> same_time_yielding, same_time_yielding_with_cancel, same_time_yielding_with_cancel_other, % same_time_yielding_with_cancel_other_accessor, - auto_cancel_yielding]. + auto_cancel_yielding, + suspended_scheduler_timeout]. %% Basic start_timer/3 functionality @@ -630,6 +632,31 @@ auto_cancel_yielding(Config) when is_list(Config) -> Mem = mem(), ok. +suspended_scheduler_timeout(Config) when is_list(Config) -> + Ref = make_ref(), + SchdlrsOnln = erlang:system_info(schedulers_online), + lists:foreach(fun (Sched) -> + process_flag(scheduler, Sched), + erlang:send_after(1000, self(), {Ref, Sched}) + end, + lists:seq(1, SchdlrsOnln)), + process_flag(scheduler, 0), + erlang:system_flag(schedulers_online, 1), + try + lists:foreach(fun (Sched) -> + receive + {Ref, Sched} -> + ok + after 2000 -> + ct:fail({missing_timeout, Sched}) + end + end, + lists:seq(1, SchdlrsOnln)) + after + erlang:system_flag(schedulers_online, SchdlrsOnln) + end, + ok. + process_is_cleaned_up(P) when is_pid(P) -> undefined == erts_debug:get_internal_state({process_status, P}). |