]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/malloc/table.c
Bash-4.3 distribution sources and documentation
[thirdparty/bash.git] / lib / malloc / table.c
CommitLineData
f73dda09
JA
1/* table.c - bookkeeping functions for allocated memory */
2
b80f6443 3/* Copyright (C) 2001-2003 Free Software Foundation, Inc.
f73dda09
JA
4
5 This file is part of GNU Bash, the Bourne Again SHell.
6
3185942a
JA
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
20
f73dda09
JA
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
25#include <stdio.h>
0628567a 26#include <string.h>
f73dda09
JA
27
28#include "imalloc.h"
29#include "table.h"
30
ac50fbac
CR
31#ifdef SHELL
32extern int interrupt_immediately, running_trap;
33extern int signal_is_trapped __P((int));
34#endif
35
f73dda09
JA
36extern int malloc_register;
37
38#ifdef MALLOC_REGISTER
39
40#define FIND_ALLOC 0x01 /* allocate new entry or find existing */
41#define FIND_EXIST 0x02 /* find existing entry */
42
43static int table_count = 0;
7117c2d2 44static int table_allocated = 0;
f73dda09 45static mr_table_t mem_table[REG_TABLE_SIZE];
7117c2d2 46static mr_table_t mem_overflow;
f73dda09
JA
47
48/*
49 * NOTE: taken from dmalloc (http://dmalloc.com) and modified.
50 */
51static unsigned int
52mt_hash (key)
53 const PTR_T key;
54{
7117c2d2 55 unsigned int a, b, c;
f73dda09
JA
56 unsigned long x;
57
58 /* set up the internal state */
59 a = 0x9e3779b9; /* the golden ratio; an arbitrary value */
60 x = (unsigned long)key; /* truncation is OK */
61 b = x >> 8;
62 c = x >> 3; /* XXX - was >> 4 */
63
64 HASH_MIX(a, b, c);
65 return c;
66}
67
68#if 0
69static unsigned int
70which_bucket (mem)
71 PTR_T mem;
72{
7117c2d2 73 return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1));
f73dda09
JA
74}
75#else
7117c2d2 76#define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
f73dda09
JA
77#endif
78
79static mr_table_t *
80find_entry (mem, flags)
81 PTR_T mem;
82 int flags;
83{
84 unsigned int bucket;
85 register mr_table_t *tp;
86 mr_table_t *endp, *lastp;
87
7117c2d2
JA
88 if (mem_overflow.mem == mem)
89 return (&mem_overflow);
90
f73dda09
JA
91 bucket = which_bucket (mem); /* get initial hash */
92 tp = endp = mem_table + bucket;
93 lastp = mem_table + REG_TABLE_SIZE;
94
95 while (1)
96 {
97 if (tp->mem == mem)
98 return (tp);
99 if (tp->mem == 0 && (flags & FIND_ALLOC))
100 {
101 table_count++;
102 return (tp);
103 }
104
105 tp++;
106
107 if (tp == lastp) /* wrap around */
108 tp = mem_table;
109
110 if (tp == endp && (flags & FIND_EXIST))
111 return ((mr_table_t *)NULL);
112
113 if (tp == endp && (flags & FIND_ALLOC))
114 break;
115 }
116
117 /* oops. table is full. replace an existing free entry. */
118 do
119 {
7117c2d2
JA
120 /* If there are no free entries, punt right away without searching. */
121 if (table_allocated == REG_TABLE_SIZE)
122 break;
123
f73dda09
JA
124 if (tp->flags & MT_FREE)
125 {
126 memset(tp, 0, sizeof (mr_table_t));
127 return (tp);
128 }
129 tp++;
7117c2d2
JA
130
131 if (tp == lastp)
132 tp = mem_table;
f73dda09
JA
133 }
134 while (tp != endp);
135
7117c2d2
JA
136 /* wow. entirely full. return mem_overflow dummy entry. */
137 tp = &mem_overflow;
138 memset (tp, 0, sizeof (mr_table_t));
139 return tp;
f73dda09
JA
140}
141
142mr_table_t *
143mr_table_entry (mem)
144 PTR_T mem;
145{
146 return (find_entry (mem, FIND_EXIST));
147}
148
149void
150mregister_describe_mem (mem, fp)
151 PTR_T mem;
152 FILE *fp;
153{
154 mr_table_t *entry;
155
156 entry = find_entry (mem, FIND_EXIST);
157 if (entry == 0)
158 return;
159 fprintf (fp, "malloc: %p: %s: last %s from %s:%d\n",
160 mem,
161 (entry->flags & MT_ALLOC) ? "allocated" : "free",
162 (entry->flags & MT_ALLOC) ? "allocated" : "freed",
163 entry->file ? entry->file : "unknown",
164 entry->line);
165}
166
167void
168mregister_alloc (tag, mem, size, file, line)
169 const char *tag;
170 PTR_T mem;
171 size_t size;
172 const char *file;
173 int line;
174{
175 mr_table_t *tentry;
ac50fbac
CR
176 sigset_t set, oset;
177 int blocked_sigs;
178
179 /* Block all signals in case we are executed from a signal handler. */
180 blocked_sigs = 0;
181#ifdef SHELL
182 if (interrupt_immediately || running_trap || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD))
183#endif
184 {
185 _malloc_block_signals (&set, &oset);
186 blocked_sigs = 1;
187 }
f73dda09
JA
188
189 tentry = find_entry (mem, FIND_ALLOC);
190
191 if (tentry == 0)
192 {
193 /* oops. table is full. punt. */
b80f6443 194 fprintf (stderr, _("register_alloc: alloc table is full with FIND_ALLOC?\n"));
ac50fbac
CR
195 if (blocked_sigs)
196 _malloc_unblock_signals (&set, &oset);
f73dda09
JA
197 return;
198 }
199
200 if (tentry->flags & MT_ALLOC)
201 {
202 /* oops. bad bookkeeping. ignore for now */
b80f6443 203 fprintf (stderr, _("register_alloc: %p already in table as allocated?\n"), mem);
f73dda09
JA
204 }
205
206 tentry->mem = mem;
207 tentry->size = size;
208 tentry->func = tag;
209 tentry->flags = MT_ALLOC;
210 tentry->file = file;
211 tentry->line = line;
212 tentry->nalloc++;
7117c2d2
JA
213
214 if (tentry != &mem_overflow)
215 table_allocated++;
ac50fbac
CR
216
217 if (blocked_sigs)
218 _malloc_unblock_signals (&set, &oset);
f73dda09
JA
219}
220
221void
222mregister_free (mem, size, file, line)
223 PTR_T mem;
224 int size;
225 const char *file;
226 int line;
227{
228 mr_table_t *tentry;
ac50fbac
CR
229 sigset_t set, oset;
230 int blocked_sigs;
231
232 /* Block all signals in case we are executed from a signal handler. */
233 blocked_sigs = 0;
234#ifdef SHELL
235 if (interrupt_immediately || running_trap || signal_is_trapped (SIGINT) || signal_is_trapped (SIGCHLD))
236#endif
237 {
238 _malloc_block_signals (&set, &oset);
239 blocked_sigs = 1;
240 }
f73dda09
JA
241
242 tentry = find_entry (mem, FIND_EXIST);
243 if (tentry == 0)
244 {
245 /* oops. not found. */
7117c2d2 246#if 0
f73dda09 247 fprintf (stderr, "register_free: %p not in allocation table?\n", mem);
7117c2d2 248#endif
ac50fbac
CR
249 if (blocked_sigs)
250 _malloc_unblock_signals (&set, &oset);
f73dda09
JA
251 return;
252 }
253 if (tentry->flags & MT_FREE)
254 {
255 /* oops. bad bookkeeping. ignore for now */
b80f6443 256 fprintf (stderr, _("register_free: %p already in table as free?\n"), mem);
f73dda09
JA
257 }
258
259 tentry->flags = MT_FREE;
260 tentry->func = "free";
261 tentry->file = file;
262 tentry->line = line;
263 tentry->nfree++;
7117c2d2
JA
264
265 if (tentry != &mem_overflow)
266 table_allocated--;
ac50fbac
CR
267
268 if (blocked_sigs)
269 _malloc_unblock_signals (&set, &oset);
f73dda09
JA
270}
271
272/* If we ever add more flags, this will require changes. */
273static char *
274_entry_flags(x)
275 int x;
276{
277 if (x & MT_FREE)
278 return "free";
279 else if (x & MT_ALLOC)
280 return "allocated";
281 else
282 return "undetermined?";
283}
284
285static void
286_register_dump_table(fp)
287 FILE *fp;
288{
289 register int i;
290 mr_table_t entry;
291
292 for (i = 0; i < REG_TABLE_SIZE; i++)
293 {
294 entry = mem_table[i];
295 if (entry.mem)
296 fprintf (fp, "[%d] %p:%d:%s:%s:%s:%d:%d:%d\n", i,
297 entry.mem, entry.size,
298 _entry_flags(entry.flags),
299 entry.func ? entry.func : "unknown",
300 entry.file ? entry.file : "unknown",
301 entry.line,
302 entry.nalloc, entry.nfree);
303 }
304}
305
306void
307mregister_dump_table()
308{
309 _register_dump_table (stderr);
310}
311
312void
313mregister_table_init ()
314{
315 memset (mem_table, 0, sizeof(mr_table_t) * REG_TABLE_SIZE);
7117c2d2 316 memset (&mem_overflow, 0, sizeof (mr_table_t));
f73dda09
JA
317 table_count = 0;
318}
319
320#endif /* MALLOC_REGISTER */
321
322int
323malloc_set_register(n)
324 int n;
325{
326 int old;
327
328 old = malloc_register;
329 malloc_register = n;
330 return old;
331}