From: dlg Date: Thu, 14 Dec 2017 00:41:58 +0000 (+0000) Subject: add code to provide simple wait condition handling. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=0d158b2bc03d5e86f4220bdfdd06967891b50c6f;p=openbsd add code to provide simple wait condition handling. this will be used to replace the bare sleep_state handling in a bunch of places, starting with the barriers. --- diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index 98760385c02..b9942f0bd27 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.287 2017/06/19 23:44:11 dlg Exp $ +# $OpenBSD: Makefile,v 1.288 2017/12/14 00:41:58 dlg Exp $ # $NetBSD: Makefile,v 1.4 1996/01/09 03:23:01 thorpej Exp $ # Makefile for section 9 (kernel function and variable) manual pages. @@ -9,8 +9,8 @@ MAN= aml_evalnode.9 atomic_add_int.9 atomic_cas_uint.9 \ 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 \ diff --git a/share/man/man9/cond_init.9 b/share/man/man9/cond_init.9 new file mode 100644 index 00000000000..1f6ff24d24c --- /dev/null +++ b/share/man/man9/cond_init.9 @@ -0,0 +1,108 @@ +.\" $OpenBSD: cond_init.9,v 1.1 2017/12/14 00:41:58 dlg Exp $ */ +.\" +.\" 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: December 14 2017 $ +.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 diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c index 7fb23449560..ea28288d375 100644 --- a/sys/kern/kern_synch.c +++ b/sys/kern/kern_synch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_synch.c,v 1.142 2017/12/04 09:38:20 mpi Exp $ */ +/* $OpenBSD: kern_synch.c,v 1.143 2017/12/14 00:41:58 dlg Exp $ */ /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */ /* @@ -704,3 +704,31 @@ refcnt_finalize(struct refcnt *r, const char *wmesg) 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); + } +} diff --git a/sys/sys/proc.h b/sys/sys/proc.h index d65efbfd486..1addf7529cd 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.242 2017/12/12 07:55:36 deraadt Exp $ */ +/* $OpenBSD: proc.h,v 1.243 2017/12/14 00:41:58 dlg Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -557,6 +557,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 diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 82abf9b873e..04326d9db38 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systm.h,v 1.135 2017/11/13 14:41:46 mpi Exp $ */ +/* $OpenBSD: systm.h,v 1.136 2017/12/14 00:41:58 dlg Exp $ */ /* $NetBSD: systm.h,v 1.50 1996/06/09 04:55:09 briggs Exp $ */ /*- @@ -247,6 +247,11 @@ int sleep_finish_timeout(struct sleep_state *); 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);