Commits

Armin Rigo  committed c58a07f

Add fetch_and_add to the C sources and expose it via rlib.atomic_ops.

  • Participants
  • Parent commits 52ae351
  • Branches stm-gc-2

Comments (0)

Files changed (4)

File rpython/rlib/atomic_ops.py

 import py
-from pypy.tool.autopath import pypydir
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 
 
-cdir = py.path.local(pypydir) / 'translator' / 'stm'
-cdir2 = py.path.local(pypydir) / 'translator' / 'c'
+cdir = py.path.local(__file__).join('..', '..', 'translator', 'stm')
+cdir2 = py.path.local(__file__).join('..', '..', 'translator', 'c')
 
 eci = ExternalCompilationInfo(
     include_dirs = [cdir, cdir2],
            bool_cas((volatile unsigned long*)(ptr),  \\
                     (unsigned long)(old),            \\
                     (unsigned long)(_new))
+#define pypy_fetch_and_add(ptr, value)                    \\
+           fetch_and_add((volatile unsigned long*)(ptr),  \\
+                         (unsigned long)(value))
 '''],
 )
 
 
 bool_cas = rffi.llexternal('pypy_bool_cas', [llmemory.Address]*3, lltype.Bool,
                            compilation_info=eci, macro=True)
+fetch_and_add = rffi.llexternal('pypy_fetch_and_add', [llmemory.Address,
+                                                       lltype.Signed],
+                                lltype.Signed,
+                                compilation_info=eci, macro=True)

File rpython/rlib/test/test_atomic_ops.py

-from rpython.rlib.atomic_ops import bool_cas
+from rpython.rlib.atomic_ops import bool_cas, fetch_and_add
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 
 
     assert rffi.cast(lltype.Signed, a[0]) == 43
     #
     lltype.free(a, flavor='raw')
-    return 0
 
-def test_translate_bool_cas():
+def test_fetch_and_add():
+    a = lltype.malloc(ARRAY, 1, flavor='raw')
+    a[0] = rffi.cast(llmemory.Address, 42)
+    #
+    res = fetch_and_add(rffi.cast(llmemory.Address, a), -2)
+    assert res == 42
+    assert rffi.cast(lltype.Signed, a[0]) == 40
+    res = fetch_and_add(rffi.cast(llmemory.Address, a), 3)
+    assert res == 40
+    assert rffi.cast(lltype.Signed, a[0]) == 43
+    #
+    lltype.free(a, flavor='raw')
+
+def test_translate():
     from rpython.translator.c.test.test_genc import compile
 
-    f = compile(test_bool_cas, [])
+    def llf():
+        test_bool_cas()
+        test_fetch_and_add()
+        return 0
+
+    f = compile(llf, [])
     res = f()
     assert res == 0

File rpython/translator/stm/src_stm/atomic_ops.h

 
 #ifdef __llvm__
 #  define HAS_SYNC_BOOL_COMPARE_AND_SWAP
+#  define HAS_SYNC_FETCH_AND_ADD
 #endif
 
 #ifdef __GNUC__
 #  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
 #    define HAS_SYNC_BOOL_COMPARE_AND_SWAP
+#    define HAS_SYNC_FETCH_AND_ADD
 #  endif
 #endif
 
 /* end */
 #endif
 
+#ifdef HAS_SYNC_FETCH_AND_ADD
+#  define fetch_and_add __sync_fetch_and_add
+#else
+/* x86 (32 bits and 64 bits) */
+static inline Unsigned
+fetch_and_add(volatile Unsigned *ptr, Unsigned value)
+{
+    Unsigned prev;
+#if defined(__amd64__)
+    assert(sizeof(Unsigned) == 8);
+#elif defined(__i386__)
+    assert(sizeof(Unsigned) == 4);
+#else
+#   error "the custom version of fetch_and_add() is only for x86 or x86-64"
+#endif
+    asm volatile("lock;"
+#if defined(__amd64__)
+                 "xaddq %1, %2;"
+#else
+                 "xaddl %1, %2;"
+#endif
+                 : "=r"(prev)
+                 : "0"(value), "m"(*ptr)
+                 : "memory");
+    return prev;
+}
+/* end */
+#endif
+
 
 static inline void spinloop(void)
 {

File rpython/translator/stm/test/test_stmgcintf.c

 
 /************************************************************/
 
+void test_bool_cas(void)
+{
+    volatile Unsigned bv = 10;
+
+    assert(bool_cas(&bv, 10, 15));
+    assert(bv == 15);
+    assert(!bool_cas(&bv, 10, 15));
+    assert(bv == 15);
+    assert(!bool_cas(&bv, 10, 25));
+    assert(bv == 15);
+    assert(bool_cas(&bv, 15, 14));
+    assert(bv == 14);
+}
+
+void test_fetch_and_add(void)
+{
+    volatile Unsigned bv = 14;
+
+    assert(fetch_and_add(&bv, 2) == 14);
+    assert(bv == 16);
+    assert(fetch_and_add(&bv, 7) == 16);
+    assert(fetch_and_add(&bv, (Unsigned)-1) == 23);
+    assert(bv == 22);
+}
+
+/************************************************************/
+
 void test_set_get_del(void)
 {
     stm_set_tls((void *)42);
 
 int main(int argc, char **argv)
 {
+    XTEST(bool_cas);
+    XTEST(fetch_and_add);
+
     DescriptorInit();
     XTEST(set_get_del);
     XTEST(run_all_transactions);