atomic_testandset_int seems unimplemented

Konstantin Belousov kostikbel at gmail.com
Sat Nov 7 11:30:18 UTC 2015


On Sat, Nov 07, 2015 at 06:10:32PM +1100, George Abdelmalik wrote:
> Hi,
> 
> My reading of atomic(9) implies that the atomic_testandset_* family of 
> functions should be present
> on the arm architecture, however I don't see any evidence of it in any 
> of the expected locations,
> ./sys/arm/include/atomic-v4.h
> ./sys/arm/include/atomic-v6.h
> ./sys/arm/include/atomic.h
> 
> Is there some impediment within the architecture which doesn't make that 
> semantic possible or is
> it just that there is no in-tree consumer yet?
No consumers, apparently.  testandset has somewhat rarely needed semantic,
and readandclear semantic is not complimentary, to confuse the users even
more.

> 
> Any thoughts on this matter would be appreciated, or better yet a 
> possible implementation - sadly for
> me assembly is not my strength.

Below is the patch for ARMv6.  I did not tested the _64 implementation,
and I also doubt that we run in big endian mode for ARMv6 at all.
Do you also need an implementation for ARMv5 ?

diff --git a/sys/arm/include/atomic-v6.h b/sys/arm/include/atomic-v6.h
index d22f7e1..9ee8043 100644
--- a/sys/arm/include/atomic-v6.h
+++ b/sys/arm/include/atomic-v6.h
@@ -593,6 +593,60 @@ atomic_store_rel_long(volatile u_long *p, u_long v)
 	*p = v;
 }
 
+static __inline int
+atomic_testandset_32(volatile uint32_t *p, u_int v)
+{
+	uint32_t tmp, tmp2, res, mask;
+
+	mask = 1u << (v & 0x1f);
+	tmp = tmp2 = 0;
+	__asm __volatile(
+	"1:     ldrex   %0, [%3]        \n"
+	"       orr     %1, %0, %4      \n"
+	"       strex   %2, %1, [%3]    \n"
+	"       cmp     %2, #0          \n"
+	"       it      ne              \n"
+	"       bne     1b              \n"
+	: "=&r" (res), "=&r" (tmp), "=&r" (tmp2), "+&r" (p)
+	: "r" (mask)
+	: "cc", "memory");
+	return ((res & mask) != 0);
+}
+
+static __inline int
+atomic_testandset_int(volatile u_int *p, u_int v)
+{
+
+	return (atomic_testandset_32((volatile uint32_t *)p, v));
+}
+
+static __inline int
+atomic_testandset_long(volatile u_long *p, u_int v)
+{
+
+	return (atomic_testandset_32((volatile uint32_t *)p, v));
+}
+
+static __inline int
+atomic_testandset_64(volatile uint64_t *p, u_int v)
+{
+	volatile uint32_t *p32;
+
+	p32 = (volatile uint32_t *)p;
+#if BYTE_ORDER == LITTLE_ENDIAN
+	if (v >= 32) {
+		v &= 0x1f;
+		p32++;
+	}
+#else
+	if (v >= 32)
+		v &= 0x1f;
+	else
+		p32++;
+#endif
+	return (atomic_testandset_32(p32, v));
+}
+
 #undef ATOMIC_ACQ_REL
 #undef ATOMIC_ACQ_REL_LONG
 


More information about the freebsd-arm mailing list