> 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, &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