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

openSUSE Build Service is sponsored by