From 8a6049c2680fe1bdacf53a90e4c3ff97bc791ec9 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 30 Jun 2020 11:48:48 +0200 Subject: [PATCH] MEDIUM: sched: create a new TASK_KILLED task flag This flag, when set, will be used to indicate that the task must die. At the moment this may only be placed by the task itself or by the scheduler when placing it into the TL_NORMAL queue. --- include/haproxy/task-t.h | 1 + src/task.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/haproxy/task-t.h b/include/haproxy/task-t.h index 88f2bdd94..cf86c0a3e 100644 --- a/include/haproxy/task-t.h +++ b/include/haproxy/task-t.h @@ -38,6 +38,7 @@ #define TASK_SHARED_WQ 0x0008 /* The task's expiration may be updated by other * threads, must be set before first queue/wakeup */ #define TASK_SELF_WAKING 0x0010 /* task/tasklet found waking itself */ +#define TASK_KILLED 0x0020 /* task/tasklet killed, may now be freed */ #define TASK_WOKEN_INIT 0x0100 /* woken up for initialisation purposes */ #define TASK_WOKEN_TIMER 0x0200 /* woken up because of expired timer */ diff --git a/src/task.c b/src/task.c index b65000b8f..7626e6037 100644 --- a/src/task.c +++ b/src/task.c @@ -379,7 +379,7 @@ unsigned int run_tasks_from_lists(unsigned int budgets[]) budgets[queue]--; t = (struct task *)LIST_ELEM(tl_queues[queue].n, struct tasklet *, list); - state = (t->state & (TASK_SHARED_WQ|TASK_SELF_WAKING)); + state = t->state & (TASK_SHARED_WQ|TASK_SELF_WAKING|TASK_KILLED); ti->flags &= ~TI_FL_STUCK; // this thread is still running activity[tid].ctxsw++; @@ -414,11 +414,18 @@ unsigned int run_tasks_from_lists(unsigned int budgets[]) } __ha_barrier_store(); - if (likely(process == process_stream)) + + /* Note for below: if TASK_KILLED arrived before we've read the state, we + * directly free the task. Otherwise it will be seen after processing and + * it's freed on the exit path. + */ + if (likely(!(state & TASK_KILLED) && process == process_stream)) t = process_stream(t, ctx, state); - else if (process != NULL) + else if (!(state & TASK_KILLED) && process != NULL) t = process(t, ctx, state); else { + if (task_in_wq(t)) + __task_unlink_wq(t); __task_free(t); sched->current = NULL; __ha_barrier_store(); @@ -440,7 +447,12 @@ unsigned int run_tasks_from_lists(unsigned int budgets[]) } state = _HA_ATOMIC_AND(&t->state, ~TASK_RUNNING); - if (state & TASK_WOKEN_ANY) + if (unlikely(state & TASK_KILLED)) { + if (task_in_wq(t)) + __task_unlink_wq(t); + __task_free(t); + } + else if (state & TASK_WOKEN_ANY) task_wakeup(t, 0); else task_queue(t);