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