diff options
author | Erlang/OTP <otp@erlang.org> | 2021-09-02 12:15:37 +0200 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2021-09-02 12:15:37 +0200 |
commit | 9052e7996215b2d661b1f4c4f7d3c83c290d033d (patch) | |
tree | 597a485bcc3699b15586ec3233df43d9fc0c1d37 | |
parent | a81d70bd010c032b0c49b05dc4d2eaa747852b06 (diff) | |
parent | ee2dc019cc2bf78cacc15b3be02b8f7100414a61 (diff) | |
download | erlang-9052e7996215b2d661b1f4c4f7d3c83c290d033d.tar.gz |
Merge branch 'rickard/schedulers-online-fix/GH-4809/OTP-17500' into maint-22
* rickard/schedulers-online-fix/GH-4809/OTP-17500:
Fix erlang:system_flag(schedulers_online, _)
-rw-r--r-- | erts/emulator/beam/erl_process.c | 43 | ||||
-rw-r--r-- | erts/emulator/test/scheduler_SUITE.erl | 68 |
2 files changed, 95 insertions, 16 deletions
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 666d3a1413..0c8999dc16 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -7966,6 +7966,7 @@ erts_set_schedulers_online(Process *p, int online, increase; ErtsProcList *plp; int dirty_no, change_dirty, dirty_online; + Eterm resume_next = NIL; if (new_no < 1) return ERTS_SCHDLR_SSPND_EINVAL; @@ -7976,8 +7977,7 @@ erts_set_schedulers_online(Process *p, if (dirty_only) resume_proc = 0; - else - { + else { resume_proc = 1; /* * If we suspend current process we need to suspend before @@ -7997,8 +7997,7 @@ erts_set_schedulers_online(Process *p, have_unlocked_plocks = 0; no = (int) new_no; - if (!dirty_only) - { + if (!dirty_only) { changing = erts_atomic32_read_nob(&schdlr_sspnd.changing); if (changing & ERTS_SCHDLR_SSPND_CHNG_ONLN) { enqueue_wait: @@ -8007,7 +8006,7 @@ erts_set_schedulers_online(Process *p, erts_proclist_store_last(&schdlr_sspnd.chngq, plp); resume_proc = 0; res = ERTS_SCHDLR_SSPND_YIELD_RESTART; - goto done; + goto return_wait; } plp = erts_proclist_peek_first(schdlr_sspnd.chngq); if (!plp) { @@ -8017,6 +8016,7 @@ erts_set_schedulers_online(Process *p, ASSERT(schdlr_sspnd.changer == am_true); if (!erts_proclist_same(plp, p)) goto enqueue_wait; + schdlr_sspnd.changer = am_false; p->flags &= ~F_SCHDLR_ONLN_WAITQ; erts_proclist_remove(&schdlr_sspnd.chngq, plp); proclist_destroy(plp); @@ -8075,8 +8075,7 @@ erts_set_schedulers_online(Process *p, if (dirty_only) increase = (dirty_no > dirty_online); - else - { + else { change_flags |= ERTS_SCHDLR_SSPND_CHNG_ONLN; schdlr_sspnd_set_nscheds(&schdlr_sspnd.online, ERTS_SCHED_NORMAL, @@ -8101,8 +8100,7 @@ erts_set_schedulers_online(Process *p, dcpu_sched_ix_resume_wake(ix); } } - if (!dirty_only) - { + if (!dirty_only) { if (schdlr_sspnd.msb.ongoing|schdlr_sspnd.nmsb.ongoing) { for (ix = online; ix < no; ix++) erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix)); @@ -8139,8 +8137,7 @@ erts_set_schedulers_online(Process *p, dcpu_sched_ix_wake(0); } } - if (!dirty_only) - { + if (!dirty_only) { if (schdlr_sspnd.msb.ongoing|schdlr_sspnd.nmsb.ongoing) { for (ix = no; ix < online; ix++) erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix)); @@ -8165,13 +8162,24 @@ erts_set_schedulers_online(Process *p, if (change_flags & ERTS_SCHDLR_SSPND_CHNG_ONLN) { /* Suspend and wait for requested change to complete... */ + ASSERT(schdlr_sspnd.changer == am_false); schdlr_sspnd.changer = p->common.id; resume_proc = 0; res = ERTS_SCHDLR_SSPND_YIELD_DONE; } - + else { done: - + ASSERT(schdlr_sspnd.changer == am_false); + /* We're done; we may need to wake up a queued process... */ + plp = erts_proclist_peek_first(schdlr_sspnd.chngq); + if (plp) { + schdlr_sspnd.changer = am_true; /* change right in transit */ + /* resume process that is queued for next change... */ + resume_next = plp->u.pid; + ASSERT(is_internal_pid(resume_next)); + } + } +return_wait: ASSERT(schdlr_sspnd_get_nscheds(&schdlr_sspnd.online, ERTS_SCHED_DIRTY_CPU) <= schdlr_sspnd_get_nscheds(&schdlr_sspnd.online, @@ -8190,6 +8198,15 @@ done: erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS); } + if (is_internal_pid(resume_next)) { + Process *rp = erts_proc_lookup(resume_next); + if (rp) { + erts_proc_lock(rp, ERTS_PROC_LOCK_STATUS); + resume_process(rp, ERTS_PROC_LOCK_STATUS); + erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); + } + } + return res; } diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index c863a69a43..b691ef20fb 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -59,7 +59,9 @@ dirty_scheduler_threads/1, poll_threads/1, reader_groups/1, - otp_16446/1]). + otp_16446/1, + simultaneously_change_schedulers_online/1, + simultaneously_change_schedulers_online_with_exits/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -76,7 +78,9 @@ all() -> dirty_scheduler_threads, poll_threads, reader_groups, - otp_16446]. + otp_16446, + simultaneously_change_schedulers_online, + simultaneously_change_schedulers_online_with_exits]. groups() -> [{scheduler_bind, [], @@ -84,10 +88,12 @@ groups() -> sct_cmd, sbt_cmd]}]. init_per_suite(Config) -> - Config. + [{schedulers_online, erlang:system_info(schedulers_online)} | Config]. end_per_suite(Config) -> catch erts_debug:set_internal_state(available_internal_state, false), + SchedOnln = proplists:get_value(schedulers_online, Config), + erlang:system_flag(schedulers_online, SchedOnln), Config. init_per_testcase(update_cpu_info, Config) -> @@ -1867,6 +1873,62 @@ otp_16446(Config) when is_list(Config) -> erlang:display(Comment), {comment, Comment}. +simultaneously_change_schedulers_online(Config) when is_list(Config) -> + SchedOnline = erlang:system_info(schedulers_online), + Change = fun Change (0) -> + ok; + Change (N) -> + %timer:sleep(rand:uniform(100)), + erlang:system_flag(schedulers_online, + rand:uniform(erlang:system_info(schedulers))), + Change(N-1) + end, + PMs = lists:map(fun (_) -> + spawn_monitor(fun () -> Change(10) end) + end, lists:seq(1,2500)), + lists:foreach(fun ({P, M}) -> + receive + {'DOWN', M, process, P, normal} -> + ok + end + end, + PMs), + erlang:system_flag(schedulers_online, SchedOnline), + ok. + +simultaneously_change_schedulers_online_with_exits(Config) when is_list(Config) -> + SchedOnline = erlang:system_info(schedulers_online), + Change = fun Change (0) -> + exit(bye); + Change (N) -> + %timer:sleep(rand:uniform(100)), + erlang:system_flag(schedulers_online, + rand:uniform(erlang:system_info(schedulers))), + Change(N-1) + end, + PMs = lists:map(fun (_) -> + spawn_monitor(fun () -> Change(10) end) + end, lists:seq(1,2500)), + %% Kill every 10:th process... + _ = lists:foldl(fun ({P, _M}, 0) -> + exit(P, bye), + 10; + (_PM, N) -> + N-1 + end, + 10, + PMs), + lists:foreach(fun ({P, M}) -> + receive + {'DOWN', M, process, P, Reason} -> + bye = Reason + end + end, + PMs), + erlang:system_flag(schedulers_online, SchedOnline), + ok. + + %% %% Utils %% |