On Tue, Mar 08, 2022 at 04:55:56PM +0100, Alexander Bluhm wrote:
> Once we had the discussion where we need the READ_ONCE() macro.  As
> modern C compiler has much freedom how to access memory, I came to
> the conclusion that it would be wise to use READ_ONCE() and
> WRITE_ONCE() everywhere when we use atomic operations variables.
> Using atomic operations on one side and do whatever the compiler
> thinks at the other side of the variable feels wrong.
> 
> The rule use READ_ONCE, WRITE_ONCE, atomic_inc, atomic_dec consistently
> would be easy to follow.  Thinking about where the compiler might
> reorder things and break MP code is much more complicated.
>
> Do we want to go this direction?

mvs@ mentioned that FreeBSD has atomic load and store instructions
for that.  I decided to implement them as static inline functions
as they provide stronger type checks.  Also I add them for int and
long only, everything else is not atomic.

> If yes, here is the change for struct refcnt and cond.  While there
> rename the field to r_refs which is easier to grep.

Note that the _init functions do not need atomic operations.  But
the whole idea is to make it consistent and have a simple rule.  If
an MP variable locking is marked as atomic, use the atomic_ functions.

As a bonus alpha gets the membar it needs.

ok?

bluhm

Index: sys/dev/pci/if_iwm.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.391
diff -u -p -r1.391 if_iwm.c
--- sys/dev/pci/if_iwm.c        8 Feb 2022 14:24:36 -0000       1.391
+++ sys/dev/pci/if_iwm.c        9 Mar 2022 18:52:52 -0000
@@ -9975,7 +9975,7 @@ iwm_init(struct ifnet *ifp)
 
        generation = ++sc->sc_generation;
 
-       KASSERT(sc->task_refs.refs == 0);
+       KASSERT(atomic_load_int(&sc->task_refs.r_refs) == 0);
        refcnt_init(&sc->task_refs);
 
        err = iwm_preinit(sc);
@@ -10116,7 +10116,7 @@ iwm_stop(struct ifnet *ifp)
        iwm_del_task(sc, systq, &sc->mac_ctxt_task);
        iwm_del_task(sc, systq, &sc->phy_ctxt_task);
        iwm_del_task(sc, systq, &sc->bgscan_done_task);
-       KASSERT(sc->task_refs.refs >= 1);
+       KASSERT(atomic_load_int(&sc->task_refs.r_refs) >= 1);
        refcnt_finalize(&sc->task_refs, "iwmstop");
 
        iwm_stop_device(sc);
Index: sys/dev/pci/if_iwx.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/dev/pci/if_iwx.c,v
retrieving revision 1.134
diff -u -p -r1.134 if_iwx.c
--- sys/dev/pci/if_iwx.c        21 Jan 2022 15:51:02 -0000      1.134
+++ sys/dev/pci/if_iwx.c        9 Mar 2022 18:53:50 -0000
@@ -8017,7 +8017,7 @@ iwx_init(struct ifnet *ifp)
        if (sc->sc_nvm.sku_cap_11n_enable)
                iwx_setup_ht_rates(sc);
 
-       KASSERT(sc->task_refs.refs == 0);
+       KASSERT(atomic_load_int(&sc->task_refs.r_refs) == 0);
        refcnt_init(&sc->task_refs);
        ifq_clr_oactive(&ifp->if_snd);
        ifp->if_flags |= IFF_RUNNING;
@@ -8139,7 +8139,7 @@ iwx_stop(struct ifnet *ifp)
        iwx_del_task(sc, systq, &sc->mac_ctxt_task);
        iwx_del_task(sc, systq, &sc->phy_ctxt_task);
        iwx_del_task(sc, systq, &sc->bgscan_done_task);
-       KASSERT(sc->task_refs.refs >= 1);
+       KASSERT(atomic_load_int(&sc->task_refs.r_refs) >= 1);
        refcnt_finalize(&sc->task_refs, "iwxstop");
 
        iwx_stop_device(sc);
Index: sys/kern/kern_synch.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_synch.c,v
retrieving revision 1.182
diff -u -p -r1.182 kern_synch.c
--- sys/kern/kern_synch.c       19 Feb 2022 23:56:18 -0000      1.182
+++ sys/kern/kern_synch.c       9 Mar 2022 18:57:53 -0000
@@ -804,7 +804,7 @@ sys___thrwakeup(struct proc *p, void *v,
 void
 refcnt_init(struct refcnt *r)
 {
-       r->refs = 1;
+       atomic_store_int(&r->r_refs, 1);
 }
 
 void
@@ -813,10 +813,10 @@ refcnt_take(struct refcnt *r)
 #ifdef DIAGNOSTIC
        u_int refcnt;
 
-       refcnt = atomic_inc_int_nv(&r->refs);
+       refcnt = atomic_inc_int_nv(&r->r_refs);
        KASSERT(refcnt != 0);
 #else
-       atomic_inc_int(&r->refs);
+       atomic_inc_int(&r->r_refs);
 #endif
 }
 
@@ -825,7 +825,7 @@ refcnt_rele(struct refcnt *r)
 {
        u_int refcnt;
 
-       refcnt = atomic_dec_int_nv(&r->refs);
+       refcnt = atomic_dec_int_nv(&r->r_refs);
        KASSERT(refcnt != ~0);
 
        return (refcnt == 0);
@@ -844,10 +844,10 @@ refcnt_finalize(struct refcnt *r, const 
        struct sleep_state sls;
        u_int refcnt;
 
-       refcnt = atomic_dec_int_nv(&r->refs);
+       refcnt = atomic_dec_int_nv(&r->r_refs);
        while (refcnt) {
                sleep_setup(&sls, r, PWAIT, wmesg, 0);
-               refcnt = r->refs;
+               refcnt = atomic_load_int(&r->r_refs);
                sleep_finish(&sls, refcnt);
        }
 }
@@ -855,13 +855,13 @@ refcnt_finalize(struct refcnt *r, const 
 void
 cond_init(struct cond *c)
 {
-       c->c_wait = 1;
+       atomic_store_int(&c->c_wait, 1);
 }
 
 void
 cond_signal(struct cond *c)
 {
-       c->c_wait = 0;
+       atomic_store_int(&c->c_wait, 0);
 
        wakeup_one(c);
 }
@@ -870,12 +870,12 @@ void
 cond_wait(struct cond *c, const char *wmesg)
 {
        struct sleep_state sls;
-       int wait;
+       unsigned int wait;
 
-       wait = c->c_wait;
+       wait = atomic_load_int(&c->c_wait);
        while (wait) {
                sleep_setup(&sls, c, PWAIT, wmesg, 0);
-               wait = c->c_wait;
+               wait = atomic_load_int(&c->c_wait);
                sleep_finish(&sls, wait);
        }
 }
Index: sys/netinet/ip_ipsp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipsp.c,v
retrieving revision 1.268
diff -u -p -r1.268 ip_ipsp.c
--- sys/netinet/ip_ipsp.c       4 Jan 2022 06:32:39 -0000       1.268
+++ sys/netinet/ip_ipsp.c       9 Mar 2022 18:50:02 -0000
@@ -565,7 +565,7 @@ tdb_printit(void *addr, int full, int (*
                DUMP(inext, "%p");
                DUMP(onext, "%p");
                DUMP(xform, "%p");
-               pr("%18s: %d\n", "refcnt", tdb->tdb_refcnt.refs);
+               pr("%18s: %d\n", "refcnt", tdb->tdb_refcnt.r_refs);
                DUMP(encalgxform, "%p");
                DUMP(authalgxform, "%p");
                DUMP(compalgxform, "%p");
@@ -625,7 +625,7 @@ tdb_printit(void *addr, int full, int (*
                pr(" %s", ipsp_address(&tdb->tdb_src, buf, sizeof(buf)));
                pr("->%s", ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)));
                pr(":%d", tdb->tdb_sproto);
-               pr(" #%d", tdb->tdb_refcnt.refs);
+               pr(" #%d", tdb->tdb_refcnt.r_refs);
                pr(" %08x\n", tdb->tdb_flags);
        }
 }
Index: sys/sys/atomic.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/atomic.h,v
retrieving revision 1.6
diff -u -p -r1.6 atomic.h
--- sys/sys/atomic.h    9 Mar 2019 06:14:21 -0000       1.6
+++ sys/sys/atomic.h    9 Mar 2022 18:48:42 -0000
@@ -1,6 +1,7 @@
 /*     $OpenBSD: atomic.h,v 1.6 2019/03/09 06:14:21 visa Exp $ */
 /*
  * Copyright (c) 2014 David Gwynne <d...@openbsd.org>
+ * Copyright (c) 2022 Alexander Bluhm <bl...@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
@@ -194,6 +195,50 @@ atomic_sub_long_nv(volatile unsigned lon
 #ifndef atomic_dec_long
 #define atomic_dec_long(_p) ((void)atomic_dec_long_nv(_p))
 #endif
+
+#ifdef _KERNEL
+/*
+ * atomic_load_* - read from memory
+ */
+
+static void membar_datadep_consumer(void);
+
+static inline unsigned int
+atomic_load_int(volatile unsigned int *p)
+{
+       unsigned int v;
+
+       v = *p;
+       membar_datadep_consumer();
+       return v;
+}
+
+static inline unsigned long
+atomic_load_long(volatile unsigned long *p)
+{
+       unsigned long v;
+
+       v = *p;
+       membar_datadep_consumer();
+       return v;
+}
+
+/*
+ * atomic_store_* - write to memory
+ */
+
+static inline void
+atomic_store_int(volatile unsigned int *p, unsigned int v)
+{
+       *p = v;
+}
+
+static inline void
+atomic_store_long(volatile unsigned long *p, unsigned long v)
+{
+       *p = v;
+}
+#endif /* _KERNEL */
 
 /*
  * memory barriers
Index: sys/sys/proc.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/proc.h,v
retrieving revision 1.328
diff -u -p -r1.328 proc.h
--- sys/sys/proc.h      25 Feb 2022 18:05:49 -0000      1.328
+++ sys/sys/proc.h      9 Mar 2022 19:01:14 -0000
@@ -589,10 +589,10 @@ struct sleep_state {
 };
 
 struct cond {
-       int     c_wait;
+       unsigned int    c_wait;         /* [a] initialized and waiting */
 };
 
-#define COND_INITIALIZER()             { 1 }
+#define COND_INITIALIZER()             { .c_wait = 1 }
 
 #if defined(MULTIPROCESSOR)
 void   proc_trampoline_mp(void);       /* XXX */
Index: sys/sys/refcnt.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/refcnt.h,v
retrieving revision 1.4
diff -u -p -r1.4 refcnt.h
--- sys/sys/refcnt.h    7 Jun 2016 07:53:33 -0000       1.4
+++ sys/sys/refcnt.h    9 Mar 2022 18:58:45 -0000
@@ -19,11 +19,16 @@
 #ifndef _SYS_REFCNT_H_
 #define _SYS_REFCNT_H_
 
+/*
+ * Locks used to protect struct members in this file:
+ *     a       atomic operations
+ */
+
 struct refcnt {
-       unsigned int refs;
+       unsigned int    r_refs;         /* [a] reference counter */
 };
 
-#define REFCNT_INITIALIZER()   { .refs = 1 }
+#define REFCNT_INITIALIZER()           { .r_refs = 1 }
 
 #ifdef _KERNEL
 
Index: share/man/man9/Makefile
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/share/man/man9/Makefile,v
retrieving revision 1.306
diff -u -p -r1.306 Makefile
--- share/man/man9/Makefile     1 Aug 2020 08:40:20 -0000       1.306
+++ share/man/man9/Makefile     9 Mar 2022 18:46:17 -0000
@@ -4,8 +4,8 @@
 #      Makefile for section 9 (kernel function and variable) manual pages.
 
 MAN=   aml_evalnode.9 atomic_add_int.9 atomic_cas_uint.9 \
-       atomic_dec_int.9 atomic_inc_int.9 atomic_setbits_int.9 \
-       atomic_sub_int.9 atomic_swap_uint.9 \
+       atomic_dec_int.9 atomic_inc_int.9 atomic_load_int.9 \
+       atomic_setbits_int.9 atomic_sub_int.9 atomic_swap_uint.9 \
        audio.9 autoconf.9 \
        bemtoh32.9 bio_register.9 bintimeadd.9 boot.9 bpf_mtap.9 buffercache.9 \
        bufq_init.9 bus_dma.9 bus_space.9 \
Index: share/man/man9/atomic_load_int.9
===================================================================
RCS file: share/man/man9/atomic_load_int.9
diff -N share/man/man9/atomic_load_int.9
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ share/man/man9/atomic_load_int.9    9 Mar 2022 10:20:06 -0000
@@ -0,0 +1,68 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2014 David Gwynne <d...@openbsd.org>
+.\" Copyright (c) 2022 Alexander Bluhm <bl...@openbsd.org>
+.\" All rights reserved.
+.\"
+.\" 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: February 13 2014 $
+.Dt ATOMIC_LOAD_INT 9
+.Os
+.Sh NAME
+.Nm atomic_load_int ,
+.Nm atomic_load_long ,
+.Nm atomic_store_long ,
+.Nm atomic_store_int
+.Nd atomic read and write memory operations
+.Sh SYNOPSIS
+.In sys/atomic.h
+.Ft unsigned int
+.Fn atomic_load_int "volatile unsigned int *p"
+.Ft unsigned long
+.Fn atomic_load_long "volatile unsigned long *p"
+.Ft void
+.Fn atomic_store_int "volatile unsigned int *p" "unsigned int v"
+.Ft void
+.Fn atomic_store_long "volatile unsigned long *p" "unsigned long v"
+.Sh DESCRIPTION
+The atomic_load and atomic_store set of functions provide an interface
+for atomically performing read or write memory operations with
+respect to interrupts and multiple processors in the system.
+.Pp
+The atomic_store functions change the value referenced by the pointer
+.Fa p
+to the value
+.Fa v .
+.Sh CONTEXT
+.Fn atomic_load_int ,
+.Fn atomic_load_long ,
+.Fn atomic_store_int ,
+and
+.Fn atomic_store_long
+can all be called during autoconf, from process context, or from
+interrupt context.
+.Sh RETURN VALUES
+.Nm atomic_load_int
+and
+.Nm atomic_load_long
+return the value at
+.Fa p .
+.Sh SEE ALSO
+.Xr atomic_add_int 9 ,
+.Xr atomic_add_long 9 ,
+.Xr atomic_sub_int 9 ,
+.Xr atomic_sub_long 9
+.Sh HISTORY
+The atomic_load and atomic_store functions first appeared in
+.Ox 7.1 .

Reply via email to