Commit 49579c7e by Ian Lance Taylor Committed by Ian Lance Taylor

configure.ac: Check for support of __atomic extensions.

	* 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.

From-SVN: r204994
parent 7f369373
2013-11-18 Ian Lance Taylor <iant@google.com>
* 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 <jakub@redhat.com> 2013-11-18 Jakub Jelinek <jakub@redhat.com>
* elf.c (SHN_UNDEF): Define. * elf.c (SHN_UNDEF): Define.
......
...@@ -40,6 +40,7 @@ noinst_LTLIBRARIES = libbacktrace.la ...@@ -40,6 +40,7 @@ noinst_LTLIBRARIES = libbacktrace.la
libbacktrace_la_SOURCES = \ libbacktrace_la_SOURCES = \
backtrace.h \ backtrace.h \
atomic.c \
dwarf.c \ dwarf.c \
fileline.c \ fileline.c \
internal.h \ internal.h \
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
@SET_MAKE@ @SET_MAKE@
# Makefile.am -- Backtrace Makefile. # 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 # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are # modification, are permitted provided that the following conditions are
...@@ -93,8 +93,8 @@ CONFIG_CLEAN_FILES = backtrace-supported.h ...@@ -93,8 +93,8 @@ CONFIG_CLEAN_FILES = backtrace-supported.h
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES) LTLIBRARIES = $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 = am__DEPENDENCIES_1 =
am_libbacktrace_la_OBJECTS = dwarf.lo fileline.lo posix.lo print.lo \ am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
state.lo print.lo state.lo
libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) @NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT)
@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT)
...@@ -258,6 +258,7 @@ AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG) ...@@ -258,6 +258,7 @@ AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG)
noinst_LTLIBRARIES = libbacktrace.la noinst_LTLIBRARIES = libbacktrace.la
libbacktrace_la_SOURCES = \ libbacktrace_la_SOURCES = \
backtrace.h \ backtrace.h \
atomic.c \
dwarf.c \ dwarf.c \
fileline.c \ fileline.c \
internal.h \ internal.h \
......
/* 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
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
/* ELF size: 32 or 64 */ /* ELF size: 32 or 64 */
#undef BACKTRACE_ELF_SIZE #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 /* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */ don't. */
#undef HAVE_DECL_STRNLEN #undef HAVE_DECL_STRNLEN
......
...@@ -11748,6 +11748,44 @@ $as_echo "#define HAVE_SYNC_FUNCTIONS 1" >>confdefs.h ...@@ -11748,6 +11748,44 @@ $as_echo "#define HAVE_SYNC_FUNCTIONS 1" >>confdefs.h
fi 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 # The library needs to be able to read the executable itself. Compile
# a file to determine the executable format. The awk script # a file to determine the executable format. The awk script
# filetype.awk prints out the file type. # filetype.awk prints out the file type.
......
...@@ -194,6 +194,24 @@ if test "$libbacktrace_cv_sys_sync" = "yes"; then ...@@ -194,6 +194,24 @@ if test "$libbacktrace_cv_sys_sync" = "yes"; then
fi fi
AC_SUBST(BACKTRACE_SUPPORTS_THREADS) 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 # The library needs to be able to read the executable itself. Compile
# a file to determine the executable format. The awk script # a file to determine the executable format. The awk script
# filetype.awk prints out the file type. # filetype.awk prints out the file type.
......
...@@ -2643,12 +2643,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -2643,12 +2643,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
&& pc < (entry - 1)->high) && pc < (entry - 1)->high)
{ {
if (state->threaded) if (state->threaded)
{ lines = (struct line *) backtrace_atomic_load_pointer (&u->lines);
/* Use __sync_bool_compare_and_swap to do a
load-acquire. */
while (!__sync_bool_compare_and_swap (&u->lines, lines, lines))
lines = u->lines;
}
if (lines != (struct line *) (uintptr_t) -1) if (lines != (struct line *) (uintptr_t) -1)
break; break;
...@@ -2659,13 +2654,8 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -2659,13 +2654,8 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
lines = u->lines; lines = u->lines;
} }
/* Do a load-acquire of u->lines. */
if (state->threaded) if (state->threaded)
{ lines = backtrace_atomic_load_pointer (&u->lines);
/* Use __sync_bool_compare_and_swap to do an atomic load. */
while (!__sync_bool_compare_and_swap (&u->lines, lines, lines))
lines = u->lines;
}
new_data = 0; new_data = 0;
if (lines == NULL) if (lines == NULL)
...@@ -2713,12 +2703,11 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, ...@@ -2713,12 +2703,11 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
} }
else else
{ {
__sync_bool_compare_and_swap (&u->lines_count, 0, count); backtrace_atomic_store_size_t (&u->lines_count, count);
__sync_bool_compare_and_swap (&u->function_addrs, NULL, backtrace_atomic_store_pointer (&u->function_addrs, function_addrs);
function_addrs); backtrace_atomic_store_size_t (&u->function_addrs_count,
__sync_bool_compare_and_swap (&u->function_addrs_count, 0, function_addrs_count);
function_addrs_count); backtrace_atomic_store_pointer (&u->lines, lines);
__sync_bool_compare_and_swap (&u->lines, NULL, lines);
} }
} }
...@@ -2849,11 +2838,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc, ...@@ -2849,11 +2838,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
pp = (struct dwarf_data **) (void *) &state->fileline_data; pp = (struct dwarf_data **) (void *) &state->fileline_data;
while (1) while (1)
{ {
ddata = *pp; ddata = backtrace_atomic_load_pointer (pp);
/* Atomic load. */
while (!__sync_bool_compare_and_swap (pp, ddata, ddata))
ddata = *pp;
if (ddata == NULL) if (ddata == NULL)
break; break;
...@@ -2985,10 +2970,7 @@ backtrace_dwarf_add (struct backtrace_state *state, ...@@ -2985,10 +2970,7 @@ backtrace_dwarf_add (struct backtrace_state *state,
{ {
struct dwarf_data *p; struct dwarf_data *p;
/* Atomic load. */ p = backtrace_atomic_load_pointer (pp);
p = *pp;
while (!__sync_bool_compare_and_swap (pp, p, p))
p = *pp;
if (p == NULL) if (p == NULL)
break; break;
......
...@@ -442,10 +442,7 @@ elf_add_syminfo_data (struct backtrace_state *state, ...@@ -442,10 +442,7 @@ elf_add_syminfo_data (struct backtrace_state *state,
{ {
struct elf_syminfo_data *p; struct elf_syminfo_data *p;
/* Atomic load. */ p = backtrace_atomic_load_pointer (pp);
p = *pp;
while (!__sync_bool_compare_and_swap (pp, p, p))
p = *pp;
if (p == NULL) if (p == NULL)
break; break;
...@@ -490,11 +487,7 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr, ...@@ -490,11 +487,7 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
while (1) while (1)
{ {
edata = *pp; edata = backtrace_atomic_load_pointer (pp);
/* Atomic load. */
while (!__sync_bool_compare_and_swap (pp, edata, edata))
edata = *pp;
if (edata == NULL) if (edata == NULL)
break; break;
...@@ -902,7 +895,6 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, ...@@ -902,7 +895,6 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
{ {
int found_sym; int found_sym;
int found_dwarf; int found_dwarf;
syminfo elf_syminfo_fn;
fileline elf_fileline_fn; fileline elf_fileline_fn;
struct phdr_data pd; struct phdr_data pd;
...@@ -919,18 +911,19 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, ...@@ -919,18 +911,19 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
dl_iterate_phdr (phdr_callback, (void *) &pd); dl_iterate_phdr (phdr_callback, (void *) &pd);
elf_syminfo_fn = found_sym ? elf_syminfo : elf_nosyms;
if (!state->threaded) if (!state->threaded)
{ {
if (state->syminfo_fn == NULL || found_sym) if (found_sym)
state->syminfo_fn = elf_syminfo_fn; state->syminfo_fn = elf_syminfo;
else if (state->syminfo_fn == NULL)
state->syminfo_fn = elf_nosyms;
} }
else else
{ {
__sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_syminfo_fn);
if (found_sym) if (found_sym)
__sync_bool_compare_and_swap (&state->syminfo_fn, elf_nosyms, backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo);
elf_syminfo_fn); else
__sync_bool_compare_and_swap (&state->syminfo_fn, NULL, elf_nosyms);
} }
if (!state->threaded) if (!state->threaded)
...@@ -942,11 +935,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor, ...@@ -942,11 +935,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
{ {
fileline current_fn; fileline current_fn;
/* Atomic load. */ current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
current_fn = state->fileline_fn;
while (!__sync_bool_compare_and_swap (&state->fileline_fn, current_fn,
current_fn))
current_fn = state->fileline_fn;
if (current_fn == NULL || current_fn == elf_nodebug) if (current_fn == NULL || current_fn == elf_nodebug)
*fileline_fn = elf_fileline_fn; *fileline_fn = elf_fileline_fn;
} }
......
...@@ -58,15 +58,10 @@ fileline_initialize (struct backtrace_state *state, ...@@ -58,15 +58,10 @@ fileline_initialize (struct backtrace_state *state,
int called_error_callback; int called_error_callback;
int descriptor; int descriptor;
failed = state->fileline_initialization_failed; if (!state->threaded)
failed = state->fileline_initialization_failed;
if (state->threaded) else
{ failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
/* 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 (failed) if (failed)
{ {
...@@ -74,13 +69,10 @@ fileline_initialize (struct backtrace_state *state, ...@@ -74,13 +69,10 @@ fileline_initialize (struct backtrace_state *state,
return 0; return 0;
} }
fileline_fn = state->fileline_fn; if (!state->threaded)
if (state->threaded) fileline_fn = state->fileline_fn;
{ else
while (!__sync_bool_compare_and_swap (&state->fileline_fn, fileline_fn, fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
fileline_fn))
fileline_fn = state->fileline_fn;
}
if (fileline_fn != NULL) if (fileline_fn != NULL)
return 1; return 1;
...@@ -151,8 +143,7 @@ fileline_initialize (struct backtrace_state *state, ...@@ -151,8 +143,7 @@ fileline_initialize (struct backtrace_state *state,
if (!state->threaded) if (!state->threaded)
state->fileline_initialization_failed = 1; state->fileline_initialization_failed = 1;
else else
__sync_bool_compare_and_swap (&state->fileline_initialization_failed, backtrace_atomic_store_int (&state->fileline_initialization_failed, 1);
0, failed);
return 0; return 0;
} }
...@@ -160,15 +151,10 @@ fileline_initialize (struct backtrace_state *state, ...@@ -160,15 +151,10 @@ fileline_initialize (struct backtrace_state *state,
state->fileline_fn = fileline_fn; state->fileline_fn = fileline_fn;
else else
{ {
__sync_bool_compare_and_swap (&state->fileline_fn, NULL, fileline_fn); backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn);
/* At this point we know that state->fileline_fn is not NULL. /* Note that if two threads initialize at once, one of the data
Either we stored our value, or some other thread stored its sets may be leaked. */
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. */
} }
return 1; return 1;
......
...@@ -65,7 +65,48 @@ POSSIBILITY OF SUCH DAMAGE. */ ...@@ -65,7 +65,48 @@ POSSIBILITY OF SUCH DAMAGE. */
#define __sync_lock_test_and_set(A, B) (abort(), 0) #define __sync_lock_test_and_set(A, B) (abort(), 0)
#define __sync_lock_release(A) abort() #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 /* The type of the function that collects file/line information. This
is like backtrace_pcinfo. */ is like backtrace_pcinfo. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment