File 0946-Fix-prio-elevation-race.patch of Package erlang
From 226538bf7fd1edf05f7f2d9d826b19a8ac06a593 Mon Sep 17 00:00:00 2001
From: Rickard Green <rickard@erlang.org>
Date: Fri, 17 Jul 2020 14:56:38 +0200
Subject: [PATCH] Fix prio elevation race
A race condition when changing process priority by calling
process_flag(priority, Prio) could cause elevation of priority for a
system task to be ignored. This bug hit if the system task was
scheduled on the process calling process_flag() at the same time as
the priority was changed. The bug is quite harmless and should hit
very seldom if ever.
---
erts/emulator/beam/erl_process.c | 53 +++++++++-----------------------
1 file changed, 15 insertions(+), 38 deletions(-)
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 6c83693df8..fb73641f57 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -6379,7 +6379,7 @@ check_enqueue_in_prio_queue(Process *c_p,
{
erts_aint32_t aprio, qbit, max_qbit;
- aprio = (actual >> ERTS_PSFLGS_ACT_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK;
+ aprio = ((*newp) >> ERTS_PSFLGS_ACT_PRIO_OFFSET) & ERTS_PSFLGS_PRIO_MASK;
qbit = 1 << aprio;
*prq_prio_p = aprio;
@@ -6838,6 +6838,12 @@ active_sys_enqueue(Process *p, ErtsProcSysTask *sys_task,
enqueue = ERTS_ENQUEUE_NOT;
n |= enable_flags;
+ if (sys_task && ERTS_PSFLGS_GET_ACT_PRIO(a) > task_prio) {
+ /* elevate prio for system task... */
+ n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
+ n |= (task_prio << ERTS_PSFLGS_ACT_PRIO_OFFSET);
+ }
+
if (!(a & (ERTS_PSFLG_RUNNING
| ERTS_PSFLG_RUNNING_SYS
| ERTS_PSFLG_DIRTY_RUNNING
@@ -6931,40 +6937,12 @@ static int
schedule_process_sys_task(Process *p, erts_aint32_t prio, ErtsProcSysTask *st,
erts_aint32_t *fail_state_p)
{
- erts_aint32_t fail_state, state;
-
- fail_state = *fail_state_p;
-
- /* Elevate priority if needed. */
- state = erts_atomic32_read_acqb(&p->state);
- if (ERTS_PSFLGS_GET_ACT_PRIO(state) <= prio) {
- if (state & fail_state) {
- *fail_state_p = state & fail_state;
- return 0;
- }
- }
- else {
- erts_aint32_t n, a, e;
-
- a = state;
- do {
- if (a & fail_state) {
- *fail_state_p = a & fail_state;
- return 0;
- }
- if (ERTS_PSFLGS_GET_ACT_PRIO(a) <= prio) {
- n = a;
- break;
- }
- n = e = a;
- n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
- n |= (prio << ERTS_PSFLGS_ACT_PRIO_OFFSET);
- a = erts_atomic32_cmpxchg_nob(&p->state, n, e);
- } while (a != e);
-
- state = n;
+ erts_aint32_t fail_state = *fail_state_p;
+ erts_aint32_t state = erts_atomic32_read_acqb(&p->state);
+ if (state & fail_state) {
+ *fail_state_p = state & fail_state;
+ return 0;
}
-
return !(active_sys_enqueue(p, st, prio, ERTS_PSFLG_SYS_TASKS,
state, fail_state_p) & fail_state);
}
@@ -9143,11 +9121,10 @@ erts_set_process_priority(Process *p, Eterm value)
}
max_qbit = 0;
- ASSERT((a & ERTS_PSFLG_SYS_TASKS)
- ? !!p->sys_task_qs
- : !p->sys_task_qs);
- if (a & ERTS_PSFLG_SYS_TASKS)
+ if (a & ERTS_PSFLG_SYS_TASKS) {
+ ASSERT(p->sys_task_qs);
max_qbit |= p->sys_task_qs->qmask;
+ }
if (a & ERTS_PSFLG_DELAYED_SYS) {
ErtsProcSysTaskQs *qs;
qs = ERTS_PROC_GET_DELAYED_GC_TASK_QS(p);
--
2.26.2