1da0c48c4Sopenharmony_ci/* Memory handling for libdw. 2da0c48c4Sopenharmony_ci Copyright (C) 2003, 2004, 2006 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2003. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include <errno.h> 35da0c48c4Sopenharmony_ci#include <stdlib.h> 36da0c48c4Sopenharmony_ci#include "libdwP.h" 37da0c48c4Sopenharmony_ci#include "system.h" 38da0c48c4Sopenharmony_ci#include "atomics.h" 39da0c48c4Sopenharmony_ci#if USE_VG_ANNOTATIONS == 1 40da0c48c4Sopenharmony_ci#include <helgrind.h> 41da0c48c4Sopenharmony_ci#else 42da0c48c4Sopenharmony_ci#define ANNOTATE_HAPPENS_BEFORE(X) 43da0c48c4Sopenharmony_ci#define ANNOTATE_HAPPENS_AFTER(X) 44da0c48c4Sopenharmony_ci#endif 45da0c48c4Sopenharmony_ci 46da0c48c4Sopenharmony_ci#define THREAD_ID_UNSET ((size_t) -1) 47da0c48c4Sopenharmony_cistatic __thread size_t thread_id = THREAD_ID_UNSET; 48da0c48c4Sopenharmony_cistatic atomic_size_t next_id = ATOMIC_VAR_INIT(0); 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_cistruct libdw_memblock * 51da0c48c4Sopenharmony_ci__libdw_alloc_tail (Dwarf *dbg) 52da0c48c4Sopenharmony_ci{ 53da0c48c4Sopenharmony_ci if (thread_id == THREAD_ID_UNSET) 54da0c48c4Sopenharmony_ci thread_id = atomic_fetch_add (&next_id, 1); 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_ci pthread_rwlock_rdlock (&dbg->mem_rwl); 57da0c48c4Sopenharmony_ci if (thread_id >= dbg->mem_stacks) 58da0c48c4Sopenharmony_ci { 59da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 60da0c48c4Sopenharmony_ci pthread_rwlock_wrlock (&dbg->mem_rwl); 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_ci /* Another thread may have already reallocated. In theory using an 63da0c48c4Sopenharmony_ci atomic would be faster, but given that this only happens once per 64da0c48c4Sopenharmony_ci thread per Dwarf, some minor slowdown should be fine. */ 65da0c48c4Sopenharmony_ci if (thread_id >= dbg->mem_stacks) 66da0c48c4Sopenharmony_ci { 67da0c48c4Sopenharmony_ci dbg->mem_tails = realloc (dbg->mem_tails, (thread_id+1) 68da0c48c4Sopenharmony_ci * sizeof (struct libdw_memblock *)); 69da0c48c4Sopenharmony_ci if (dbg->mem_tails == NULL) 70da0c48c4Sopenharmony_ci { 71da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 72da0c48c4Sopenharmony_ci dbg->oom_handler(); 73da0c48c4Sopenharmony_ci } 74da0c48c4Sopenharmony_ci for (size_t i = dbg->mem_stacks; i <= thread_id; i++) 75da0c48c4Sopenharmony_ci dbg->mem_tails[i] = NULL; 76da0c48c4Sopenharmony_ci dbg->mem_stacks = thread_id + 1; 77da0c48c4Sopenharmony_ci ANNOTATE_HAPPENS_BEFORE (&dbg->mem_tails); 78da0c48c4Sopenharmony_ci } 79da0c48c4Sopenharmony_ci 80da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 81da0c48c4Sopenharmony_ci pthread_rwlock_rdlock (&dbg->mem_rwl); 82da0c48c4Sopenharmony_ci } 83da0c48c4Sopenharmony_ci 84da0c48c4Sopenharmony_ci /* At this point, we have an entry in the tail array. */ 85da0c48c4Sopenharmony_ci ANNOTATE_HAPPENS_AFTER (&dbg->mem_tails); 86da0c48c4Sopenharmony_ci struct libdw_memblock *result = dbg->mem_tails[thread_id]; 87da0c48c4Sopenharmony_ci if (result == NULL) 88da0c48c4Sopenharmony_ci { 89da0c48c4Sopenharmony_ci result = malloc (dbg->mem_default_size); 90da0c48c4Sopenharmony_ci if (result == NULL) 91da0c48c4Sopenharmony_ci { 92da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 93da0c48c4Sopenharmony_ci dbg->oom_handler(); 94da0c48c4Sopenharmony_ci } 95da0c48c4Sopenharmony_ci result->size = dbg->mem_default_size 96da0c48c4Sopenharmony_ci - offsetof (struct libdw_memblock, mem); 97da0c48c4Sopenharmony_ci result->remaining = result->size; 98da0c48c4Sopenharmony_ci result->prev = NULL; 99da0c48c4Sopenharmony_ci dbg->mem_tails[thread_id] = result; 100da0c48c4Sopenharmony_ci } 101da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 102da0c48c4Sopenharmony_ci return result; 103da0c48c4Sopenharmony_ci} 104da0c48c4Sopenharmony_ci 105da0c48c4Sopenharmony_ci/* Can only be called after a allocation for this thread has already 106da0c48c4Sopenharmony_ci been done, to possibly undo it. */ 107da0c48c4Sopenharmony_cistruct libdw_memblock * 108da0c48c4Sopenharmony_ci__libdw_thread_tail (Dwarf *dbg) 109da0c48c4Sopenharmony_ci{ 110da0c48c4Sopenharmony_ci struct libdw_memblock *result; 111da0c48c4Sopenharmony_ci pthread_rwlock_rdlock (&dbg->mem_rwl); 112da0c48c4Sopenharmony_ci result = dbg->mem_tails[thread_id]; 113da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 114da0c48c4Sopenharmony_ci return result; 115da0c48c4Sopenharmony_ci} 116da0c48c4Sopenharmony_ci 117da0c48c4Sopenharmony_civoid * 118da0c48c4Sopenharmony_ci__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) 119da0c48c4Sopenharmony_ci{ 120da0c48c4Sopenharmony_ci size_t size = MAX (dbg->mem_default_size, 121da0c48c4Sopenharmony_ci (align - 1 + 122da0c48c4Sopenharmony_ci 2 * minsize + offsetof (struct libdw_memblock, mem))); 123da0c48c4Sopenharmony_ci struct libdw_memblock *newp = malloc (size); 124da0c48c4Sopenharmony_ci if (newp == NULL) 125da0c48c4Sopenharmony_ci dbg->oom_handler (); 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ci uintptr_t result = ((uintptr_t) newp->mem + align - 1) & ~(align - 1); 128da0c48c4Sopenharmony_ci 129da0c48c4Sopenharmony_ci newp->size = size - offsetof (struct libdw_memblock, mem); 130da0c48c4Sopenharmony_ci newp->remaining = (uintptr_t) newp + size - (result + minsize); 131da0c48c4Sopenharmony_ci 132da0c48c4Sopenharmony_ci pthread_rwlock_rdlock (&dbg->mem_rwl); 133da0c48c4Sopenharmony_ci newp->prev = dbg->mem_tails[thread_id]; 134da0c48c4Sopenharmony_ci dbg->mem_tails[thread_id] = newp; 135da0c48c4Sopenharmony_ci pthread_rwlock_unlock (&dbg->mem_rwl); 136da0c48c4Sopenharmony_ci 137da0c48c4Sopenharmony_ci return (void *) result; 138da0c48c4Sopenharmony_ci} 139da0c48c4Sopenharmony_ci 140da0c48c4Sopenharmony_ci 141da0c48c4Sopenharmony_ciDwarf_OOM 142da0c48c4Sopenharmony_cidwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler) 143da0c48c4Sopenharmony_ci{ 144da0c48c4Sopenharmony_ci Dwarf_OOM old = dbg->oom_handler; 145da0c48c4Sopenharmony_ci dbg->oom_handler = handler; 146da0c48c4Sopenharmony_ci return old; 147da0c48c4Sopenharmony_ci} 148da0c48c4Sopenharmony_ci 149da0c48c4Sopenharmony_ci 150da0c48c4Sopenharmony_civoid 151da0c48c4Sopenharmony_ci__attribute ((noreturn)) attribute_hidden 152da0c48c4Sopenharmony_ci__libdw_oom (void) 153da0c48c4Sopenharmony_ci{ 154da0c48c4Sopenharmony_ci while (1) 155da0c48c4Sopenharmony_ci error (EXIT_FAILURE, ENOMEM, "libdw"); 156da0c48c4Sopenharmony_ci} 157