while playing with some options around running an interfaces send
queue, i came up with the following. if you've deferred work to a
taskq and you're not reference counting, this can help you guarantee
that any work before a point has completed before proceeding.
think of it like intr_barrier.
i dont currently have a need for this right now, so there's no real
pressure to put this in. it's more a backup.
if someone oks it i will happily commit it though.
Index: share/man/man9/task_add.9
===================================================================
RCS file: /cvs/src/share/man/man9/task_add.9,v
retrieving revision 1.16
diff -u -p -r1.16 task_add.9
--- share/man/man9/task_add.9 14 Sep 2015 15:14:55 -0000 1.16
+++ share/man/man9/task_add.9 30 Nov 2015 06:24:29 -0000
@@ -20,6 +20,7 @@
.Sh NAME
.Nm taskq_create ,
.Nm taskq_destroy ,
+.Nm taskq_barrier ,
.Nm task_set ,
.Nm task_add ,
.Nm task_del ,
@@ -37,6 +38,8 @@
.Ft void
.Fn taskq_destroy "struct taskq *tq"
.Ft void
+.Fn taskq_barrier "struct taskq *tq"
+.Ft void
.Fn task_set "struct task *t" "void (*fn)(void *)" "void *arg"
.Ft int
.Fn task_add "struct taskq *tq" "struct task *t"
@@ -88,6 +91,15 @@ Calling
against the system taskq is an error and will lead to undefined
behaviour or a system fault.
.Pp
+.Fn taskq_barrier
+guarantees that any task that was running on the
+.Fa tq
+taskq when the barrier was called has finished by the time the barrier
+returns.
+.Fn taskq_barrier
+is only supported on taskqs serviced by 1 thread,
+and may not be called by a task running in the specified taskq.
+.Pp
It is the responsibility of the caller to provide the
.Fn task_set ,
.Fn task_add ,
@@ -163,6 +175,8 @@ argument given in
and
.Fn taskq_destroy
can be called during autoconf, or from process context.
+.Fn taskq_barrier
+can be called from process context.
.Fn task_set ,
.Fn task_add ,
and
Index: share/man/man9/Makefile
===================================================================
RCS file: /cvs/src/share/man/man9/Makefile,v
retrieving revision 1.262
diff -u -p -r1.262 Makefile
--- share/man/man9/Makefile 25 Nov 2015 03:09:57 -0000 1.262
+++ share/man/man9/Makefile 30 Nov 2015 06:24:29 -0000
@@ -397,6 +397,7 @@ MLINKS+=systrace.9 systrace_redirect.9 \
systrace.9 systrace_fork.9 systrace.9 systrace_exit.9
MLINKS+=task_add.9 taskq_create.9 \
task_add.9 taskq_destroy.9 \
+ task_add.9 taskq_barrier.9 \
task_add.9 task_set.9 \
task_add.9 task_del.9 \
task_add.9 TASK_INITIALIZER.9
Index: sys/sys/task.h
===================================================================
RCS file: /cvs/src/sys/sys/task.h,v
retrieving revision 1.8
diff -u -p -r1.8 task.h
--- sys/sys/task.h 9 Feb 2015 03:15:41 -0000 1.8
+++ sys/sys/task.h 30 Nov 2015 06:24:29 -0000
@@ -39,6 +39,7 @@ extern struct taskq *const systqmp;
struct taskq *taskq_create(const char *, unsigned int, int, unsigned int);
void taskq_destroy(struct taskq *);
+void taskq_barrier(struct taskq *);
void task_set(struct task *, void (*)(void *), void *);
int task_add(struct taskq *, struct task *);
Index: sys/kern/kern_task.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_task.c,v
retrieving revision 1.15
diff -u -p -r1.15 kern_task.c
--- sys/kern/kern_task.c 19 Nov 2015 13:19:24 -0000 1.15
+++ sys/kern/kern_task.c 30 Nov 2015 06:24:29 -0000
@@ -22,6 +22,7 @@
#include <sys/mutex.h>
#include <sys/kthread.h>
#include <sys/task.h>
+#include <sys/proc.h>
#define TASK_ONQUEUE 1
@@ -68,6 +69,7 @@ struct taskq *const systqmp = &taskq_sys
void taskq_init(void); /* called in init_main.c */
void taskq_create_thread(void *);
+void taskq_barrier_task(void *);
int taskq_sleep(const volatile void *, struct mutex *, int,
const char *, int);
int taskq_next_work(struct taskq *, struct task *, sleepfn);
@@ -176,6 +178,30 @@ taskq_create_thread(void *arg)
} while (tq->tq_running < tq->tq_nthreads);
mtx_leave(&tq->tq_mtx);
+}
+
+void
+taskq_barrier(struct taskq *tq)
+{
+ struct sleep_state sls;
+ unsigned int notdone = 1;
+ struct task t = TASK_INITIALIZER(taskq_barrier_task, ¬done);
+
+ task_add(tq, &t);
+
+ while (notdone) {
+ sleep_setup(&sls, ¬done, PWAIT, "tqbar");
+ sleep_finish(&sls, notdone);
+ }
+}
+
+void
+taskq_barrier_task(void *p)
+{
+ unsigned int *notdone = p;
+
+ *notdone = 0;
+ wakeup_one(notdone);
}
void