+/* FETCH_STORE sets "fet" to the value fetched from "mem" and then stores
+ "sto" there. The fetch and store are done atomically, so once the fetch
+ has been done no other thread or processor can fetch from there before
+ the store is done.
+
+ The operands are scm_t_bits, fet and sto are plain variables, mem is a
+ memory location (ie. an lvalue).
+
+ ENHANCE-ME: Add more cpu-specifics. glibc atomicity.h has some of the
+ sort of thing required. FETCH_STORE could become some sort of
+ compare-and-store if that better suited what various cpus do. */
+
+#if defined (__GNUC__) && defined (i386) && SIZEOF_SCM_T_BITS == 4
+/* This is for i386 with the normal 32-bit scm_t_bits. The xchg instruction
+ is atomic on a single processor, and it automatically asserts the "lock"
+ bus signal so it's atomic on a multi-processor (no need for the lock
+ prefix on the instruction).
+
+ The mem operand is read-write but "+" is not used since old gcc
+ (eg. 2.7.2) doesn't support that. "1" for the mem input doesn't work
+ (eg. gcc 3.3) when mem is a pointer dereference like current usage below.
+ Having mem as a plain input should be ok though. It tells gcc the value
+ is live, but as an "m" gcc won't fetch it itself (though that would be
+ harmless). */
+
+#define FETCH_STORE(fet,mem,sto) \
+ do { \
+ asm ("xchg %0, %1" \
+ : "=r" (fet), "=m" (mem) \
+ : "0" (sto), "m" (mem)); \
+ } while (0)
+#endif
+
+#ifndef FETCH_STORE
+/* This is a generic version, with a mutex to ensure the operation is
+ atomic. Unfortunately this approach probably makes arbiters no faster
+ than mutexes (though still using less memory of course), so some
+ CPU-specifics are highly desirable. */
+#define FETCH_STORE(fet,mem,sto) \
+ do { \
+ scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex); \
+ (fet) = (mem); \
+ (mem) = (sto); \
+ scm_i_pthread_mutex_unlock (&scm_i_misc_mutex); \
+ } while (0)
+#endif
+