diff options
Diffstat (limited to 'libdw')
-rw-r--r-- | libdw/ChangeLog | 8 | ||||
-rw-r--r-- | libdw/Makefile.am | 4 | ||||
-rw-r--r-- | libdw/dwarf_begin_elf.c | 17 | ||||
-rw-r--r-- | libdw/dwarf_end.c | 10 | ||||
-rw-r--r-- | libdw/libdwP.h | 59 | ||||
-rw-r--r-- | libdw/libdw_alloc.c | 6 |
6 files changed, 68 insertions, 36 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 498cf0b7..394c0df2 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,11 @@ +2019-08-26 Jonathon Anderson <jma14@rice.edu> + + * libdw_alloc.c (__libdw_allocate): Added thread-safe stack allocator. + * libdwP.h (Dwarf): Likewise. + * dwarf_begin_elf.c (dwarf_begin_elf): Support for above. + * dwarf_end.c (dwarf_end): Likewise. + * Makefile.am: Use -pthread to provide rwlocks. + 2019-07-05 Omar Sandoval <osandov@fb.com> * Makefile.am (libdw_so_LIBS): Replace libebl.a with libebl_pic.a. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 274571c3..ce793e90 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -31,7 +31,7 @@ include $(top_srcdir)/config/eu.am if BUILD_STATIC AM_CFLAGS += $(fpic_CFLAGS) endif -AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf +AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf -pthread VERSION = 1 lib_LIBRARIES = libdw.a @@ -109,7 +109,7 @@ libdw_so_LIBS = ../libebl/libebl_pic.a ../backends/libebl_backends_pic.a \ ../libcpu/libcpu_pic.a libdw_pic.a ../libdwelf/libdwelf_pic.a \ ../libdwfl/libdwfl_pic.a libdw_so_DEPS = ../lib/libeu.a ../libelf/libelf.so -libdw_so_LDLIBS = $(libdw_so_DEPS) -lz $(argp_LDADD) $(zip_LIBS) +libdw_so_LDLIBS = $(libdw_so_DEPS) -lz $(argp_LDADD) $(zip_LIBS) -pthread libdw_so_SOURCES = libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS) $(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \ diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 38c8f5c6..8d137414 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -397,7 +397,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp) assert (sizeof (struct Dwarf) < mem_default_size); /* Allocate the data structure. */ - Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size); + Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf)); if (unlikely (result == NULL) || unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0)) { @@ -414,14 +414,17 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp) result->elf = elf; result->alt_fd = -1; - /* Initialize the memory handling. */ + /* Initialize the memory handling. Initial blocks are allocated on first + actual allocation. */ result->mem_default_size = mem_default_size; result->oom_handler = __libdw_oom; - result->mem_tail = (struct libdw_memblock *) (result + 1); - result->mem_tail->size = (result->mem_default_size - - offsetof (struct libdw_memblock, mem)); - result->mem_tail->remaining = result->mem_tail->size; - result->mem_tail->prev = NULL; + if (pthread_key_create (&result->mem_key, NULL) != 0) + { + free (result); + __libdw_seterrno (DWARF_E_NOMEM); /* no memory or max pthread keys. */ + return NULL; + } + atomic_init (&result->mem_tail, (uintptr_t)NULL); if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR) { diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index 29795c10..a2e94436 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -94,14 +94,18 @@ dwarf_end (Dwarf *dwarf) /* And the split Dwarf. */ tdestroy (dwarf->split_tree, noop_free); - struct libdw_memblock *memp = dwarf->mem_tail; - /* The first block is allocated together with the Dwarf object. */ - while (memp->prev != NULL) + /* Free the internally allocated memory. */ + struct libdw_memblock *memp; + memp = (struct libdw_memblock *) (atomic_load_explicit + (&dwarf->mem_tail, + memory_order_relaxed)); + while (memp != NULL) { struct libdw_memblock *prevp = memp->prev; free (memp); memp = prevp; } + pthread_key_delete (dwarf->mem_key); /* Free the pubnames helper structure. */ free (dwarf->pubnames_sets); diff --git a/libdw/libdwP.h b/libdw/libdwP.h index eebb7d12..ad2599eb 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -31,9 +31,11 @@ #include <libintl.h> #include <stdbool.h> +#include <pthread.h> #include <libdw.h> #include <dwarf.h> +#include "atomics.h" /* gettext helper macros. */ @@ -147,6 +149,17 @@ enum #include "dwarf_sig8_hash.h" +/* Structure for internal memory handling. This is basically a simplified + reimplementation of obstacks. Unfortunately the standard obstack + implementation is not usable in libraries. */ +struct libdw_memblock +{ + size_t size; + size_t remaining; + struct libdw_memblock *prev; + char mem[0]; +}; + /* This is the structure representing the debugging state. */ struct Dwarf { @@ -218,16 +231,11 @@ struct Dwarf /* Similar for addrx/constx, which will come from .debug_addr section. */ struct Dwarf_CU *fake_addr_cu; - /* Internal memory handling. This is basically a simplified - reimplementation of obstacks. Unfortunately the standard obstack - implementation is not usable in libraries. */ - struct libdw_memblock - { - size_t size; - size_t remaining; - struct libdw_memblock *prev; - char mem[0]; - } *mem_tail; + /* Internal memory handling. Each thread allocates separately and only + allocates from its own blocks, while all the blocks are pushed atomically + onto a unified stack for easy deallocation. */ + pthread_key_t mem_key; + atomic_uintptr_t mem_tail; /* Default size of allocated memory blocks. */ size_t mem_default_size; @@ -570,21 +578,28 @@ libdw_valid_user_form (int form) extern void __libdw_seterrno (int value) internal_function; -/* Memory handling, the easy parts. This macro does not do any locking. */ +/* Memory handling, the easy parts. This macro does not do nor need to do any + locking for proper concurrent operation. */ #define libdw_alloc(dbg, type, tsize, cnt) \ - ({ struct libdw_memblock *_tail = (dbg)->mem_tail; \ - size_t _required = (tsize) * (cnt); \ - type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\ - size_t _padding = ((__alignof (type) \ - - ((uintptr_t) _result & (__alignof (type) - 1))) \ - & (__alignof (type) - 1)); \ - if (unlikely (_tail->remaining < _required + _padding)) \ - _result = (type *) __libdw_allocate (dbg, _required, __alignof (type));\ + ({ struct libdw_memblock *_tail = pthread_getspecific (dbg->mem_key); \ + size_t _req = (tsize) * (cnt); \ + type *_result; \ + if (unlikely (_tail == NULL)) \ + _result = (type *) __libdw_allocate (dbg, _req, __alignof (type)); \ else \ { \ - _required += _padding; \ - _result = (type *) ((char *) _result + _padding); \ - _tail->remaining -= _required; \ + _result = (type *) (_tail->mem + (_tail->size - _tail->remaining)); \ + size_t _padding = ((__alignof (type) \ + - ((uintptr_t) _result & (__alignof (type) - 1))) \ + & (__alignof (type) - 1)); \ + if (unlikely (_tail->remaining < _req + _padding)) \ + _result = (type *) __libdw_allocate (dbg, _req, __alignof (type)); \ + else \ + { \ + _req += _padding; \ + _result = (type *) ((char *) _result + _padding); \ + _tail->remaining -= _req; \ + } \ } \ _result; }) diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c index f1e08714..f2e74d18 100644 --- a/libdw/libdw_alloc.c +++ b/libdw/libdw_alloc.c @@ -52,8 +52,10 @@ __libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) newp->size = size - offsetof (struct libdw_memblock, mem); newp->remaining = (uintptr_t) newp + size - (result + minsize); - newp->prev = dbg->mem_tail; - dbg->mem_tail = newp; + newp->prev = (struct libdw_memblock*)atomic_exchange_explicit( + &dbg->mem_tail, (uintptr_t)newp, memory_order_relaxed); + if (pthread_setspecific (dbg->mem_key, newp) != 0) + dbg->oom_handler (); return (void *) result; } |