> Date: Mon, 30 Nov 2015 16:28:55 +1000 > From: David Gwynne <da...@gwynne.id.au> > > 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.
Never been a big fan of adding interfaces before we have an actual use case. I might have one though in inteldrm(4). But I'll need to look a little bit deeper into that. One problem with the interface is that it doesn't really work for a taskq that has multiple worker threads isn't it? > 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 > >