From f85c8c06a8470e1cf308b3653d8943bc91d4a293 Mon Sep 17 00:00:00 2001 From: markj Date: Wed, 28 Nov 2018 17:00:18 +0000 Subject: [PATCH] MFC r340730, r340731: Add taskqueue_quiesce(9) and use it to implement taskq_wait(). PR: 227784 --- share/man/man9/Makefile | 1 + share/man/man9/taskqueue.9 | 10 +++++++++- sys/kern/subr_taskqueue.c | 28 ++++++++++++++++++++++------ sys/sys/taskqueue.h | 1 + 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 43fffdf4db7..f0fa693f612 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1814,6 +1814,7 @@ MLINKS+=taskqueue.9 TASK_INIT.9 \ taskqueue.9 TASKQUEUE_FAST_DEFINE_THREAD.9 \ taskqueue.9 taskqueue_free.9 \ taskqueue.9 taskqueue_member.9 \ + taskqueue.9 taskqueue_quiesce.9 \ taskqueue.9 taskqueue_run.9 \ taskqueue.9 taskqueue_set_callback.9 \ taskqueue.9 taskqueue_start_threads.9 \ diff --git a/share/man/man9/taskqueue.9 b/share/man/man9/taskqueue.9 index e9fc9f0aab0..33153896e8f 100644 --- a/share/man/man9/taskqueue.9 +++ b/share/man/man9/taskqueue.9 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 30, 2017 +.Dd November 21, 2018 .Dt TASKQUEUE 9 .Os .Sh NAME @@ -94,6 +94,8 @@ struct timeout_task; .Ft void .Fn taskqueue_drain_all "struct taskqueue *queue" .Ft void +.Fn taskqueue_quiesce "struct taskqueue *queue" +.Ft void .Fn taskqueue_block "struct taskqueue *queue" .Ft void .Fn taskqueue_unblock "struct taskqueue *queue" @@ -298,6 +300,12 @@ do not extend the wait time of and may complete after .Fn taskqueue_drain_all returns. +The +.Fn taskqueue_quiesce +function is used to wait for the queue to become empty and for all +running tasks to finish. +To avoid blocking indefinitely, the caller must ensure by some mechanism +that tasks will eventually stop being posted to the queue. .Pp The .Fn taskqueue_block diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index 0ec519df0d4..af7dbe76870 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -344,13 +344,13 @@ taskqueue_task_nop_fn(void *context, int pending) * have begun execution. Tasks queued during execution of * this function are ignored. */ -static void +static int taskqueue_drain_tq_queue(struct taskqueue *queue) { struct task t_barrier; if (STAILQ_EMPTY(&queue->tq_queue)) - return; + return (0); /* * Enqueue our barrier after all current tasks, but with @@ -370,6 +370,7 @@ taskqueue_drain_tq_queue(struct taskqueue *queue) */ while (t_barrier.ta_pending != 0) TQ_SLEEP(queue, &t_barrier, &queue->tq_mutex, PWAIT, "-", 0); + return (1); } /* @@ -377,13 +378,13 @@ taskqueue_drain_tq_queue(struct taskqueue *queue) * complete. Tasks that begin execution during the execution * of this function are ignored. */ -static void +static int taskqueue_drain_tq_active(struct taskqueue *queue) { struct taskqueue_busy tb_marker, *tb_first; if (TAILQ_EMPTY(&queue->tq_active)) - return; + return (0); /* Block taskq_terminate().*/ queue->tq_callouts++; @@ -410,6 +411,7 @@ taskqueue_drain_tq_active(struct taskqueue *queue) queue->tq_callouts--; if ((queue->tq_flags & TQ_FLAGS_ACTIVE) == 0) wakeup_one(queue->tq_threads); + return (1); } void @@ -580,8 +582,8 @@ taskqueue_drain_all(struct taskqueue *queue) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); TQ_LOCK(queue); - taskqueue_drain_tq_queue(queue); - taskqueue_drain_tq_active(queue); + (void)taskqueue_drain_tq_queue(queue); + (void)taskqueue_drain_tq_active(queue); TQ_UNLOCK(queue); } @@ -610,6 +612,20 @@ taskqueue_drain_timeout(struct taskqueue *queue, TQ_UNLOCK(queue); } +void +taskqueue_quiesce(struct taskqueue *queue) +{ + int ret; + + TQ_LOCK(queue); + do { + ret = taskqueue_drain_tq_queue(queue); + if (ret == 0) + ret = taskqueue_drain_tq_active(queue); + } while (ret != 0); + TQ_UNLOCK(queue); +} + static void taskqueue_swi_enqueue(void *context) { diff --git a/sys/sys/taskqueue.h b/sys/sys/taskqueue.h index dbef2e91d34..9aff621206d 100644 --- a/sys/sys/taskqueue.h +++ b/sys/sys/taskqueue.h @@ -91,6 +91,7 @@ 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_quiesce(struct taskqueue *queue); void taskqueue_free(struct taskqueue *queue); void taskqueue_run(struct taskqueue *queue); void taskqueue_block(struct taskqueue *queue); -- 2.45.0