Hallo List, for one of my projects I was recently looking for implementations of some atomic primitives for Sparc and PowerPC, and also stumbled over the code in apr_atomic.c.
A few weeks later I am returning here with a bug report and an implementation for SPARC. 1) PowerPC Bug The Bug is actually in the Chip, not in the APR code; as stated in erratum number 12 in http://www-306.ibm.com/chips/techlib/techlib.nsf/techdocs/79B6E24422AA101287256E93006C957E/$file/PowerPC_970FX_errata_DD3.X_V1.7.pdf one must not spin in a three-instruction lwarx/ldarx loop because there is obviously at least one PowerPC chip that can enter a livelock... (Unfortunately I don't have a solution for this one; I am on Mac OS X where the OS supplies the spinlock primitive that I actually need; the Mac OS X version is documented as using exponential back-off.) 2) Sparc/GCC Code The following code was written by me and has survived both some testing and some real-world usage; if there is interest in it, I would contribute it to apr under two conditions: - Somebody reviews it. - My name appears somewhere as contributor. (Yes, I'm doing this a) for vanity and b) because I don't know anybody who can give me a real review of the code.) Obviously the typedef and the fact that C++ references are used would need to be changed to use the APR data types and C pointers. Regards, Colin typedef uint32_t atomic_t; inline bool atomic_compare_and_swap( const atomic_t old_value, atomic_t new_value, atomic_t & the_value ) { __asm__ __volatile__ ( "cas [%1],%2,%0" : "+r" ( new_value ) : "r" ( & the_value ), "r" ( old_value ) ); return new_value == old_value; } inline atomic_t atomic_load( atomic_t & the_value ) { __asm__ __volatile__ ( "membar #StoreLoad | #LoadLoad" : : : "memory" ); return * const_cast< volatile atomic_t * >( & the_value ); } inline void atomic_store( const atomic_t new_value, atomic_t & the_value ) { * const_cast< volatile atomic_t * >( & the_value ) = new_value; __asm__ __volatile__ ( "membar #StoreStore | #StoreLoad" : : : "memory" ); } inline atomic_t atomic_swap( const atomic_t new_value, atomic_t & the_value ) { atomic_t nrv; do { nrv = atomic_load( the_value ); } while ( ! atomic_compare_and_swap( nrv, new_value, the_value ) ); return nrv; } inline atomic_t atomic_add( const atomic_t increment, atomic_t & the_value ) { atomic_t nrv; do { nrv = atomic_load( the_value ); } while ( ! atomic_compare_and_swap( nrv, nrv + increment, the_value ) ); return nrv + increment; } static const atomic_t spin_lock_init = 0; inline void spin_lock_lock( atomic_t & s ) { atomic_t tmp; do { __asm__ __volatile__( "ldstub %1,%0; membar #LoadLoad" : "=r" ( tmp ), "+m" ( * & s ) : : "memory" ); } while ( tmp ); } inline void spin_lock_unlock( atomic_t & s ) { __asm__ __volatile__( "membar #StoreStore | #LoadStore | #StoreLoad; stb %1,%0" : "=m"( * & s ) : "r" ( 0 ) ); }
