From 8b263c956bffa5a42c166e96e4fe35218d7c64b3 Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Mon, 25 Jul 2011 13:50:29 +0400 Subject: [PATCH] ao-0.4 tarball import --- Makefile | 10 +-- ao_sysdeps/acquire_release_volatile.h | 1 + ao_sysdeps/gcc/x86.h | 10 +++ ao_sysdeps/generic_pthread.h | 46 ++++++---- atomic_ops.c | 2 +- atomic_ops.h | 6 +- atomic_ops_generalize.h | 116 ++++++++++++++++++++++++-- doc/README_atomic_ops.txt | 8 +- test_atomic.c | 5 +- test_atomic.template | 17 ++-- 10 files changed, 177 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index d2ebb04..d9f54e8 100644 --- 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 diff --git a/ao_sysdeps/acquire_release_volatile.h b/ao_sysdeps/acquire_release_volatile.h index 9f3d3c6..378bdcb 100644 --- a/ao_sysdeps/acquire_release_volatile.h +++ b/ao_sysdeps/acquire_release_volatile.h @@ -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; } diff --git a/ao_sysdeps/gcc/x86.h b/ao_sysdeps/gcc/x86.h index c73f235..69793a1 100644 --- a/ao_sysdeps/gcc/x86.h +++ b/ao_sysdeps/gcc/x86.h @@ -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) { diff --git a/ao_sysdeps/generic_pthread.h b/ao_sysdeps/generic_pthread.h index e0e405a..f515524 100644 --- a/ao_sysdeps/generic_pthread.h +++ b/ao_sysdeps/generic_pthread.h @@ -31,13 +31,13 @@ /* 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; } diff --git a/atomic_ops.c b/atomic_ops.c index 33ecfac..8e93bd7 100644 --- a/atomic_ops.c +++ b/atomic_ops.c @@ -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. diff --git a/atomic_ops.h b/atomic_ops.h index 36daee0..98db8f9 100644 --- a/atomic_ops.h +++ b/atomic_ops.h @@ -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 */ @@ -89,10 +90,11 @@ /* 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. */ /* */ diff --git a/atomic_ops_generalize.h b/atomic_ops_generalize.h index 5a6c872..315198f 100644 --- a/atomic_ops_generalize.h +++ b/atomic_ops_generalize.h @@ -267,7 +267,7 @@ #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 @@ -487,39 +487,43 @@ #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 @@ -604,6 +608,102 @@ # 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 */ diff --git a/doc/README_atomic_ops.txt b/doc/README_atomic_ops.txt index 5e7a3ea..be45ae2 100644 --- a/doc/README_atomic_ops.txt +++ b/doc/README_atomic_ops.txt @@ -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 diff --git a/test_atomic.c b/test_atomic.c index 5947d79..0955860 100644 --- a/test_atomic.c +++ b/test_atomic.c @@ -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) diff --git a/test_atomic.template b/test_atomic.template index 35dd0a6..6f5e943 100644 --- a/test_atomic.template +++ b/test_atomic.template @@ -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 } -- 2.40.0