From bcafb4a81d1fc8deefed6e6fa567d66417857c9a Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 19 Nov 2013 01:09:47 +0000 Subject: * configure.ac: Check for support of __atomic extensions. * internal.h: Declare or #define atomic functions for use in backtrace code. * atomic.c: New file. * dwarf.c (dwarf_lookup_pc): Use atomic functions. (dwarf_fileline, backtrace_dwarf_add): Likewise. * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. (backtrace_initialize): Likewise. * fileline.c (fileline_initialize): Likewise. * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. * configure, config.h.in, Makefile.in: Rebuild. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204994 138bc75d-0d04-0410-961f-82ee72b054a4 --- libbacktrace/ChangeLog | 14 ++++++ libbacktrace/Makefile.am | 1 + libbacktrace/Makefile.in | 7 +-- libbacktrace/atomic.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++ libbacktrace/config.h.in | 3 ++ libbacktrace/configure | 38 ++++++++++++++++ libbacktrace/configure.ac | 18 ++++++++ libbacktrace/dwarf.c | 36 ++++----------- libbacktrace/elf.c | 31 +++++-------- libbacktrace/fileline.c | 40 ++++++----------- libbacktrace/internal.h | 43 +++++++++++++++++- 11 files changed, 263 insertions(+), 79 deletions(-) create mode 100644 libbacktrace/atomic.c (limited to 'libbacktrace') diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog index c06194df3e4..134d9a71752 100644 --- a/libbacktrace/ChangeLog +++ b/libbacktrace/ChangeLog @@ -1,3 +1,17 @@ +2013-11-18 Ian Lance Taylor + + * configure.ac: Check for support of __atomic extensions. + * internal.h: Declare or #define atomic functions for use in + backtrace code. + * atomic.c: New file. + * dwarf.c (dwarf_lookup_pc): Use atomic functions. + (dwarf_fileline, backtrace_dwarf_add): Likewise. + * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. + (backtrace_initialize): Likewise. + * fileline.c (fileline_initialize): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. + * configure, config.h.in, Makefile.in: Rebuild. + 2013-11-18 Jakub Jelinek * elf.c (SHN_UNDEF): Define. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index 035986bbf96..20dbde480c5 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -40,6 +40,7 @@ noinst_LTLIBRARIES = libbacktrace.la libbacktrace_la_SOURCES = \ backtrace.h \ + atomic.c \ dwarf.c \ fileline.c \ internal.h \ diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in index 971406bf6da..a1e144aca17 100644 --- a/libbacktrace/Makefile.in +++ b/libbacktrace/Makefile.in @@ -16,7 +16,7 @@ @SET_MAKE@ # Makefile.am -- Backtrace Makefile. -# Copyright (C) 2012 Free Software Foundation, Inc. +# Copyright (C) 2012-2013 Free Software Foundation, Inc. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -93,8 +93,8 @@ CONFIG_CLEAN_FILES = backtrace-supported.h CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = -am_libbacktrace_la_OBJECTS = dwarf.lo fileline.lo posix.lo print.lo \ - state.lo +am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \ + print.lo state.lo libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) @NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) @@ -258,6 +258,7 @@ AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG) noinst_LTLIBRARIES = libbacktrace.la libbacktrace_la_SOURCES = \ backtrace.h \ + atomic.c \ dwarf.c \ fileline.c \ internal.h \ diff --git a/libbacktrace/atomic.c b/libbacktrace/atomic.c new file mode 100644 index 00000000000..44fa5521ad4 --- /dev/null +++ b/libbacktrace/atomic.c @@ -0,0 +1,111 @@ +/* atomic.c -- Support for atomic functions if not present. + Copyright (C) 2013 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +/* This file holds implementations of the atomic functions that are + used if the host compiler has the sync functions but not the atomic + functions, as is true of versions of GCC before 4.7. */ + +#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) + +/* Do an atomic load of a pointer. */ + +void * +backtrace_atomic_load_pointer (void *arg) +{ + void **pp; + void *p; + + pp = (void **) arg; + p = *pp; + while (!__sync_bool_compare_and_swap (pp, p, p)) + p = *pp; + return p; +} + +/* Do an atomic load of an int. */ + +int +backtrace_atomic_load_int (int *p) +{ + int i; + + i = *p; + while (!__sync_bool_compare_and_swap (p, i, i)) + i = *p; + return i; +} + +/* Do an atomic store of a pointer. */ + +void +backtrace_atomic_store_pointer (void *arg, void *p) +{ + void **pp; + void *old; + + pp = (void **) arg; + old = *pp; + while (!__sync_bool_compare_and_swap (pp, old, p)) + old = *pp; +} + +/* Do an atomic store of a size_t value. */ + +void +backtrace_atomic_store_size_t (size_t *p, size_t v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +/* Do an atomic store of a int value. */ + +void +backtrace_atomic_store_int (int *p, int v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +#endif diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in index 48ff63fdc05..87cb805984d 100644 --- a/libbacktrace/config.h.in +++ b/libbacktrace/config.h.in @@ -3,6 +3,9 @@ /* ELF size: 32 or 64 */ #undef BACKTRACE_ELF_SIZE +/* Define to 1 if you have the __atomic functions */ +#undef HAVE_ATOMIC_FUNCTIONS + /* Define to 1 if you have the declaration of `strnlen', and to 0 if you don't. */ #undef HAVE_DECL_STRNLEN diff --git a/libbacktrace/configure b/libbacktrace/configure index e6b13c0b706..d6bda6e67b6 100755 --- a/libbacktrace/configure +++ b/libbacktrace/configure @@ -11748,6 +11748,44 @@ $as_echo "#define HAVE_SYNC_FUNCTIONS 1" >>confdefs.h fi +# Test for __atomic support. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __atomic extensions" >&5 +$as_echo_n "checking __atomic extensions... " >&6; } +if test "${libbacktrace_cv_sys_atomic+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "${with_target_subdir}"; then + libbacktrace_cv_sys_atomic=yes + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +int +main () +{ +__atomic_load_n (&i, __ATOMIC_ACQUIRE); + __atomic_store_n (&i, 1, __ATOMIC_RELEASE); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + libbacktrace_cv_sys_atomic=yes +else + libbacktrace_cv_sys_atomic=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_atomic" >&5 +$as_echo "$libbacktrace_cv_sys_atomic" >&6; } +if test "$libbacktrace_cv_sys_atomic" = "yes"; then + +$as_echo "#define HAVE_ATOMIC_FUNCTIONS 1" >>confdefs.h + +fi + # The library needs to be able to read the executable itself. Compile # a file to determine the executable format. The awk script # filetype.awk prints out the file type. diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 48c86203837..f97afbc8b74 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -194,6 +194,24 @@ if test "$libbacktrace_cv_sys_sync" = "yes"; then fi AC_SUBST(BACKTRACE_SUPPORTS_THREADS) +# Test for __atomic support. +AC_CACHE_CHECK([__atomic extensions], +[libbacktrace_cv_sys_atomic], +[if test -n "${with_target_subdir}"; then + libbacktrace_cv_sys_atomic=yes + else + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([int i;], + [__atomic_load_n (&i, __ATOMIC_ACQUIRE); + __atomic_store_n (&i, 1, __ATOMIC_RELEASE);])], + [libbacktrace_cv_sys_atomic=yes], + [libbacktrace_cv_sys_atomic=no]) + fi]) +if test "$libbacktrace_cv_sys_atomic" = "yes"; then + AC_DEFINE([HAVE_ATOMIC_FUNCTIONS], 1, + [Define to 1 if you have the __atomic functions]) +fi + # The library needs to be able to read the executable itself. Compile # a file to determine the executable format. The awk script # filetype.awk prints out the file type. diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 501afe553d2..0aba2d3f574 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -2643,12 +2643,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, && pc < (entry - 1)->high) { if (state->threaded) - { - /* Use __sync_bool_compare_and_swap to do a - load-acquire. */ - while (!__sync_bool_compare_and_swap (&u->lines, lines, lines)) - lines = u->lines; - } + lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); if (lines != (struct line *) (uintptr_t) -1) break; @@ -2659,13 +2654,8 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, lines = u->lines; } - /* Do a load-acquire of u->lines. */ if (state->threaded) - { - /* Use __sync_bool_compare_and_swap to do an atomic load. */ - while (!__sync_bool_compare_and_swap (&u->lines, lines, lines)) - lines = u->lines; - } + lines = backtrace_atomic_load_pointer (&u->lines); new_data = 0; if (lines == NULL) @@ -2713,12 +2703,11 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, } else { - __sync_bool_compare_and_swap (&u->lines_count, 0, count); - __sync_bool_compare_and_swap (&u->function_addrs, NULL, - function_addrs); - __sync_bool_compare_and_swap (&u->function_addrs_count, 0, - function_addrs_count); - __sync_bool_compare_and_swap (&u->lines, NULL, lines); + backtrace_atomic_store_size_t (&u->lines_count, count); + backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); + backtrace_atomic_store_size_t (&u->function_addrs_count, + function_addrs_count); + backtrace_atomic_store_pointer (&u->lines, lines); } } @@ -2849,11 +2838,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc, pp = (struct dwarf_data **) (void *) &state->fileline_data; while (1) { - ddata = *pp; - /* Atomic load. */ - while (!__sync_bool_compare_and_swap (pp, ddata, ddata)) - ddata = *pp; - + ddata = backtrace_atomic_load_pointer (pp); if (ddata == NULL) break; @@ -2985,10 +2970,7 @@ backtrace_dwarf_add (struct backtrace_state *state, { struct dwarf_data *p; - /* Atomic load. */ - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; + p = backtrace_atomic_load_pointer (pp); if (p == NULL) break; diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 659b349f73b..981ce7f831c 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -442,10 +442,7 @@ elf_add_syminfo_data (struct backtrace_state *state, { struct elf_syminfo_data *p; - /* Atomic load. */ - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; + p = backtrace_atomic_load_pointer (pp); if (p == NULL) break; @@ -490,11 +487,7 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr, pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; while (1) { - edata = *pp; - /* Atomic load. */ - while (!__sync_bool_compare_and_swap (pp, edata, edata)) - edata = *pp; - + edata = backtrace_atomic_load_pointer (pp); if (edata == NULL) break; @@ -902,7 +895,6 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, { int found_sym; int found_dwarf; - syminfo elf_syminfo_fn; fileline elf_fileline_fn; struct phdr_data pd; @@ -919,18 +911,19 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, dl_iterate_phdr (phdr_callback, (void *) &pd); - elf_syminfo_fn = found_sym ? elf_syminfo : elf_nosyms; if (!state->threaded) { - if (state->syminfo_fn == NULL || found_sym) - state->syminfo_fn = elf_syminfo_fn; + if (found_sym) + state->syminfo_fn = elf_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = elf_nosyms; } else { - __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_syminfo_fn); if (found_sym) - __sync_bool_compare_and_swap (&state->syminfo_fn, elf_nosyms, - elf_syminfo_fn); + backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); + else + __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_nosyms); } if (!state->threaded) @@ -942,11 +935,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, { fileline current_fn; - /* Atomic load. */ - current_fn = state->fileline_fn; - while (!__sync_bool_compare_and_swap (&state->fileline_fn, current_fn, - current_fn)) - current_fn = state->fileline_fn; + current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); if (current_fn == NULL || current_fn == elf_nodebug) *fileline_fn = elf_fileline_fn; } diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index e5c39be8e0e..cc063f52c0d 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -58,15 +58,10 @@ fileline_initialize (struct backtrace_state *state, int called_error_callback; int descriptor; - failed = state->fileline_initialization_failed; - - if (state->threaded) - { - /* Use __sync_bool_compare_and_swap to do an atomic load. */ - while (!__sync_bool_compare_and_swap - (&state->fileline_initialization_failed, failed, failed)) - failed = state->fileline_initialization_failed; - } + if (!state->threaded) + failed = state->fileline_initialization_failed; + else + failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); if (failed) { @@ -74,13 +69,10 @@ fileline_initialize (struct backtrace_state *state, return 0; } - fileline_fn = state->fileline_fn; - if (state->threaded) - { - while (!__sync_bool_compare_and_swap (&state->fileline_fn, fileline_fn, - fileline_fn)) - fileline_fn = state->fileline_fn; - } + if (!state->threaded) + fileline_fn = state->fileline_fn; + else + fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); if (fileline_fn != NULL) return 1; @@ -151,8 +143,7 @@ fileline_initialize (struct backtrace_state *state, if (!state->threaded) state->fileline_initialization_failed = 1; else - __sync_bool_compare_and_swap (&state->fileline_initialization_failed, - 0, failed); + backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); return 0; } @@ -160,15 +151,10 @@ fileline_initialize (struct backtrace_state *state, state->fileline_fn = fileline_fn; else { - __sync_bool_compare_and_swap (&state->fileline_fn, NULL, fileline_fn); - - /* At this point we know that state->fileline_fn is not NULL. - Either we stored our value, or some other thread stored its - value. If some other thread stored its value, we leak the - one we just initialized. Either way, state->fileline_fn is - initialized. The compare_and_swap is a full memory barrier, - so we should have full access to that value even if it was - created by another thread. */ + backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); + + /* Note that if two threads initialize at once, one of the data + sets may be leaked. */ } return 1; diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h index 1ea664a0bcd..c93e89f36f4 100644 --- a/libbacktrace/internal.h +++ b/libbacktrace/internal.h @@ -65,7 +65,48 @@ POSSIBILITY OF SUCH DAMAGE. */ #define __sync_lock_test_and_set(A, B) (abort(), 0) #define __sync_lock_release(A) abort() -#endif /* !defined(HAVE_SYNC_FUNCTIONS) */ +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ + +#ifdef HAVE_ATOMIC_FUNCTIONS + +/* We have the atomic builtin functions. */ + +#define backtrace_atomic_load_pointer(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_load_int(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_store_pointer(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_size_t(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_int(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) + +#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ +#ifdef HAVE_SYNC_FUNCTIONS + +/* We have the sync functions but not the atomic functions. Define + the atomic ones in terms of the sync ones. */ + +extern void *backtrace_atomic_load_pointer (void *); +extern int backtrace_atomic_load_int (int *); +extern void backtrace_atomic_store_pointer (void *, void *); +extern void backtrace_atomic_store_size_t (size_t *, size_t); +extern void backtrace_atomic_store_int (int *, int); + +#else /* !defined (HAVE_SYNC_FUNCTIONS) */ + +/* We have neither the sync nor the atomic functions. These will + never be called. */ + +#define backtrace_atomic_load_pointer(p) (abort(), 0) +#define backtrace_atomic_load_int(p) (abort(), 0) +#define backtrace_atomic_store_pointer(p, v) abort() +#define backtrace_atomic_store_size_t(p, v) abort() +#define backtrace_atomic_store_int(p, v) abort() + +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ +#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ /* The type of the function that collects file/line information. This is like backtrace_pcinfo. */ -- cgit v1.2.1