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, &notdone);
+
+       task_add(tq, &t);
+
+       while (notdone) {
+               sleep_setup(&sls, &notdone, PWAIT, "tqbar");
+               sleep_finish(&sls, notdone);
+       }
+}
+
+void
+taskq_barrier_task(void *p)
+{
+       unsigned int *notdone = p;
+
+       *notdone = 0;
+       wakeup_one(notdone);
 }
 
 void

Reply via email to