mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / mysys / my_alloc.c
blob6a5fad822a66dd6c9e0bd39f5db175a481edbbe8
1 /*
2 Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 /* Routines to handle mallocing of results which will be freed the same time */
20 #include <my_global.h>
21 #include <my_sys.h>
22 #include <m_string.h>
23 #undef EXTRA_DEBUG
24 #define EXTRA_DEBUG
28 Initialize memory root
30 SYNOPSIS
31 init_alloc_root()
32 mem_root - memory root to initialize
33 block_size - size of chunks (blocks) used for memory allocation
34 (It is external size of chunk i.e. it should include
35 memory required for internal structures, thus it
36 should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
37 pre_alloc_size - if non-0, then size of block that should be
38 pre-allocated during memory root initialization.
40 DESCRIPTION
41 This function prepares memory root for further use, sets initial size of
42 chunk for memory allocation and pre-allocates first block if specified.
43 Altough error can happen during execution of this function if
44 pre_alloc_size is non-0 it won't be reported. Instead it will be
45 reported as error in first alloc_root() on this memory root.
48 void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
49 size_t pre_alloc_size __attribute__((unused)))
51 DBUG_ENTER("init_alloc_root");
52 DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
54 mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
55 mem_root->min_malloc= 32;
56 mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
57 mem_root->error_handler= 0;
58 mem_root->block_num= 4; /* We shift this with >>2 */
59 mem_root->first_block_usage= 0;
61 #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
62 if (pre_alloc_size)
64 if ((mem_root->free= mem_root->pre_alloc=
65 (USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
66 MYF(0))))
68 mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
69 mem_root->free->left= pre_alloc_size;
70 mem_root->free->next= 0;
73 #endif
74 DBUG_VOID_RETURN;
79 SYNOPSIS
80 reset_root_defaults()
81 mem_root memory root to change defaults of
82 block_size new value of block size. Must be greater or equal
83 than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
84 68 bytes and depends on platform and compilation flags)
85 pre_alloc_size new size of preallocated block. If not zero,
86 must be equal to or greater than block size,
87 otherwise means 'no prealloc'.
88 DESCRIPTION
89 Function aligns and assigns new value to block size; then it tries to
90 reuse one of existing blocks as prealloc block, or malloc new one of
91 requested size. If no blocks can be reused, all unused blocks are freed
92 before allocation.
95 void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
96 size_t pre_alloc_size __attribute__((unused)))
98 DBUG_ASSERT(alloc_root_inited(mem_root));
100 mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
101 #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
102 if (pre_alloc_size)
104 size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
105 if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
107 USED_MEM *mem, **prev= &mem_root->free;
109 Free unused blocks, so that consequent calls
110 to reset_root_defaults won't eat away memory.
112 while (*prev)
114 mem= *prev;
115 if (mem->size == size)
117 /* We found a suitable block, no need to do anything else */
118 mem_root->pre_alloc= mem;
119 return;
121 if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
123 /* remove block from the list and free it */
124 *prev= mem->next;
125 my_free(mem, MYF(0));
127 else
128 prev= &mem->next;
130 /* Allocate new prealloc block and add it to the end of free list */
131 if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
133 mem->size= size;
134 mem->left= pre_alloc_size;
135 mem->next= *prev;
136 *prev= mem_root->pre_alloc= mem;
138 else
140 mem_root->pre_alloc= 0;
144 else
145 #endif
146 mem_root->pre_alloc= 0;
150 void *alloc_root(MEM_ROOT *mem_root, size_t length)
152 #if defined(HAVE_purify) && defined(EXTRA_DEBUG)
153 reg1 USED_MEM *next;
154 DBUG_ENTER("alloc_root");
155 DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
157 DBUG_ASSERT(alloc_root_inited(mem_root));
159 DBUG_EXECUTE_IF("simulate_out_of_memory",
161 if (mem_root->error_handler)
162 (*mem_root->error_handler)();
163 DBUG_SET("-d,simulate_out_of_memory");
164 DBUG_RETURN((void*) 0); /* purecov: inspected */
167 length+=ALIGN_SIZE(sizeof(USED_MEM));
168 if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME))))
170 if (mem_root->error_handler)
171 (*mem_root->error_handler)();
172 DBUG_RETURN((uchar*) 0); /* purecov: inspected */
174 next->next= mem_root->used;
175 next->size= length;
176 mem_root->used= next;
177 DBUG_PRINT("exit",("ptr: 0x%lx", (long) (((char*) next)+
178 ALIGN_SIZE(sizeof(USED_MEM)))));
179 DBUG_RETURN((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
180 #else
181 size_t get_size, block_size;
182 uchar* point;
183 reg1 USED_MEM *next= 0;
184 reg2 USED_MEM **prev;
185 DBUG_ENTER("alloc_root");
186 DBUG_PRINT("enter",("root: 0x%lx", (long) mem_root));
187 DBUG_ASSERT(alloc_root_inited(mem_root));
189 DBUG_EXECUTE_IF("simulate_out_of_memory",
191 /* Avoid reusing an already allocated block */
192 if (mem_root->error_handler)
193 (*mem_root->error_handler)();
194 DBUG_SET("-d,simulate_out_of_memory");
195 DBUG_RETURN((void*) 0); /* purecov: inspected */
197 length= ALIGN_SIZE(length);
198 if ((*(prev= &mem_root->free)) != NULL)
200 if ((*prev)->left < length &&
201 mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
202 (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
204 next= *prev;
205 *prev= next->next; /* Remove block from list */
206 next->next= mem_root->used;
207 mem_root->used= next;
208 mem_root->first_block_usage= 0;
210 for (next= *prev ; next && next->left < length ; next= next->next)
211 prev= &next->next;
213 if (! next)
214 { /* Time to alloc new block */
215 block_size= mem_root->block_size * (mem_root->block_num >> 2);
216 get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
217 get_size= max(get_size, block_size);
219 if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
221 if (mem_root->error_handler)
222 (*mem_root->error_handler)();
223 DBUG_RETURN((void*) 0); /* purecov: inspected */
225 mem_root->block_num++;
226 next->next= *prev;
227 next->size= get_size;
228 next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
229 *prev=next;
232 point= (uchar*) ((char*) next+ (next->size-next->left));
233 /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
234 if ((next->left-= length) < mem_root->min_malloc)
235 { /* Full block */
236 *prev= next->next; /* Remove block from list */
237 next->next= mem_root->used;
238 mem_root->used= next;
239 mem_root->first_block_usage= 0;
241 DBUG_PRINT("exit",("ptr: 0x%lx", (ulong) point));
242 DBUG_RETURN((void*) point);
243 #endif
248 Allocate many pointers at the same time.
250 DESCRIPTION
251 ptr1, ptr2, etc all point into big allocated memory area.
253 SYNOPSIS
254 multi_alloc_root()
255 root Memory root
256 ptr1, length1 Multiple arguments terminated by a NULL pointer
257 ptr2, length2 ...
259 NULL
261 RETURN VALUE
262 A pointer to the beginning of the allocated memory block
263 in case of success or NULL if out of memory.
266 void *multi_alloc_root(MEM_ROOT *root, ...)
268 va_list args;
269 char **ptr, *start, *res;
270 size_t tot_length, length;
271 DBUG_ENTER("multi_alloc_root");
273 va_start(args, root);
274 tot_length= 0;
275 while ((ptr= va_arg(args, char **)))
277 length= va_arg(args, uint);
278 tot_length+= ALIGN_SIZE(length);
280 va_end(args);
282 if (!(start= (char*) alloc_root(root, tot_length)))
283 DBUG_RETURN(0); /* purecov: inspected */
285 va_start(args, root);
286 res= start;
287 while ((ptr= va_arg(args, char **)))
289 *ptr= res;
290 length= va_arg(args, uint);
291 res+= ALIGN_SIZE(length);
293 va_end(args);
294 DBUG_RETURN((void*) start);
297 #define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
299 /* Mark all data in blocks free for reusage */
301 static inline void mark_blocks_free(MEM_ROOT* root)
303 reg1 USED_MEM *next;
304 reg2 USED_MEM **last;
306 /* iterate through (partially) free blocks, mark them free */
307 last= &root->free;
308 for (next= root->free; next; next= *(last= &next->next))
310 next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
311 TRASH_MEM(next);
314 /* Combine the free and the used list */
315 *last= next=root->used;
317 /* now go through the used blocks and mark them free */
318 for (; next; next= next->next)
320 next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
321 TRASH_MEM(next);
324 /* Now everything is set; Indicate that nothing is used anymore */
325 root->used= 0;
326 root->first_block_usage= 0;
331 Deallocate everything used by alloc_root or just move
332 used blocks to free list if called with MY_USED_TO_FREE
334 SYNOPSIS
335 free_root()
336 root Memory root
337 MyFlags Flags for what should be freed:
339 MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
340 MY_KEEP_PREALLOC If this is not set, then free also the
341 preallocated block
343 NOTES
344 One can call this function either with root block initialised with
345 init_alloc_root() or with a bzero()-ed block.
346 It's also safe to call this multiple times with the same mem_root.
349 void free_root(MEM_ROOT *root, myf MyFlags)
351 reg1 USED_MEM *next,*old;
352 DBUG_ENTER("free_root");
353 DBUG_PRINT("enter",("root: 0x%lx flags: %u", (long) root, (uint) MyFlags));
355 if (MyFlags & MY_MARK_BLOCKS_FREE)
357 mark_blocks_free(root);
358 DBUG_VOID_RETURN;
360 if (!(MyFlags & MY_KEEP_PREALLOC))
361 root->pre_alloc=0;
363 for (next=root->used; next ;)
365 old=next; next= next->next ;
366 if (old != root->pre_alloc)
367 my_free(old,MYF(0));
369 for (next=root->free ; next ;)
371 old=next; next= next->next;
372 if (old != root->pre_alloc)
373 my_free(old,MYF(0));
375 root->used=root->free=0;
376 if (root->pre_alloc)
378 root->free=root->pre_alloc;
379 root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
380 TRASH_MEM(root->pre_alloc);
381 root->free->next=0;
383 root->block_num= 4;
384 root->first_block_usage= 0;
385 DBUG_VOID_RETURN;
389 Find block that contains an object and set the pre_alloc to it
392 void set_prealloc_root(MEM_ROOT *root, char *ptr)
394 USED_MEM *next;
395 for (next=root->used; next ; next=next->next)
397 if ((char*) next <= ptr && (char*) next + next->size > ptr)
399 root->pre_alloc=next;
400 return;
403 for (next=root->free ; next ; next=next->next)
405 if ((char*) next <= ptr && (char*) next + next->size > ptr)
407 root->pre_alloc=next;
408 return;
414 char *strdup_root(MEM_ROOT *root, const char *str)
416 return strmake_root(root, str, strlen(str));
420 char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
422 char *pos;
423 if ((pos=alloc_root(root,len+1)))
425 memcpy(pos,str,len);
426 pos[len]=0;
428 return pos;
432 void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
434 char *pos;
435 if ((pos=alloc_root(root,len)))
436 memcpy(pos,str,len);
437 return pos;