Index: sys/sys/proc.h =================================================================== RCS file: /cvs/src/sys/sys/proc.h,v retrieving revision 1.240 diff -u -p -r1.240 proc.h --- sys/sys/proc.h 29 Aug 2017 02:51:27 -0000 1.240 +++ sys/sys/proc.h 12 Dec 2017 06:05:56 -0000 @@ -555,6 +555,12 @@ struct sleep_state { int sls_sig; }; +struct cond { + int c_wait; +}; + +#define COND_INITIALIZER() { 1 } + #if defined(MULTIPROCESSOR) void proc_trampoline_mp(void); /* XXX */ #endif Index: sys/sys/systm.h =================================================================== RCS file: /cvs/src/sys/sys/systm.h,v retrieving revision 1.135 diff -u -p -r1.135 systm.h --- sys/sys/systm.h 13 Nov 2017 14:41:46 -0000 1.135 +++ sys/sys/systm.h 12 Dec 2017 06:05:56 -0000 @@ -247,6 +247,11 @@ int sleep_finish_timeout(struct sleep_st int sleep_finish_signal(struct sleep_state *); void sleep_queue_init(void); +struct cond; +void cond_init(struct cond *); +void cond_wait(struct cond *, const char *); +void cond_signal(struct cond *); + struct mutex; struct rwlock; void wakeup_n(const volatile void *, int); Index: sys/kern/kern_synch.c =================================================================== RCS file: /cvs/src/sys/kern/kern_synch.c,v retrieving revision 1.142 diff -u -p -r1.142 kern_synch.c --- sys/kern/kern_synch.c 4 Dec 2017 09:38:20 -0000 1.142 +++ sys/kern/kern_synch.c 12 Dec 2017 06:05:56 -0000 @@ -704,3 +704,31 @@ refcnt_finalize(struct refcnt *r, const sleep_finish(&sls, refcnt); } } + +void +cond_init(struct cond *c) +{ + c->c_wait = 1; +} + +void +cond_signal(struct cond *c) +{ + c->c_wait = 0; + + wakeup_one(c); +} + +void +cond_wait(struct cond *c, const char *wmesg) +{ + struct sleep_state sls; + int wait; + + wait = c->c_wait; + while (wait) { + sleep_setup(&sls, c, PWAIT, wmesg); + wait = c->c_wait; + sleep_finish(&sls, wait); + } +} Index: sys/kern/kern_task.c =================================================================== RCS file: /cvs/src/sys/kern/kern_task.c,v retrieving revision 1.21 diff -u -p -r1.21 kern_task.c --- sys/kern/kern_task.c 13 Nov 2017 23:52:49 -0000 1.21 +++ sys/kern/kern_task.c 12 Dec 2017 06:05:56 -0000 @@ -183,25 +183,19 @@ taskq_create_thread(void *arg) void taskq_barrier(struct taskq *tq) { - struct sleep_state sls; - unsigned int notdone = 1; - struct task t = TASK_INITIALIZER(taskq_barrier_task, ¬done); + struct cond c = COND_INITIALIZER(); + struct task t = TASK_INITIALIZER(taskq_barrier_task, &c); task_add(tq, &t); - while (notdone) { - sleep_setup(&sls, ¬done, PWAIT, "tqbar"); - sleep_finish(&sls, notdone); - } + cond_wait(&c, "tqbar"); } void taskq_barrier_task(void *p) { - unsigned int *notdone = p; - - *notdone = 0; - wakeup_one(notdone); + struct cond *c = p; + cond_signal(c); } void Index: sys/kern/kern_timeout.c =================================================================== RCS file: /cvs/src/sys/kern/kern_timeout.c,v retrieving revision 1.51 diff -u -p -r1.51 kern_timeout.c --- sys/kern/kern_timeout.c 24 Nov 2017 02:36:53 -0000 1.51 +++ sys/kern/kern_timeout.c 12 Dec 2017 06:05:56 -0000 @@ -334,11 +334,10 @@ timeout_barrier(struct timeout *to) splx(splsoftclock()); KERNEL_UNLOCK(); } else { - int wait = 1; + struct cond c = COND_INITIALIZER(); struct timeout barrier; - struct sleep_state sls; - timeout_set_proc(&barrier, timeout_proc_barrier, &wait); + timeout_set_proc(&barrier, timeout_proc_barrier, &c); mtx_enter(&timeout_mutex); barrier.to_flags |= TIMEOUT_ONQUEUE; @@ -347,10 +346,7 @@ timeout_barrier(struct timeout *to) wakeup_one(&timeout_proc); - while (wait) { - sleep_setup(&sls, &wait, PSWP, "tmobar"); - sleep_finish(&sls, wait); - } + cond_wait(&c, "tmobar"); } } Index: sys/net/ifq.c =================================================================== RCS file: /cvs/src/sys/net/ifq.c,v retrieving revision 1.15 diff -u -p -r1.15 ifq.c --- sys/net/ifq.c 14 Nov 2017 08:44:11 -0000 1.15 +++ sys/net/ifq.c 12 Dec 2017 06:05:56 -0000 @@ -133,22 +133,15 @@ ifq_restart_task(void *p) void ifq_barrier(struct ifqueue *ifq) { - struct sleep_state sls; - unsigned int notdone = 1; - struct task t = TASK_INITIALIZER(ifq_barrier_task, ¬done); - - /* this should only be called from converted drivers */ - KASSERT(ISSET(ifq->ifq_if->if_xflags, IFXF_MPSAFE)); + struct cond c = COND_INITIALIZER(); + struct task t = TASK_INITIALIZER(ifq_barrier_task, &c); if (ifq->ifq_serializer == NULL) return; ifq_serialize(ifq, &t); - while (notdone) { - sleep_setup(&sls, ¬done, PWAIT, "ifqbar"); - sleep_finish(&sls, notdone); - } + cond_wait(&c, "ifqbar"); } void Index: share/man/man9/Makefile =================================================================== RCS file: /cvs/src/share/man/man9/Makefile,v retrieving revision 1.287 diff -u -p -r1.287 Makefile --- share/man/man9/Makefile 19 Jun 2017 23:44:11 -0000 1.287 +++ share/man/man9/Makefile 12 Dec 2017 06:05:56 -0000 @@ -9,8 +9,8 @@ MAN= aml_evalnode.9 atomic_add_int.9 ato audio.9 autoconf.9 \ bemtoh32.9 bio_register.9 boot.9 bpf_mtap.9 buffercache.9 bufq_init.9 \ bus_dma.9 bus_space.9 \ - copy.9 config_attach.9 config_defer.9 counters_alloc.9 cpumem_get.9 \ - crypto.9 \ + copy.9 cond_init.9 config_attach.9 config_defer.9 counters_alloc.9 \ + cpumem_get.9 crypto.9 \ delay.9 disk.9 disklabel.9 dma_alloc.9 dohooks.9 \ dostartuphooks.9 \ evcount.9 extent.9 fb_setup.9 file.9 fork1.9 \ Index: share/man/man9/cond_init.9 =================================================================== RCS file: share/man/man9/cond_init.9 diff -N share/man/man9/cond_init.9 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man9/cond_init.9 12 Dec 2017 06:05:56 -0000 @@ -0,0 +1,108 @@ +.\" $OpenBSD$ */ +.\" +.\" Copyright (c) 2017 David Gwynne +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: September 11 2015 $ +.Dt COND_INIT 9 +.Os +.Sh NAME +.Nm cond_init , +.Nm cond_wait , +.Nm cond_signal , +.Nm COND_INITIALIZER +.Nd wait condition API +.Sh SYNOPSIS +.In sys/systm.h +.Ft void +.Fn "cond_init" "struct cond *c" +.Ft void +.Fn "cond_wait" "struct cond *c" "const char *wmesg" +.Ft void +.Fn "cond_signal" "struct cond *c" +.Fn "COND_INITIALIZER" +.Sh DESCRIPTION +The wait condition API allows a thread to sleep while it waits for +a notification, aka signal, that pending work has completed. +.Pp +.Fn cond_init +initialises the wait condition +.Fa c +for use. +.Pp +.Fn cond_wait +is used to sleep on the wait condition +.Fa c +until whatever the thread is waiting on calls +.Fa cond_signal . +.Fa wmesg +is a pointer to a character string indicating the reason the thread +is sleeping. +.Pp +.Fa cond_signal +is used to notify the thread waiting on +.Fa c +that the work has finished and it may proceed. +.Pp +.Fn COND_INITIALIZER +initialises a declaration of a cond for use. +.Sh CONTEXT +.Fn cond_init , +and +.Fn cond_signal +can be called during autoconf, from process context, or from interrupt +context. +.Pp +.Fn cond_wait +can be called from process context. +.Sh EXAMPLES +.Xr taskq_barrier 9 +is implemented using the wait condition API. +The following is a commented copy of the implementation: +.Bd -literal +static void taskq_barrier_task(void *); + +void +taskq_barrier(struct taskq *tq) +{ + struct cond c; + struct task t; + + /* + * any currently running work has to have finished + * before this new task can be run. + */ + + cond_init(&c); + task_init(&t, taskq_barrier_task, &c); + + task_add(tq, &t); + + /* wait until the task runs and signals completion */ + cond_wait(&c, "tqbar"); +} + +static void +taskq_barrier_task(void *p) +{ + struct cond *c = p; + + /* + * all previous tasks have run, signal the thread waiting + * in taskq_barrier + */ + + cond_signal(c); +} +.Ed