]> granicus.if.org Git - libatomic_ops/commitdiff
ao-0.4 tarball import libatomic_ops-0_4
authorIvan Maidanski <ivmai@mail.ru>
Mon, 25 Jul 2011 09:50:29 +0000 (13:50 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Mon, 25 Jul 2011 09:50:29 +0000 (13:50 +0400)
Makefile
ao_sysdeps/acquire_release_volatile.h
ao_sysdeps/gcc/x86.h
ao_sysdeps/generic_pthread.h
atomic_ops.c
atomic_ops.h
atomic_ops_generalize.h
doc/README_atomic_ops.txt
test_atomic.c
test_atomic.template

index d2ebb046e2b9f0b930979ce0c6337458b8193081..d9f54e8b0a402dd99a2b61cb74e178b1d5505d09 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2003 by Hewlett-Packard Company.  All rights reserved.
+# Copyright (c) 2003 Hewlett-Packard Developlment Company, L.P.
 # 
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -68,11 +68,11 @@ atomic_ops.a: atomic_ops.o
        $(AR) ruc atomic_ops.a atomic_ops.o
        $(RANLIB) atomic_ops.a
 
-test_atomic: test_atomic.c test_atomic_include.h $(ATOMIC_OPS_HEADERS)
-       $(CC) $(CFLAGS) test_atomic.c -o test_atomic -lpthread
+test_atomic: test_atomic.c atomic_ops.c test_atomic_include.h $(ATOMIC_OPS_HEADERS)
+       $(CC) $(CFLAGS) test_atomic.c atomic_ops.c -o test_atomic -lpthread
 
-test_atomic_pthreads: test_atomic.c test_atomic_include.h $(ATOMIC_OPS_HEADERS)
-       $(CC) $(CFLAGS) -DAO_USE_PTHREAD_DEFS test_atomic.c -o test_atomic_pthreads -lpthread
+test_atomic_pthreads: test_atomic.c atomic_ops.c test_atomic_include.h $(ATOMIC_OPS_HEADERS)
+       $(CC) $(CFLAGS) -DAO_USE_PTHREAD_DEFS test_atomic.c atomic_ops.c -o test_atomic_pthreads -lpthread
 
 test_atomic_include.h: test_atomic.template
        sed -e s/XX// test_atomic.template > test_atomic_include.h
index 9f3d3c64933ba2a6cf1668d905bc2b359bee1d5b..378bdcb52c8c9fce9e5e137f53f3c4f640272bfb 100644 (file)
@@ -36,6 +36,7 @@ AO_load_acquire(volatile AO_T *p)
 AO_INLINE void
 AO_store_release(volatile AO_T *p, AO_T val)
 {
+  AO_compiler_barrier();       /* Empirically necessary. Gcc bug? */
   /* A normal volatile store generates an st.rel       */
   *p = val;
 }
index c73f2359d4baa535f0abf02be4978522e22d4337..69793a1620dcaf1ea4a0fb857e27babcc883748b 100644 (file)
@@ -65,6 +65,16 @@ AO_fetch_and_add_full (volatile AO_T *p, long incr)
 
 #define AO_HAVE_fetch_and_add_full
 
+/* Really only works for 486 and later */
+AO_INLINE void
+AO_or_full (volatile AO_T *p, AO_T incr)
+{
+  __asm__ __volatile__ ("lock; orl %1, %0" :
+                       "+m" (*p) : "r" (incr) : "memory");
+}
+
+#define AO_HAVE_or_full
+
 AO_INLINE AO_TS_T
 AO_test_and_set_full(volatile AO_T *addr)
 {
index e0e405ae40a289639af5473cb39f2ef09dbe366a..f5155246c6c92c6819ca966c3bec08e4c203ccc6 100644 (file)
 
 /* We define only the full barrier variants, and count on the          */
 /* generalization section below to fill in the rest.                   */
-static pthread_mutex_t AO_lock = PTHREAD_MUTEX_INITIALIZER;
+extern pthread_mutex_t AO_pt_lock;
 
 AO_INLINE void
 AO_nop_full()
 {
-  pthread_mutex_lock(&AO_lock);
-  pthread_mutex_unlock(&AO_lock);
+  pthread_mutex_lock(&AO_pt_lock);
+  pthread_mutex_unlock(&AO_pt_lock);
 }
 
 #define AO_HAVE_nop_full
@@ -46,9 +46,9 @@ AO_INLINE AO_T
 AO_load_full(volatile AO_T *addr)
 {
   AO_T result;
-  pthread_mutex_lock(&AO_lock);
+  pthread_mutex_lock(&AO_pt_lock);
   result = *addr;
-  pthread_mutex_unlock(&AO_lock);
+  pthread_mutex_unlock(&AO_pt_lock);
   return result;
 }
 
@@ -57,9 +57,9 @@ AO_load_full(volatile AO_T *addr)
 AO_INLINE void
 AO_store_full(volatile AO_T *addr, AO_T val)
 {
-  pthread_mutex_lock(&AO_lock);
+  pthread_mutex_lock(&AO_pt_lock);
   *addr = val;
-  pthread_mutex_unlock(&AO_lock);
+  pthread_mutex_unlock(&AO_pt_lock);
 }
 
 #define AO_HAVE_store_full
@@ -68,46 +68,56 @@ AO_INLINE AO_TS_VAL
 AO_test_and_set_full(volatile AO_TS_T *addr)
 {
   int result;
-  pthread_mutex_lock(&AO_lock);
+  pthread_mutex_lock(&AO_pt_lock);
   result = (int)(*addr);
   *addr = AO_TS_SET;
-  pthread_mutex_unlock(&AO_lock);
+  pthread_mutex_unlock(&AO_pt_lock);
   assert(result == AO_TS_SET || result == AO_TS_CLEAR);
   return result;
 }
 
 #define AO_HAVE_test_and_set_full
 
-static AO_T
-AO_fetch_and_add_full(volatile AO_T *p, long incr)
+AO_INLINE AO_T
+AO_fetch_and_add_full(volatile AO_T *p, AO_T incr)
 {
   AO_T tmp;
 
-  pthread_mutex_lock(&AO_lock);
+  pthread_mutex_lock(&AO_pt_lock);
   tmp = *p;
   *p = tmp + incr;
-  pthread_mutex_unlock(&AO_lock);
+  pthread_mutex_unlock(&AO_pt_lock);
   return tmp;
 }
 
 #define AO_HAVE_fetch_and_add_full
 
-#define AO_fetch_and_add1_full(addr) AO_fetch_and_add_full(addr,1)
-#define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,-1)
+AO_INLINE void
+AO_or_full(volatile AO_T *p, AO_T incr)
+{
+  AO_T tmp;
+
+  pthread_mutex_lock(&AO_pt_lock);
+  tmp = *p;
+  *p = (tmp | incr);
+  pthread_mutex_unlock(&AO_pt_lock);
+}
+
+#define AO_HAVE_or_full
 
 AO_INLINE int
 AO_compare_and_swap_full(volatile AO_T *addr,
                             AO_T old, AO_T new_val) 
 {
-  pthread_mutex_lock(&AO_lock);
+  pthread_mutex_lock(&AO_pt_lock);
   if (*addr == old)
     {
       *addr = new_val;
-      pthread_mutex_unlock(&AO_lock);
+      pthread_mutex_unlock(&AO_pt_lock);
       return 1;
     }
   else
-    pthread_mutex_unlock(&AO_lock);
+    pthread_mutex_unlock(&AO_pt_lock);
     return 0;
 }
 
index 33ecfacbbe9f62e1107cf49eb79c2931249f224b..8e93bd7bee8f064d556d5bc41640566fca2b9b3f 100644 (file)
@@ -37,7 +37,7 @@
  * Lock for pthreads-based implementation.
  */
 
-static pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t AO_pt_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /*
  * Out of line compare-and-swap emulation based on test and set.
index 36daee09a4ec88b616b153f15ecf5fb658321904..98db8f907a1df70713f7f9ef0eb02a7ffb1ddddd 100644 (file)
@@ -68,6 +68,7 @@
 /* AO_fetch_and_add                                            */
 /* AO_fetch_and_add1                                           */
 /* AO_fetch_and_sub1                                           */
+/* AO_or                                                       */
 /* AO_compare_and_swap                                         */
 /*                                                             */
 /* Note that atomicity guarantees are valid only if both       */
 /* AO_TS_SET, and returns the prior value.                     */
 /* An AO_TS_T clear location can be reset with the             */
 /* AO_CLEAR macro, which normally uses AO_store_release.       */
-/* AO_fetch_and_add takes an address and a long increment      */
+/* AO_fetch_and_add takes an address and an AO_T increment     */
 /* value.  The AO_fetch_and_add1 and AO_fetch_and_sub1 variants        */
 /* are provided, since they allow faster implementations on    */
-/* some hardware.                                              */
+/* some hardware. AO_or atomically ors an AO_T value into a    */
+/* memory location, but does not provide access to the original.*/
 /*                                                             */
 /* We expect this list to grow slowly over time.               */
 /*                                                             */
index 5a6c8726cb09b489bdccb8ab7b2b4eebb5f5fb48..315198f18cb8acfde96b786a026bda889b3029ea 100644 (file)
 #if defined(AO_HAVE_compare_and_swap_full) && \
     !defined(AO_HAVE_fetch_and_add_full)
    AO_INLINE AO_T
-   AO_fetch_and_add_full(volatile AO_T *addr, long incr)
+   AO_fetch_and_add_full(volatile AO_T *addr, AO_T incr)
    {
      AO_T old;
      do
 
 #if defined(AO_HAVE_fetch_and_add_full) &&\
     !defined(AO_HAVE_fetch_and_sub1_full)
-#  define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,-1)
+#  define AO_fetch_and_sub1_full(addr) AO_fetch_and_add_full(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_full
 #endif
 #if defined(AO_HAVE_fetch_and_add_release) &&\
     !defined(AO_HAVE_fetch_and_sub1_release)
-#  define AO_fetch_and_sub1_release(addr) AO_fetch_and_add_release(addr,-1)
+#  define AO_fetch_and_sub1_release(addr) \
+       AO_fetch_and_add_release(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_release
 #endif
 #if defined(AO_HAVE_fetch_and_add_acquire) &&\
     !defined(AO_HAVE_fetch_and_sub1_acquire)
-#  define AO_fetch_and_sub1_acquire(addr) AO_fetch_and_add_acquire(addr,-1)
+#  define AO_fetch_and_sub1_acquire(addr) \
+       AO_fetch_and_add_acquire(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_acquire
 #endif
 #if defined(AO_HAVE_fetch_and_add_write) &&\
     !defined(AO_HAVE_fetch_and_sub1_write)
-#  define AO_fetch_and_sub1_write(addr) AO_fetch_and_add_write(addr,-1)
+#  define AO_fetch_and_sub1_write(addr) \
+       AO_fetch_and_add_write(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_write
 #endif
 #if defined(AO_HAVE_fetch_and_add_read) &&\
     !defined(AO_HAVE_fetch_and_sub1_read)
-#  define AO_fetch_and_sub1_read(addr) AO_fetch_and_add_read(addr,-1)
+#  define AO_fetch_and_sub1_read(addr) \
+       AO_fetch_and_add_read(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_read
 #endif
 #if defined(AO_HAVE_fetch_and_add_release_write) &&\
     !defined(AO_HAVE_fetch_and_sub1_release_write)
 #  define AO_fetch_and_sub1_release_write(addr) \
-       AO_fetch_and_add_release_write(addr,-1)
+       AO_fetch_and_add_release_write(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_release_write
 #endif
 #if defined(AO_HAVE_fetch_and_add_acquire_read) &&\
     !defined(AO_HAVE_fetch_and_sub1_acquire_read)
 #  define AO_fetch_and_sub1_acquire_read(addr) \
-       AO_fetch_and_add_acquire_read(addr,-1)
+       AO_fetch_and_add_acquire_read(addr,(AO_T)(-1))
 #  define AO_HAVE_fetch_and_sub1_acquire_read
 #endif
 
 #  define AO_HAVE_fetch_and_sub1_acquire_read
 #endif
 
+/* Atomic or */
+#if defined(AO_HAVE_compare_and_swap_full) && \
+    !defined(AO_HAVE_or_full)
+   AO_INLINE void
+   AO_or_full(volatile AO_T *addr, AO_T incr)
+   {
+     AO_T old;
+     do
+       {
+         old = *addr;
+       }
+     while (!AO_compare_and_swap_full(addr, old, (old | incr)));
+   }
+#  define AO_HAVE_or_full
+#endif
+
+#if defined(AO_HAVE_or_full)
+#  if !defined(AO_HAVE_or_release)
+#    define AO_or_release(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_release
+#  endif
+#  if !defined(AO_HAVE_or_acquire)
+#    define AO_or_acquire(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_acquire
+#  endif
+#  if !defined(AO_HAVE_or_write)
+#    define AO_or_write(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_write
+#  endif
+#  if !defined(AO_HAVE_or_read)
+#    define AO_or_read(addr, val) \
+        AO_or_full(addr, val)
+#    define AO_HAVE_or_read
+#  endif
+#endif /* AO_HAVE_or_full */
+
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_release)
+#  define AO_or(addr, val) \
+       AO_or_release(addr, val)
+#  define AO_HAVE_or
+#endif
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_acquire)
+#  define AO_or(addr, val) \
+       AO_or_acquire(addr, val)
+#  define AO_HAVE_or
+#endif
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_write)
+#  define AO_or(addr, val) \
+       AO_or_write(addr, val)
+#  define AO_HAVE_or
+#endif
+#if !defined(AO_HAVE_or) && \
+    defined(AO_HAVE_or_read)
+#  define AO_or(addr, val) \
+       AO_or_read(addr, val)
+#  define AO_HAVE_or
+#endif
+
+#if defined(AO_HAVE_or_acquire) &&\
+    defined(AO_HAVE_nop_full) && \
+    !defined(AO_HAVE_or_full)
+#  define AO_or_full(addr, val) \
+       (AO_nop_full(), AO_or_acquire(addr, val))
+#endif
+
+#if !defined(AO_HAVE_or_release_write) && \
+    defined(AO_HAVE_or_write)
+#  define AO_or_release_write(addr, val) \
+       AO_or_write(addr, val)
+#  define AO_HAVE_or_release_write
+#endif
+#if !defined(AO_HAVE_or_release_write) && \
+    defined(AO_HAVE_or_release)
+#  define AO_or_release_write(addr, val) \
+       AO_or_release(addr, val)
+#  define AO_HAVE_or_release_write
+#endif
+#if !defined(AO_HAVE_or_acquire_read) && \
+    defined(AO_HAVE_or_read)
+#  define AO_or_acquire_read(addr, val) \
+       AO_or_read(addr, val)
+#  define AO_HAVE_or_acquire_read
+#endif
+#if !defined(AO_HAVE_or_acquire_read) && \
+    defined(AO_HAVE_or_acquire)
+#  define AO_or_acquire_read(addr, val) \
+       AO_or_acquire(addr, val)
+#  define AO_HAVE_or_acquire_read
+#endif
+
   
 /* Test_and_set */
   
index 5e7a3eabbaa4a9da619b379a5cca5ae8b80405a4..be45ae231193c01d6642909511f06cfd7ed60510 100644 (file)
@@ -60,12 +60,14 @@ AO_T load(volatile AO_T * addr)
        Atomic load of *addr.
 void store(volatile AO_T * addr, AO_T new_val)
        Atomically store new_val to *addr.
-void fetch_and_add(volatile AO_T *addr, incr)
+AO_T fetch_and_add(volatile AO_T *addr, AO_T incr)
        Atomically add incr to *addr, and return the original value of *addr.
-void fetch_and_add1(volatile AO_T *addr)
+AO_T fetch_and_add1(volatile AO_T *addr)
        Equivalent to AO_fetch_and_add(addr, 1).
-void fetch_and_sub1(volatile AO_T *addr)
+AO_T fetch_and_sub1(volatile AO_T *addr)
        Equivalent to AO_fetch_and_add(addr, (AO_T)(-1)).
+void or(volatile AO_T *addr, AO_T incr)
+       Atomically or incr into *addr.
 int compare_and_swap(volatile AO_T * addr, AO_T old_val, AO_T new_val)
        Atomically compare *addr to old_val, and replace *addr by new_val
        if the first comparison succeeds.  Returns nonzero if the comparison
index 5947d791c50ea530df79feddacef920529e01608..095586058154566d6d7a19bdf3a91ad8713bb565 100644 (file)
@@ -125,8 +125,8 @@ void * acqrel_thr(void *id)
        my_counter1 = AO_load(&counter1);
        if (my_counter1 < my_counter2)
          {
-           fprintf(stderr, "Saw release store out of order: %d < %d\n",
-                   my_counter1, my_counter2);
+           fprintf(stderr, "Saw release store out of order: %lu < %lu\n",
+                   (unsigned long)my_counter1, (unsigned long)my_counter2);
            abort();
          }
       }
@@ -178,6 +178,7 @@ void * test_and_set_thr(void * id)
         junk *= 17;
         junk *= 17;
     }
+  return 0;
 }
 
 int test_and_set_test(void)
index 35dd0a6b1236bdfd28e0da4196a8648e4c715d7f..6f5e9435089ec14b5b3d0d81caa723a5246c1cfc 100644 (file)
@@ -18,7 +18,7 @@
 
 void test_atomicXX(void)
 {
-  AO_T x, y;
+  AO_T x;
 # if defined(AO_HAVE_test_and_setXX)
     AO_TS_T z = AO_TS_INITIALIZER;
 # endif
@@ -55,25 +55,32 @@ void test_atomicXX(void)
     MISSING(AO_fetch_and_add);
 # endif
 # if defined(AO_HAVE_fetch_and_add1XX)
-    TA_assert(AO_fetch_and_add1(&x) == 13);
+    TA_assert(AO_fetch_and_add1XX(&x) == 13);
 # else
     MISSING(AO_fetch_and_add1);
     ++x;
 # endif
 # if defined(AO_HAVE_fetch_and_sub1XX)
-    TA_assert(AO_fetch_and_sub1(&x) == 14);
+    TA_assert(AO_fetch_and_sub1XX(&x) == 14);
 # else
     MISSING(AO_fetch_and_sub1);
     --x;
 # endif
 # if defined(AO_HAVE_compare_and_swapXX)
-    TA_assert(!AO_compare_and_swap(&x, 14, 42));
+    TA_assert(!AO_compare_and_swapXX(&x, 14, 42));
     TA_assert(x == 13);
-    TA_assert(AO_compare_and_swap(&x, 13, 42));
+    TA_assert(AO_compare_and_swapXX(&x, 13, 42));
     TA_assert(x == 42);
 # else
     MISSING(AO_compare_and_swap);
 # endif
+# if defined(AO_HAVE_orXX)
+    AO_orXX(&x, 66);
+    TA_assert(x == 106);
+# else
+    MISSING(AO_or);
+    x |= 34;
+# endif
 }