#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 */
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++;
}
__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();
}
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);