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.
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);