diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index cbe80deb3428..bfc941ee3326 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -300,6 +300,15 @@ taskqueue_enqueue_timeout(struct taskqueue *queue, return (res); } +static void +taskqueue_drain_running(struct taskqueue *queue) +{ + + while (!TAILQ_EMPTY(&queue->tq_active)) + TQ_SLEEP(queue, &queue->tq_active, &queue->tq_mutex, + PWAIT, "-", 0); +} + void taskqueue_block(struct taskqueue *queue) { @@ -350,6 +359,8 @@ taskqueue_run_locked(struct taskqueue *queue) wakeup(task); } TAILQ_REMOVE(&queue->tq_active, &tb, tb_link); + if (TAILQ_EMPTY(&queue->tq_active)) + wakeup(&queue->tq_active); } void @@ -433,6 +444,25 @@ taskqueue_drain(struct taskqueue *queue, struct task *task) TQ_UNLOCK(queue); } +void +taskqueue_drain_all(struct taskqueue *queue) +{ + struct task *task; + + if (!queue->tq_spin) + WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); + + TQ_LOCK(queue); + task = STAILQ_LAST(&queue->tq_queue, task, ta_link); + if (task != NULL) + while (task->ta_pending != 0) + TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0); + taskqueue_drain_running(queue); + KASSERT(STAILQ_EMPTY(&queue->tq_queue), + ("taskqueue queue is not empty after draining")); + TQ_UNLOCK(queue); +} + void taskqueue_drain_timeout(struct taskqueue *queue, struct timeout_task *timeout_task) diff --git a/sys/sys/taskqueue.h b/sys/sys/taskqueue.h index 7836262b233c..326eb91f59df 100644 --- a/sys/sys/taskqueue.h +++ b/sys/sys/taskqueue.h @@ -81,6 +81,7 @@ int taskqueue_cancel_timeout(struct taskqueue *queue, void taskqueue_drain(struct taskqueue *queue, struct task *task); void taskqueue_drain_timeout(struct taskqueue *queue, struct timeout_task *timeout_task); +void taskqueue_drain_all(struct taskqueue *queue); void taskqueue_free(struct taskqueue *queue); void taskqueue_run(struct taskqueue *queue); void taskqueue_block(struct taskqueue *queue);