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>
28 Initialize memory 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.
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))
64 if ((mem_root
->free
= mem_root
->pre_alloc
=
65 (USED_MEM
*) my_malloc(pre_alloc_size
+ ALIGN_SIZE(sizeof(USED_MEM
)),
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;
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'.
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
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))
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.
115 if (mem
->size
== size
)
117 /* We found a suitable block, no need to do anything else */
118 mem_root
->pre_alloc
= mem
;
121 if (mem
->left
+ ALIGN_SIZE(sizeof(USED_MEM
)) == mem
->size
)
123 /* remove block from the list and free it */
125 my_free(mem
, MYF(0));
130 /* Allocate new prealloc block and add it to the end of free list */
131 if ((mem
= (USED_MEM
*) my_malloc(size
, MYF(0))))
134 mem
->left
= pre_alloc_size
;
136 *prev
= mem_root
->pre_alloc
= mem
;
140 mem_root
->pre_alloc
= 0;
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)
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
;
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
))));
181 size_t get_size
, block_size
;
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
)
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
)
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
++;
227 next
->size
= get_size
;
228 next
->left
= get_size
-ALIGN_SIZE(sizeof(USED_MEM
));
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
)
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
);
248 Allocate many pointers at the same time.
251 ptr1, ptr2, etc all point into big allocated memory area.
256 ptr1, length1 Multiple arguments terminated by a NULL pointer
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
, ...)
269 char **ptr
, *start
, *res
;
270 size_t tot_length
, length
;
271 DBUG_ENTER("multi_alloc_root");
273 va_start(args
, root
);
275 while ((ptr
= va_arg(args
, char **)))
277 length
= va_arg(args
, uint
);
278 tot_length
+= ALIGN_SIZE(length
);
282 if (!(start
= (char*) alloc_root(root
, tot_length
)))
283 DBUG_RETURN(0); /* purecov: inspected */
285 va_start(args
, root
);
287 while ((ptr
= va_arg(args
, char **)))
290 length
= va_arg(args
, uint
);
291 res
+= ALIGN_SIZE(length
);
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
)
304 reg2 USED_MEM
**last
;
306 /* iterate through (partially) free blocks, mark them free */
308 for (next
= root
->free
; next
; next
= *(last
= &next
->next
))
310 next
->left
= next
->size
- ALIGN_SIZE(sizeof(USED_MEM
));
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
));
324 /* Now everything is set; Indicate that nothing is used anymore */
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
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
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
);
360 if (!(MyFlags
& MY_KEEP_PREALLOC
))
363 for (next
=root
->used
; next
;)
365 old
=next
; next
= next
->next
;
366 if (old
!= root
->pre_alloc
)
369 for (next
=root
->free
; next
;)
371 old
=next
; next
= next
->next
;
372 if (old
!= root
->pre_alloc
)
375 root
->used
=root
->free
=0;
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
);
384 root
->first_block_usage
= 0;
389 Find block that contains an object and set the pre_alloc to it
392 void set_prealloc_root(MEM_ROOT
*root
, char *ptr
)
395 for (next
=root
->used
; next
; next
=next
->next
)
397 if ((char*) next
<= ptr
&& (char*) next
+ next
->size
> ptr
)
399 root
->pre_alloc
=next
;
403 for (next
=root
->free
; next
; next
=next
->next
)
405 if ((char*) next
<= ptr
&& (char*) next
+ next
->size
> ptr
)
407 root
->pre_alloc
=next
;
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
)
423 if ((pos
=alloc_root(root
,len
+1)))
432 void *memdup_root(MEM_ROOT
*root
, const void *str
, size_t len
)
435 if ((pos
=alloc_root(root
,len
)))