BUG/MINOR: sched: properly cover for a rare MT_LIST_ADDQ() race
authorWilly Tarreau <w@1wt.eu>
Tue, 30 Jun 2020 11:46:21 +0000 (13:46 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 30 Jun 2020 12:06:19 +0000 (14:06 +0200)
commit1553b6657dd15565baaa0220ab232ba6c9cf7797
treea418d3778a50490630fbc3a7ea8d4b920a832917
parent9467f18d32e97e6063329fc613018188346fc1cf
BUG/MINOR: sched: properly cover for a rare MT_LIST_ADDQ() race

In commit 3ef7a190b ("MEDIUM: tasks: apply a fair CPU distribution
between tasklet classes") we compute a total weight to be used to
split the CPU time between queues. There is a mention that the
total cannot be null, wihch is based on the fact that we only get
there if thread_has_task() returns non-zero. But there is a very
small race which can break this assumption: if two threads conflict
on MT_LIST_ADDQ() on an empty shared list and both roll back before
trying again, there is the possibility that a first call to
MT_LIST_ISEMPTY() sees the first thread install itself, then the
second call will see the list empty when both roll back. Thus we
could proceed with the queue while it's temporarily empty and
compute max lengths using a divide by zero. This case is very
hard to trigger, it seldom happens on 16 threads at 400k req/s.

Let's simply test for max_total and leave the loop when we've not
found any work.

No backport is needed, that's 2.2-only.
src/task.c