> On 30 Nov 2015, at 5:54 PM, Mark Kettenis <[email protected]> wrote:
>
>> Date: Mon, 30 Nov 2015 16:28:55 +1000
>> From: David Gwynne <[email protected]>
>>
>> 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.
the diff is successfully backed up now though ;)
>
> One problem with the interface is that it doesn't really work for a
> taskq that has multiple worker threads isn't it?
the current implementation is restricted like that. i had a version that was
supposed to work for multiple threads but was a smorgasbord of use after frees.
i have an idea for another way of doing it if you think it is necessary.
dlg
>
>> 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
>>
>>