2
* $Id: walloc.c,v 1.12 2004/01/17 13:46:23 rmanfredi Exp $
4
* Copyright (c) 2002-2003, Raphael Manfredi
6
* Explicit-width block allocator, based on zalloc().
8
*----------------------------------------------------------------------
9
* This file is part of gtk-gnutella.
11
* gtk-gnutella is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* gtk-gnutella is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with gtk-gnutella; if not, write to the Free Software
24
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
*----------------------------------------------------------------------
32
#include "override.h" /* Must be the last header included */
34
RCSID("$Id: walloc.c,v 1.12 2004/01/17 13:46:23 rmanfredi Exp $");
36
#if ZALLOC_ALIGNBYTES == 2
37
#define ZALLOC_ALIGNBITS 1
38
#elif ZALLOC_ALIGNBYTES == 4
39
#define ZALLOC_ALIGNBITS 2
40
#elif ZALLOC_ALIGNBYTES == 8
41
#define ZALLOC_ALIGNBITS 3
43
#error "Unexpected ZALLOC_ALIGNBYTES value"
47
#undef walloc /* We want to define the real routines */
52
#define WALLOC_MAX 4096 /* Passed this size, use malloc() */
53
#define WALLOC_CHUNK 4096 /* Target chunk size for small structs */
54
#define WALLOC_MINCOUNT 8 /* Minimum amount of structs in a chunk */
56
#define WZONE_SIZE (WALLOC_MAX / ZALLOC_ALIGNBYTES)
58
static struct zone *wzone[WZONE_SIZE];
61
* Under REMAP_ZALLOC, do not define walloc(), wfree() and wrealloc().
68
* Allocate memory from a zone suitable for the given size.
70
* The basics for this algorithm is to allocate from fixed-sized zones, which
71
* are multiples of ZALLOC_ALIGNBYTES until WALLOC_MAX (e.g. 8, 16, 24, 40, ...)
72
* and to malloc() if size is greater or equal to WALLOC_MAX.
73
* Naturally, zones are allocated on demand only.
75
* Returns a pointer to the start of the allocated block.
77
gpointer walloc(int size)
80
gint rounded = zalloc_round(size);
85
if (rounded >= WALLOC_MAX)
86
return g_malloc(size); /* Too big for efficient zalloc() */
88
idx = rounded >> ZALLOC_ALIGNBITS;
90
g_assert(WALLOC_MAX >> ZALLOC_ALIGNBITS == WZONE_SIZE);
91
g_assert(idx >= 0 && idx < WZONE_SIZE);
93
if (!(zone = wzone[idx])) {
97
* We're paying this computation/allocation cost once per size!
99
* Try to create approximately WALLOC_CHUNK byte chunks, but
100
* capable of holding at least WALLOC_MINCOUNT structures.
103
count = WALLOC_CHUNK / rounded;
104
count = MAX(count, WALLOC_MINCOUNT);
106
if (!(zone = wzone[idx] = zget(rounded, count)))
107
g_error("zget() failed?");
116
* Same as walloc(), but zeroes the allocated memory before returning.
118
gpointer walloc0(int size)
120
gpointer p = walloc(size);
131
* Free a block allocated via walloc().
133
* The size is used to find the zone from which the block was allocated, or
134
* to determine that we actually malloc()'ed it so it gets free()'ed.
136
void wfree(gpointer ptr, gint size)
139
gint rounded = zalloc_round(size);
145
if (rounded >= WALLOC_MAX) {
150
idx = rounded >> ZALLOC_ALIGNBITS;
152
g_assert(idx >= 0 && idx < WZONE_SIZE);
163
* Reallocate a block allocated via walloc().
164
* Returns new block address.
166
gpointer wrealloc(gpointer old, gint old_size, gint new_size)
169
gint rounded = zalloc_round(new_size);
171
if (zalloc_round(old_size) == rounded)
174
new = walloc(new_size);
175
memcpy(new, old, MIN(old_size, new_size));
176
wfree(old, old_size);
180
#endif /* !REMAP_ZALLOC */
183
*** Tracking versions of the walloc routines.
190
* Allocate memory from a zone suitable for the given size.
191
* Returns a pointer to the start of the allocated block.
193
gpointer walloc_track(int size, gchar *file, gint line)
196
gint rounded = zalloc_round(size);
201
if (rounded >= WALLOC_MAX)
203
return malloc_track(size, file, line);
205
return g_malloc(size); /* Too big for efficient zalloc() */
208
idx = rounded >> ZALLOC_ALIGNBITS;
210
g_assert(WALLOC_MAX >> ZALLOC_ALIGNBITS == WZONE_SIZE);
211
g_assert(idx >= 0 && idx < WZONE_SIZE);
213
if (!(zone = wzone[idx])) {
217
* We're paying this computation/allocation cost once per size!
219
* Try to create approximately WALLOC_CHUNK byte chunks, but
220
* capable of holding at least WALLOC_MINCOUNT structures.
223
count = WALLOC_CHUNK / rounded;
224
count = MAX(count, WALLOC_MINCOUNT);
226
if (!(zone = wzone[idx] = zget(rounded, count)))
227
g_error("zget() failed?");
230
return zalloc_track(zone, file, line);
236
* Same as walloc_track(), but zeroes the allocated memory before returning.
238
gpointer walloc0_track(int size, gchar *file, gint line)
240
gpointer p = walloc_track(size, file, line);
251
* Reallocate a block allocated via walloc().
252
* Returns new block address.
254
gpointer wrealloc_track(gpointer old, gint old_size, gint new_size,
255
gchar *file, gint line)
258
gint rounded = zalloc_round(new_size);
260
if (zalloc_round(old_size) == rounded)
263
new = walloc_track(new_size, file, line);
264
memcpy(new, old, MIN(old_size, new_size));
265
wfree(old, old_size);
269
#endif /* TRACK_ZALLOC */
274
* Destroy all the zones we allocated so far.
280
for (i = 0; i < WZONE_SIZE; i++) {
281
if (wzone[i] != NULL) {