add code to provide simple wait condition handling.
authordlg <dlg@openbsd.org>
Thu, 14 Dec 2017 00:41:58 +0000 (00:41 +0000)
committerdlg <dlg@openbsd.org>
Thu, 14 Dec 2017 00:41:58 +0000 (00:41 +0000)
this will be used to replace the bare sleep_state handling in a
bunch of places, starting with the barriers.

share/man/man9/Makefile
share/man/man9/cond_init.9 [new file with mode: 0644]
sys/kern/kern_synch.c
sys/sys/proc.h
sys/sys/systm.h

index 9876038..b9942f0 100644 (file)
@@ -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 (file)
index 0000000..1f6ff24
--- /dev/null
@@ -0,0 +1,108 @@
+.\"    $OpenBSD: cond_init.9,v 1.1 2017/12/14 00:41:58 dlg Exp $ */
+.\"
+.\" Copyright (c) 2017 David Gwynne <dlg@openbsd.org>
+.\"
+.\" 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
index 7fb2344..ea28288 100644 (file)
@@ -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);
+       }
+}
index d65efbf..1addf75 100644 (file)
@@ -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
index 82abf9b..04326d9 100644 (file)
@@ -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);