Message ID | mcrd3nbldes.fsf@google.com |
---|---|
State | New |
Headers | show |
On Tue, 1 Feb 2011, Ian Lance Taylor wrote: > The libgo library uses __sync_bool_compare_and_swap_4 (i.e., uses > __sync_bool_compare_and_swap on uint32 types). That function is not > available for all gcc targets. This patch adds the function to the > library for those cases. Ideally this would be handled by libgcc, but > that does not currently happen. This function should be harmless if > libgcc does get an implementation. On some targets libgcc does have an implementation (ARM, PA, SH Linux - note that for more recent ARM architectures the sync operations are inlined). The __HAVE_* macros only know about whether the operation can be inlined, not about whether it's available in libgcc. libstdc++-v3 uses link tests to see if these operations are available (either inlined or in libgcc - or for that matter in libc, which could make sense for kernel helpers accessed through a vDSO). For more general questions about implementing atomics in libgcc, see past discussions around implementing C++0x/C1x atomics.
diff -r 948edbf8367c libgo/runtime/thread.c --- a/libgo/runtime/thread.c Mon Jan 31 15:32:52 2011 -0800 +++ b/libgo/runtime/thread.c Tue Feb 01 12:11:10 2011 -0800 @@ -3,6 +3,7 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "go-assert.h" void runtime_initlock(Lock *l) @@ -75,3 +76,38 @@ { sem_destroy(&l->sem); } + +#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + +// For targets which don't have the required sync support. Really +// this should be provided by gcc itself. FIXME. + +static pthread_mutex_t sync_lock = PTHREAD_MUTEX_INITIALIZER; + +_Bool +__sync_bool_compare_and_swap_4(uint32*, uint32, uint32) + __attribute__((visibility("hidden"))); + +_Bool +__sync_bool_compare_and_swap_4(uint32* ptr, uint32 old, uint32 new) +{ + int i; + _Bool ret; + + i = pthread_mutex_lock(&sync_lock); + __go_assert(i == 0); + + if(*ptr != old) { + ret = 0; + } else { + *ptr = new; + ret = 1; + } + + i = pthread_mutex_unlock(&sync_lock); + __go_assert(i == 0); + + return ret; +} + +#endif