svn commit: r312975 - head/sys/i386/include

Mateusz Guzik mjguzik at gmail.com
Thu Feb 2 01:42:10 UTC 2017


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:
> 
> X Index: i386/include/atomic.h
> X ===================================================================
> X --- i386/include/atomic.h	(revision 313007)
> X +++ i386/include/atomic.h	(working copy)
> X @@ -225,9 +225,9 @@
> X  	"	cmpxchgl %3,%1 ;	"
> X  	"       sete	%0 ;		"
> X  	"# atomic_cmpset_int"
> X -	: "=r" (res),			/* 0 */
> X +	: "=q" (res),			/* 0 */
> X  	  "+m" (*dst),			/* 1 */
> X -	  "+a" (*expect)			/* 2 */
> X +	  "+a" (*expect)		/* 2 */
> X  	: "r" (src)			/* 3 */
> X  	: "memory", "cc");
> X  	return (res);
> 

Uh, I ended up with the same fix. Committed in r313080.

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
}

> 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)
> Y {
> Y 	u_long expect;
> Y 	u_char res;
> Y Y 	expect = expect_in;
> Y 	__asm __volatile(
> Y 	"	" MPLOCKED "		"
> Y 	"	cmpxchgq %3,%1 ;	"
> Y 	"       sete	%0 ;		"
> Y 	"# atomic_fcmpset_long"
> Y 	: "=r" (res),			/* 0 */
> Y 	  "+m" (*dst),			/* 1 */
> Y 	  "+a" (expect)			/* 2 */
> Y 	: "r" (src)			/* 3 */
> Y 	: "memory", "cc");
> Y 	*expect_out = expect;
> 
> 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.

-- 
Mateusz Guzik <mjguzik gmail.com>


More information about the svn-src-all mailing list