summaryrefslogtreecommitdiff
path: root/erts/emulator/beam/erl_process.c
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2021-06-24 13:30:30 +0200
committerErlang/OTP <otp@erlang.org>2021-06-24 13:30:30 +0200
commitdcb551aa5a44780a8fe0d103fd1b9c4b8f4e2428 (patch)
treefde303b2d0a4841f02106248a61e71e732420dcf /erts/emulator/beam/erl_process.c
parent624f3a924abbce4bed67ca522d0b5c4d98dbb18b (diff)
parentee2dc019cc2bf78cacc15b3be02b8f7100414a61 (diff)
downloaderlang-dcb551aa5a44780a8fe0d103fd1b9c4b8f4e2428.tar.gz
Merge branch 'rickard/schedulers-online-fix/GH-4809/OTP-17500' into maint-24
* rickard/schedulers-online-fix/GH-4809/OTP-17500: Fix erlang:system_flag(schedulers_online, _)
Diffstat (limited to 'erts/emulator/beam/erl_process.c')
-rw-r--r--erts/emulator/beam/erl_process.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index b798754764..76a9232159 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -7956,6 +7956,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;
@@ -7966,8 +7967,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
@@ -7987,8 +7987,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:
@@ -7997,7 +7996,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) {
@@ -8007,6 +8006,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);
@@ -8065,8 +8065,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,
@@ -8091,8 +8090,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));
@@ -8129,8 +8127,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));
@@ -8155,13 +8152,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,
@@ -8180,6 +8188,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;
}