1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Routines to handle mallocing of results which will be freed the same time */
18
#include <my_global.h>
26
Initialize memory root
30
mem_root - memory root to initialize
31
block_size - size of chunks (blocks) used for memory allocation
32
(It is external size of chunk i.e. it should include
33
memory required for internal structures, thus it
34
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
35
pre_alloc_size - if non-0, then size of block that should be
36
pre-allocated during memory root initialization.
39
This function prepares memory root for further use, sets initial size of
40
chunk for memory allocation and pre-allocates first block if specified.
41
Altough error can happen during execution of this function if
42
pre_alloc_size is non-0 it won't be reported. Instead it will be
43
reported as error in first alloc_root() on this memory root.
46
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
47
size_t pre_alloc_size __attribute__((unused)))
49
DBUG_ENTER("init_alloc_root");
50
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
52
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
53
mem_root->min_malloc= 32;
54
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
55
mem_root->error_handler= 0;
56
mem_root->block_num= 4; /* We shift this with >>2 */
57
mem_root->first_block_usage= 0;
59
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
62
if ((mem_root->free= mem_root->pre_alloc=
63
(USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
66
mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
67
mem_root->free->left= pre_alloc_size;
68
mem_root->free->next= 0;
79
mem_root memory root to change defaults of
80
block_size new value of block size. Must be greater or equal
81
than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
82
68 bytes and depends on platform and compilation flags)
83
pre_alloc_size new size of preallocated block. If not zero,
84
must be equal to or greater than block size,
85
otherwise means 'no prealloc'.
87
Function aligns and assigns new value to block size; then it tries to
88
reuse one of existing blocks as prealloc block, or malloc new one of
89
requested size. If no blocks can be reused, all unused blocks are freed
93
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
94
size_t pre_alloc_size __attribute__((unused)))
96
DBUG_ASSERT(alloc_root_inited(mem_root));
98
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
99
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
102
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
103
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
105
USED_MEM *mem, **prev= &mem_root->free;
107
Free unused blocks, so that consequent calls
108
to reset_root_defaults won't eat away memory.
113
if (mem->size == size)
115
/* We found a suitable block, no need to do anything else */
116
mem_root->pre_alloc= mem;
119
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
121
/* remove block from the list and free it */
123
my_free(mem, MYF(0));
128
/* Allocate new prealloc block and add it to the end of free list */
129
if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
132
mem->left= pre_alloc_size;
134
*prev= mem_root->pre_alloc= mem;
138
mem_root->pre_alloc= 0;
144
mem_root->pre_alloc= 0;
148
void *alloc_root(MEM_ROOT *mem_root, size_t length)
150
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
151
register USED_MEM *next;
152
DBUG_ENTER("alloc_root");
153
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
155
DBUG_ASSERT(alloc_root_inited(mem_root));
157
length+=ALIGN_SIZE(sizeof(USED_MEM));
158
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
160
if (mem_root->error_handler)
161
(*mem_root->error_handler)();
162
DBUG_RETURN((uchar*) 0); /* purecov: inspected */
164
next->next= mem_root->used;
166
mem_root->used= next;
167
DBUG_PRINT("exit",("ptr: 0x%lx", (long) (((char*) next)+
168
ALIGN_SIZE(sizeof(USED_MEM)))));
169
DBUG_RETURN((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
171
size_t get_size, block_size;
173
register USED_MEM *next= 0;
174
register USED_MEM **prev;
175
DBUG_ENTER("alloc_root");
176
DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
177
DBUG_ASSERT(alloc_root_inited(mem_root));
179
length= ALIGN_SIZE(length);
180
if ((*(prev= &mem_root->free)) != NULL)
182
if ((*prev)->left < length &&
183
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
184
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
187
*prev= next->next; /* Remove block from list */
188
next->next= mem_root->used;
189
mem_root->used= next;
190
mem_root->first_block_usage= 0;
192
for (next= *prev ; next && next->left < length ; next= next->next)
196
{ /* Time to alloc new block */
197
block_size= mem_root->block_size * (mem_root->block_num >> 2);
198
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
199
get_size= max(get_size, block_size);
201
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
203
if (mem_root->error_handler)
204
(*mem_root->error_handler)();
205
DBUG_RETURN((void*) 0); /* purecov: inspected */
207
mem_root->block_num++;
209
next->size= get_size;
210
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
214
point= (uchar*) ((char*) next+ (next->size-next->left));
215
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
216
if ((next->left-= length) < mem_root->min_malloc)
218
*prev= next->next; /* Remove block from list */
219
next->next= mem_root->used;
220
mem_root->used= next;
221
mem_root->first_block_usage= 0;
223
DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point));
224
DBUG_RETURN((void*) point);
230
Allocate many pointers at the same time.
233
ptr1, ptr2, etc all point into big allocated memory area.
238
ptr1, length1 Multiple arguments terminated by a NULL pointer
244
A pointer to the beginning of the allocated memory block
245
in case of success or NULL if out of memory.
248
void *multi_alloc_root(MEM_ROOT *root, ...)
251
char **ptr, *start, *res;
252
size_t tot_length, length;
253
DBUG_ENTER("multi_alloc_root");
255
va_start(args, root);
257
while ((ptr= va_arg(args, char **)))
259
length= va_arg(args, uint);
260
tot_length+= ALIGN_SIZE(length);
264
if (!(start= (char*) alloc_root(root, tot_length)))
265
DBUG_RETURN(0); /* purecov: inspected */
267
va_start(args, root);
269
while ((ptr= va_arg(args, char **)))
272
length= va_arg(args, uint);
273
res+= ALIGN_SIZE(length);
276
DBUG_RETURN((void*) start);
279
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
281
/* Mark all data in blocks free for reusage */
283
static inline void mark_blocks_free(MEM_ROOT* root)
285
register USED_MEM *next;
286
register USED_MEM **last;
288
/* iterate through (partially) free blocks, mark them free */
290
for (next= root->free; next; next= *(last= &next->next))
292
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
296
/* Combine the free and the used list */
297
*last= next=root->used;
299
/* now go through the used blocks and mark them free */
300
for (; next; next= next->next)
302
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
306
/* Now everything is set; Indicate that nothing is used anymore */
308
root->first_block_usage= 0;
313
Deallocate everything used by alloc_root or just move
314
used blocks to free list if called with MY_USED_TO_FREE
319
MyFlags Flags for what should be freed:
321
MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
322
MY_KEEP_PREALLOC If this is not set, then free also the
326
One can call this function either with root block initialised with
327
init_alloc_root() or with a bzero()-ed block.
328
It's also safe to call this multiple times with the same mem_root.
331
void free_root(MEM_ROOT *root, myf MyFlags)
333
register USED_MEM *next,*old;
334
DBUG_ENTER("free_root");
335
DBUG_PRINT("enter",("root: 0x%lx flags: %u", (long) root, (uint) MyFlags));
337
if (MyFlags & MY_MARK_BLOCKS_FREE)
339
mark_blocks_free(root);
342
if (!(MyFlags & MY_KEEP_PREALLOC))
345
for (next=root->used; next ;)
347
old=next; next= next->next ;
348
if (old != root->pre_alloc)
351
for (next=root->free ; next ;)
353
old=next; next= next->next;
354
if (old != root->pre_alloc)
357
root->used=root->free=0;
360
root->free=root->pre_alloc;
361
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
362
TRASH_MEM(root->pre_alloc);
366
root->first_block_usage= 0;
371
Find block that contains an object and set the pre_alloc to it
374
void set_prealloc_root(MEM_ROOT *root, char *ptr)
377
for (next=root->used; next ; next=next->next)
379
if ((char*) next <= ptr && (char*) next + next->size > ptr)
381
root->pre_alloc=next;
385
for (next=root->free ; next ; next=next->next)
387
if ((char*) next <= ptr && (char*) next + next->size > ptr)
389
root->pre_alloc=next;
396
char *strdup_root(MEM_ROOT *root, const char *str)
398
return strmake_root(root, str, strlen(str));
402
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
405
if ((pos=alloc_root(root,len+1)))
414
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
417
if ((pos=alloc_root(root,len)))