BUG/MAJOR: tasklets: Make sure he tasklet can't run twice
tasklets were originally designed to alway run on only one thread, so it was not possible to have it run on 2 threads concurrently. The API has been extended so that another thread may wake the tasklet, the idea was still that we wanted to have it run on one thread only. However, the way it's been done meant that unless a tasklet was bound to a specific tid with tasklet_set_tid(), or we explicitely used tasklet_wakeup_on() to specify the thread for the target to run on, it would be scheduled to run on the current thread. This is in fact a desirable feature. There is however a race condition in which the tasklet would be scheduled on a thread, while it is running on another. This could lead to the same tasklet to run on multiple threads, which we do not want. To fix this, just do what we already do for regular tasks, set the "TASK_RUNNING" flag, and when it's time to execute the tasklet, wait until that flag is gone. Only one case has been found in the current code, where the tasklet could run on different threads depending on who wakes it up, in the leastconn load balancer, since commit 627280e15f03755b8f59f0191cd6d6bcad5afeb3. It should not be a problem in practice, as the function called can be called concurrently. If a bug is eventually found in relation to this problem, and this patch should be backported, the following patches should be backported too : MEDIUM: quic: Make sure we return the tasklet from quic_accept_run MEDIUM: quic: Make sure we return NULL in quic_conn_app_io_cb if needed MEDIUM: quic: Make sure we return the tasklet from qcc_io_cb MEDIUM: mux_fcgi: Make sure we return the tasklet from fcgi_deferred_shut MEDIUM: listener: Make sure w ereturn the tasklet from accept_queue_process MEDIUM: checks: Make sure we return the tasklet from srv_chk_io_cb
This commit is contained in:
parent
09f5501bb9
commit
9240cd4a27
14
src/task.c
14
src/task.c
@ -599,11 +599,19 @@ unsigned int run_tasks_from_lists(unsigned int budgets[])
|
||||
|
||||
if (t->state & TASK_F_TASKLET) {
|
||||
/* this is a tasklet */
|
||||
state = _HA_ATOMIC_FETCH_AND(&t->state, TASK_PERSISTENT);
|
||||
__ha_barrier_atomic_store();
|
||||
state = _HA_ATOMIC_LOAD(&t->state);
|
||||
do {
|
||||
while (unlikely(state & TASK_RUNNING)) {
|
||||
__ha_cpu_relax();
|
||||
state = _HA_ATOMIC_LOAD(&t->state);
|
||||
}
|
||||
} while (!_HA_ATOMIC_CAS(&t->state, &state, (state & TASK_PERSISTENT) | TASK_RUNNING));
|
||||
|
||||
|
||||
if (likely(!(state & TASK_KILLED))) {
|
||||
process(t, ctx, state);
|
||||
t = process(t, ctx, state);
|
||||
if (t != NULL)
|
||||
_HA_ATOMIC_AND(&t->state, ~TASK_RUNNING);
|
||||
}
|
||||
else {
|
||||
done++;
|
||||
|
Loading…
x
Reference in New Issue
Block a user