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
This commit is contained in:
Ian Lance Taylor 2013-11-19 01:09:47 +00:00 committed by Ian Lance Taylor
parent 7f369373da
commit 49579c7e20
11 changed files with 262 additions and 78 deletions

View File

@ -1,3 +1,17 @@
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>
* elf.c (SHN_UNDEF): Define.

View File

@ -40,6 +40,7 @@ noinst_LTLIBRARIES = libbacktrace.la
libbacktrace_la_SOURCES = \
backtrace.h \
atomic.c \
dwarf.c \
fileline.c \
internal.h \

View File

@ -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 \

111
libbacktrace/atomic.c Normal file
View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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,
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);
__sync_bool_compare_and_swap (&u->lines, NULL, lines);
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;

View File

@ -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;
}

View File

@ -58,15 +58,10 @@ fileline_initialize (struct backtrace_state *state,
int called_error_callback;
int descriptor;
if (!state->threaded)
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;
}
else
failed = backtrace_atomic_load_int (&state->fileline_initialization_failed);
if (failed)
{
@ -74,13 +69,10 @@ fileline_initialize (struct backtrace_state *state,
return 0;
}
if (!state->threaded)
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;
}
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);
backtrace_atomic_store_pointer (&state->fileline_fn, 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. */
/* Note that if two threads initialize at once, one of the data
sets may be leaked. */
}
return 1;

View File

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