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 .