Date: Fri, 3 Feb 2017 05:14:15 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Mateusz Guzik <mjguzik@gmail.com> Cc: Bruce Evans <brde@optusnet.com.au>, Mateusz Guzik <mjg@freebsd.org>, src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: Re: svn commit: r312975 - head/sys/i386/include Message-ID: <20170203040751.I2354@besplex.bde.org> In-Reply-To: <20170202014204.GA992@dft-labs.eu> References: <201701300224.v0U2Osj1010421@repo.freebsd.org> <20170130142123.V953@besplex.bde.org> <20170201214349.H1136@besplex.bde.org> <20170202014204.GA992@dft-labs.eu>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 2 Feb 2017, Mateusz Guzik wrote: > On Wed, Feb 01, 2017 at 10:12:57PM +1100, Bruce Evans wrote: >> On Mon, 30 Jan 2017, Bruce Evans wrote: >> >>> On Mon, 30 Jan 2017, Mateusz Guzik wrote: >>> >>>> Log: >>>> i386: add atomic_fcmpset >>>> >>>> Tested by: pho >>> >>> This is has some bugs and style bugs. >> >> This is still broken. The invalid asm breaks building at least atomic.o >> with gcc-4.2.1. >> >> Tested fix: >> ... > > Uh, I ended up with the same fix. Committed in r313080. Thanks. > Sorry for breakage in the first place. > >> The semantics of fcmpset seem to be undocumented. On x86, *expect is >> updated non-atomically by a store in the output parameter. I think >> cmpxchg updates the "a" register atomically, but then the output >> parameter causes this to be stored non-atomically to *expect. A better >> API would somehow return the "a" register and let the caller store it >> if it wants. Ordinary cmpset can be built on this by not storing, and >> the caller can do the store atomically to a different place if *expect >> is too volatile to be atomic. >> > > The primitive was modeled after atomic_compare_exchange_* from c11 > atomics. I don't see what's the benefit of storing the result > separately. > > As it is, the primitive fits nicely into loops like "inc not zero". > > Like this: > r = *counter; > for (;;) { > if (r == 0) > break; > if (atomic_fcmpset_int(counter, &r, r + 1)) > break; > // r we can loop back to re-test r > } You won't want to ifdef this for SMP, so the i386 implementation has further bugs like I expected (fcmpset is not implemented in the CPU_DISABLE_CMPXCHG case). >> Maybe just decouple the input parameter from the output parameter. The >> following works right (for an amd64 API): >> >> Y static __inline int >> Y atomic_xfcmpset_long(volatile u_long *dst, u_long *expect_out, u_long expect_in, >> Y u_long src) The output parameter is not well named in this or in fcmpset, since when the comparison fails it holds the compared copy of *dst, not of *expect_in, and otherwise it is not useful and holds a copy of src. >> If the caller doesn't want to use *expect_out, it passes a pointer to an >> unused local variable. The compiler can then optimize away the store >> since it is not hidden in the asm. > > _fcmpset is specifically for callers who want the value back. Ones which > don't can use the _cmpset variant. The main caller of _xfcmpset would be the _cmpset variantL static __inline int atomic_cmpset_int(volatile u_int *dst, u_int expect, u_int src) { u_int dummy __unused; return (atomic_xfcmpset_int(dst, &dummy, expect, src)); } Actually, _cmpset can be built out of _fcmpset even more easily: static __inline int atomic_cmpset_int(volatile u_int *dst, u_int expect, u_int src) { return (atomic_fcmpset_int(dst, &expect, src)); } This has to be a function since a macro would expose *&expect to clobbering. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170203040751.I2354>