From: Willy Tarreau Date: Wed, 10 Sep 2025 16:45:01 +0000 (+0200) Subject: BUG/MINOR: stick-table: make sure never to miss a process_table_expire update X-Git-Tag: v3.3-dev9~151 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2831cb104fa4cb528f27240a33ba84d27d7449b8;p=thirdparty%2Fhaproxy.git BUG/MINOR: stick-table: make sure never to miss a process_table_expire update In stktable_requeue_exp(), there's a tiny race at the beginning during which we check the task's expiration date to decide whether or not to wake process_table_expire() up. During this race, the task might just have finished running on its owner thread and we can miss a task_queue() opportunity, which probably explains why during testing it seldom happens that a few entries are left at the end. Let's perform a CAS to confirm the value is still the same before leaving. This way we're certain that our value has been seen at least once. This should be backported to 3.2. --- diff --git a/src/stick_table.c b/src/stick_table.c index 54d9699a6..b7f6f89bb 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -724,14 +724,18 @@ void stktable_requeue_exp(struct stktable *t, const struct stksess *ts) old_exp = HA_ATOMIC_LOAD(&t->exp_task->expire); new_exp = tick_first(expire, old_exp); - /* let's not go further if we're already up to date */ - if (new_exp == old_exp) + /* let's not go further if we're already up to date. We have + * to make sure the compared date doesn't change under us. + */ + if (new_exp == old_exp && + HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) return; HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock); - while (new_exp != old_exp && - !HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) { + while (!HA_ATOMIC_CAS(&t->exp_task->expire, &old_exp, new_exp)) { + if (new_exp == old_exp) + break; __ha_cpu_relax(); new_exp = tick_first(expire, old_exp); }