]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: threads: Atomically set TH_FL_SLEEPING and clr FL_NOTIFIED
authorOlivier Houchard <ohouchard@haproxy.com>
Wed, 4 Feb 2026 01:46:36 +0000 (01:46 +0000)
committerOlivier Houchard <ohouchard@haproxy.com>
Wed, 4 Feb 2026 06:13:06 +0000 (07:13 +0100)
When we're about to enter polling, atomically set TH_FL_SLEEPING and
remove TH_FL_NOTIFIED, instead of doing it in sequence. Otherwise,
another thread may sett that both the TH_FL_SLEEPING and the
TH_FL_NOTIFIED bits are set, and don't wake up the thread then it should
be doing that.
This prevents a bug where a thread is sleeping while it should be
handling a new connection, which can happen if there are very few
incoming connection. This is easy to reproduce when using only two
threads, and injecting with only one connection, the connection may then
never be handled.

This should be backported up to 2.8.

src/haproxy.c

index c4a755f5e654e6321baa2a7d6d4f345d03481eba..1ad4c58f84158bfaa89b6ee854795be85dbaac5d 100644 (file)
@@ -2918,9 +2918,12 @@ void run_poll_loop()
                if (thread_has_tasks())
                        activity[tid].wake_tasks++;
                else {
-                       _HA_ATOMIC_OR(&th_ctx->flags, TH_FL_SLEEPING);
-                       _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_NOTIFIED);
-                       __ha_barrier_atomic_store();
+                       unsigned int flags = _HA_ATOMIC_LOAD(&th_ctx->flags);
+
+                       while (unlikely(!HA_ATOMIC_CAS(&th_ctx->flags, &flags,
+(flags | TH_FL_SLEEPING) & ~TH_FL_NOTIFIED)))
+                               __ha_cpu_relax();
+
                        if (thread_has_tasks()) {
                                activity[tid].wake_tasks++;
                                _HA_ATOMIC_AND(&th_ctx->flags, ~TH_FL_SLEEPING);