Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 17 Feb 2014 15:24:50 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r262063 - in stable/8: share/man/man9 sys/kern sys/sys
Message-ID:  <201402171524.s1HFOoDg009802@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Mon Feb 17 15:24:49 2014
New Revision: 262063
URL: http://svnweb.freebsd.org/changeset/base/262063

Log:
  MFC r258713,262062: add taskqueue_drain_all

Modified:
  stable/8/share/man/man9/Makefile
  stable/8/share/man/man9/taskqueue.9
  stable/8/sys/kern/subr_taskqueue.c
  stable/8/sys/sys/taskqueue.h
Directory Properties:
  stable/8/share/man/man9/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/kern/   (props changed)
  stable/8/sys/sys/   (props changed)

Modified: stable/8/share/man/man9/Makefile
==============================================================================
--- stable/8/share/man/man9/Makefile	Mon Feb 17 15:20:03 2014	(r262062)
+++ stable/8/share/man/man9/Makefile	Mon Feb 17 15:24:49 2014	(r262063)
@@ -1262,19 +1262,22 @@ MLINKS+=sysctl_ctx_init.9 sysctl_ctx_ent
 	sysctl_ctx_init.9 sysctl_ctx_free.9
 MLINKS+=taskqueue.9 TASK_INIT.9 \
 	taskqueue.9 TASK_INITIALIZER.9 \
+	taskqueue.9 taskqueue_block.9 \
 	taskqueue.9 taskqueue_create.9 \
 	taskqueue.9 taskqueue_create_fast.9 \
 	taskqueue.9 TASKQUEUE_DECLARE.9 \
 	taskqueue.9 TASKQUEUE_DEFINE.9 \
 	taskqueue.9 TASKQUEUE_DEFINE_THREAD.9 \
 	taskqueue.9 taskqueue_drain.9 \
+	taskqueue.9 taskqueue_drain_all.9 \
 	taskqueue.9 taskqueue_enqueue.9 \
 	taskqueue.9 taskqueue_enqueue_fast.9 \
 	taskqueue.9 TASKQUEUE_FAST_DEFINE.9 \
 	taskqueue.9 TASKQUEUE_FAST_DEFINE_THREAD.9 \
 	taskqueue.9 taskqueue_free.9 \
 	taskqueue.9 taskqueue_member.9 \
-	taskqueue.9 taskqueue_run.9
+	taskqueue.9 taskqueue_run.9 \
+	taskqueue.9 taskqueue_unblock.9
 MLINKS+=time.9 boottime.9 \
 	time.9 time_second.9 \
 	time.9 time_uptime.9

Modified: stable/8/share/man/man9/taskqueue.9
==============================================================================
--- stable/8/share/man/man9/taskqueue.9	Mon Feb 17 15:20:03 2014	(r262062)
+++ stable/8/share/man/man9/taskqueue.9	Mon Feb 17 15:24:49 2014	(r262063)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 18, 2009
+.Dd January 24, 2014
 .Dt TASKQUEUE 9
 .Os
 .Sh NAME
@@ -69,6 +69,12 @@ struct task {
 .Fn taskqueue_run_fast "struct taskqueue *queue"
 .Ft void
 .Fn taskqueue_drain "struct taskqueue *queue" "struct task *task"
+.Ft void
+.Fn taskqueue_drain_all "struct taskqueue *queue"
+.Ft void
+.Fn taskqueue_block "struct taskqueue *queue"
+.Ft void
+.Fn taskqueue_unblock "struct taskqueue *queue"
 .Ft int
 .Fn taskqueue_member "struct taskqueue *queue" "struct thread *td"
 .Fn TASK_INIT "struct task *task" "int priority" "task_fn_t *func" "void *context"
@@ -176,6 +182,73 @@ function is used to wait for the task to
 There is no guarantee that the task will not be
 enqueued after call to
 .Fn taskqueue_drain .
+If the caller wants to put the task into a known state,
+then before calling
+.Fn taskqueue_drain
+the caller should use out-of-band means to ensure that the task
+would not be enqueued.
+For example, if the task is enqueued by an interrupt filter, then
+the interrupt could be disabled.
+.Pp
+The
+.Fn taskqueue_drain_all
+function is used to wait for all pending and running tasks that
+are enqueued on the taskqueue to finish.
+The caller must arrange that the tasks are not re-enqueued.
+Note that
+.Fn taskqueue_drain_all
+currently does not handle tasks with delayed enqueueing.
+.Pp
+The
+.Fn taskqueue_block
+function blocks the taskqueue.
+It prevents any enqueued but not running tasks from being executed.
+Future calls to
+.Fn taskqueue_enqueue
+will enqueue tasks, but the tasks will not be run until
+.Fn taskqueue_unblock
+is called.
+Please note that
+.Fn taskqueue_block
+does not wait for any currently running tasks to finish.
+Thus, the
+.Fn taskqueue_block
+does not provide a guarantee that
+.Fn taskqueue_run
+is not running after
+.Fn taskqueue_block
+returns, but it does provide a guarantee that
+.Fn taskqueue_run
+will not be called again
+until
+.Fn taskqueue_unblock
+is called.
+If the caller requires a guarantee that
+.Fn taskqueue_run
+is not running, then this must be arranged by the caller.
+Note that if
+.Fn taskqueue_drain
+is called on a task that is enqueued on a taskqueue that is blocked by
+.Fn taskqueue_block ,
+then
+.Fn taskqueue_drain
+can not return until the taskqueue is unblocked.
+This can result in a deadlock if the thread blocked in
+.Fn taskqueue_drain
+is the thread that is supposed to call
+.Fn taskqueue_unblock .
+Thus, use of
+.Fn taskqueue_drain
+after
+.Fn taskqueue_block
+is discouraged, because the state of the task can not be known in advance.
+The same caveat applies to
+.Fn taskqueue_drain_all .
+.Pp
+The
+.Fn taskqueue_unblock
+function unblocks the previously blocked taskqueue.
+All enqueued tasks can be run after this call.
 .Pp
 The
 .Fn taskqueue_member

Modified: stable/8/sys/kern/subr_taskqueue.c
==============================================================================
--- stable/8/sys/kern/subr_taskqueue.c	Mon Feb 17 15:20:03 2014	(r262062)
+++ stable/8/sys/kern/subr_taskqueue.c	Mon Feb 17 15:24:49 2014	(r262063)
@@ -202,6 +202,15 @@ taskqueue_enqueue(struct taskqueue *queu
 	return 0;
 }
 
+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)
 {
@@ -254,6 +263,8 @@ taskqueue_run_locked(struct taskqueue *q
 		wakeup(task);
 	}
 	TAILQ_REMOVE(&queue->tq_active, &tb, tb_link);
+	if (TAILQ_EMPTY(&queue->tq_active))
+		wakeup(&queue->tq_active);
 }
 
 void
@@ -296,6 +307,25 @@ taskqueue_drain(struct taskqueue *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);
+}
+
 static void
 taskqueue_swi_enqueue(void *context)
 {

Modified: stable/8/sys/sys/taskqueue.h
==============================================================================
--- stable/8/sys/sys/taskqueue.h	Mon Feb 17 15:20:03 2014	(r262062)
+++ stable/8/sys/sys/taskqueue.h	Mon Feb 17 15:24:49 2014	(r262063)
@@ -55,6 +55,7 @@ int	taskqueue_start_threads(struct taskq
 				const char *name, ...) __printflike(4, 5);
 int	taskqueue_enqueue(struct taskqueue *queue, struct task *task);
 void	taskqueue_drain(struct taskqueue *queue, struct task *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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402171524.s1HFOoDg009802>