summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2020-01-13 10:45:40 +0100
committerErlang/OTP <otp@erlang.org>2020-01-13 10:45:40 +0100
commitd14004fa67591adb73be481ecd5b423ab4afd6d6 (patch)
tree5523d65cc49f231538dd4e2e5108543a96d02b4c /erts
parentd9a88a6e9a89e54724252dce8b612a5eb5b59444 (diff)
parentd6066510d20838ec85981114e8b37b64e7bf5103 (diff)
downloaderlang-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.c44
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl31
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}).