30
33
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
31
34
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
34
Initialize memory root
37
memory::init_alloc_root()
38
mem_root - memory root to initialize
39
block_size - size of chunks (blocks) used for memory allocation
40
(It is external size of chunk i.e. it should include
41
memory required for internal structures, thus it
42
should be no less than memory::ROOT_MIN_BLOCK_SIZE)
45
This function prepares memory root for further use, sets initial size of
46
chunk for memory allocation and pre-allocates first block if specified.
47
Altough error can happen during execution of this function if
48
pre_alloc_size is non-0 it won't be reported. Instead it will be
49
reported as error in first alloc_root() on this memory root.
52
void memory::init_alloc_root(memory::Root *mem_root, size_t block_size)
38
* Initialize memory root
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.
47
* @param mem_root memory root to initialize
48
* @param block_size size of chunks (blocks) used for memory allocation
49
* (It is external size of chunk i.e. it should include
50
* memory required for internal structures, thus it
51
* should be no less than memory::ROOT_MIN_BLOCK_SIZE)
54
void memory::Root::init_alloc_root(size_t block_size_arg)
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 - memory::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;
56
free= used= pre_alloc= 0;
58
block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
60
block_num= 4; /* We shift this with >>2 */
68
mem_root memory root to change defaults of
69
block_size new value of block size. Must be greater or equal
70
than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
71
68 bytes and depends on platform and compilation flags)
72
pre_alloc_size new size of preallocated block. If not zero,
73
must be equal to or greater than block size,
74
otherwise means 'no prealloc'.
76
Function aligns and assigns new value to block size; then it tries to
77
reuse one of existing blocks as prealloc block, or malloc new one of
78
requested size. If no blocks can be reused, all unused blocks are freed
82
void memory::reset_root_defaults(memory::Root *mem_root, size_t block_size,
83
size_t pre_alloc_size)
67
* Function aligns and assigns new value to block size; then it tries to
68
* reuse one of existing blocks as prealloc block, or malloc new one of
69
* requested size. If no blocks can be reused, all unused blocks are freed
72
* @param mem_root memory root to change defaults of
73
* @param block_size new value of block size. Must be greater or equal
74
* than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
75
* 68 bytes and depends on platform and compilation flags)
76
* @param pre_alloc_size new size of preallocated block. If not zero,
77
* must be equal to or greater than block size,
78
* otherwise means 'no prealloc'.
80
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
85
assert(alloc_root_inited(mem_root));
87
mem_root->block_size= block_size - memory::ROOT_MIN_BLOCK_SIZE;
82
block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
88
83
if (pre_alloc_size)
90
85
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
91
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
86
if (not pre_alloc || pre_alloc->size != size)
93
memory::internal::UsedMemory *mem, **prev= &mem_root->free;
88
memory::internal::UsedMemory *mem, **prev= &this->free;
95
90
Free unused blocks, so that consequent calls
96
91
to reset_root_defaults won't eat away memory.
120
115
mem->left= pre_alloc_size;
121
116
mem->next= *prev;
122
*prev= mem_root->pre_alloc= mem;
117
*prev= pre_alloc= mem;
126
mem_root->pre_alloc= 0;
132
mem_root->pre_alloc= 0;
137
void *memory::alloc_root(memory::Root *mem_root, size_t length)
133
* Allocate a chunk of memory from the Root structure provided,
134
* obtaining more memory from the heap if necessary
137
* mem_root must have been initialised via init_alloc_root()
139
* @param mem_root The memory Root to allocate from
140
* @param length The size of the block to allocate
142
* @todo Would this be more suitable as a member function on the
145
void *memory::Root::alloc_root(size_t length)
139
size_t get_size, block_size;
140
147
unsigned char* point;
141
148
memory::internal::UsedMemory *next= NULL;
142
149
memory::internal::UsedMemory **prev;
143
assert(alloc_root_inited(mem_root));
150
assert(alloc_root_inited());
145
152
length= ALIGN_SIZE(length);
146
if ((*(prev= &mem_root->free)) != NULL)
153
if ((*(prev= &this->free)) != NULL)
148
155
if ((*prev)->left < length &&
149
mem_root->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
156
this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
150
157
(*prev)->left < MAX_BLOCK_TO_DROP)
153
160
*prev= next->next; /* Remove block from list */
154
next->next= mem_root->used;
155
mem_root->used= next;
156
mem_root->first_block_usage= 0;
161
next->next= this->used;
163
this->first_block_usage= 0;
158
165
for (next= *prev ; next && next->left < length ; next= next->next)
159
166
prev= &next->next;
162
169
{ /* Time to alloc new block */
163
block_size= mem_root->block_size * (mem_root->block_num >> 2);
170
size_t get_size, tmp_block_size;
172
tmp_block_size= this->block_size * (this->block_num >> 2);
164
173
get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
165
get_size= max(get_size, block_size);
174
get_size= max(get_size, tmp_block_size);
167
176
if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
169
if (mem_root->error_handler)
170
(*mem_root->error_handler)();
178
if (this->error_handler)
179
(*this->error_handler)();
173
mem_root->block_num++;
174
183
next->next= *prev;
175
184
next->size= get_size;
176
185
next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
180
189
point= (unsigned char*) ((char*) next+ (next->size-next->left));
181
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
182
if ((next->left-= length) < mem_root->min_malloc)
190
/** @todo next part may be unneeded due to this->first_block_usage counter*/
191
if ((next->left-= length) < this->min_malloc)
183
192
{ /* Full block */
184
193
*prev= next->next; /* Remove block from list */
185
next->next= mem_root->used;
186
mem_root->used= next;
187
mem_root->first_block_usage= 0;
194
next->next= this->used;
196
this->first_block_usage= 0;
189
return((void*) point);
194
Allocate many pointers at the same time.
197
ptr1, ptr2, etc all point into big allocated memory area.
202
ptr1, length1 Multiple arguments terminated by a NULL pointer
208
A pointer to the beginning of the allocated memory block
209
in case of success or NULL if out of memory.
212
void *memory::multi_alloc_root(memory::Root *root, ...)
205
* Allocate many pointers at the same time.
208
* The variable arguments are a list of alternating pointers and lengths,
209
* terminated by a null pointer:
210
* @li <tt>char ** pointer1</tt>
211
* @li <tt>uint length1</tt>
212
* @li <tt>char ** pointer2</tt>
213
* @li <tt>uint length2</tt>
217
* @c pointer1, @c pointer2 etc. all point into big allocated memory area
219
* @param root Memory root
222
* A pointer to the beginning of the allocated memory block in case of
223
* success or NULL if out of memory
225
void *memory::Root::multi_alloc_root(int unused, ...)
215
228
char **ptr, *start, *res;
216
229
size_t tot_length, length;
218
va_start(args, root);
231
(void)unused; // For some reason Sun Studio registers unused as not used.
232
va_start(args, unused);
220
234
while ((ptr= va_arg(args, char **)))
242
256
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
244
/* Mark all data in blocks free for reusage */
246
static inline void mark_blocks_free(memory::Root* root)
260
* Mark all data in blocks free for reusage
262
void memory::Root::mark_blocks_free()
248
264
memory::internal::UsedMemory *next;
249
265
memory::internal::UsedMemory **last;
251
267
/* iterate through (partially) free blocks, mark them free */
253
for (next= root->free; next; next= *(last= &next->next))
269
for (next= free; next; next= *(last= &next->next))
255
271
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
259
275
/* Combine the free and the used list */
260
*last= next=root->used;
262
278
/* now go through the used blocks and mark them free */
263
279
for (; next; next= next->next)
269
285
/* Now everything is set; Indicate that nothing is used anymore */
271
root->first_block_usage= 0;
287
first_block_usage= 0;
276
Deallocate everything used by memory::alloc_root or just move
277
used blocks to free list if called with MY_USED_TO_FREE
282
MyFlags Flags for what should be freed:
284
MARK_BLOCKS_FREED Don't free blocks, just mark them free
285
KEEP_PREALLOC If this is not set, then free also the
289
One can call this function either with root block initialised with
290
init_alloc_root() or with a zero:ed block.
291
It's also safe to call this multiple times with the same mem_root.
294
void memory::free_root(memory::Root *root, myf MyFlags)
292
* Deallocate everything used by memory::alloc_root or just move
293
* used blocks to free list if called with MY_USED_TO_FREE
296
* One can call this function either with root block initialised with
297
* init_alloc_root() or with a zero:ed block.
298
* It's also safe to call this multiple times with the same mem_root.
300
* @param root Memory root
301
* @param MyFlags Flags for what should be freed:
302
* @li MARK_BLOCKS_FREED Don't free blocks, just mark them free
303
* @li KEEP_PREALLOC If this is not set, then free also the
306
void memory::Root::free_root(myf MyFlags)
296
308
memory::internal::UsedMemory *next,*old;
298
310
if (MyFlags & memory::MARK_BLOCKS_FREE)
300
mark_blocks_free(root);
312
this->mark_blocks_free();
303
315
if (!(MyFlags & memory::KEEP_PREALLOC))
306
for (next=root->used; next ;)
318
for (next=this->used; next ;)
308
320
old=next; next= next->next ;
309
if (old != root->pre_alloc)
321
if (old != this->pre_alloc)
312
for (next=root->free ; next ;)
324
for (next=this->free ; next ;)
314
326
old=next; next= next->next;
315
if (old != root->pre_alloc)
318
root->used=root->free=0;
321
root->free=root->pre_alloc;
322
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
323
TRASH_MEM(root->pre_alloc);
327
root->first_block_usage= 0;
332
Find block that contains an object and set the pre_alloc to it
335
void memory::set_prealloc_root(memory::Root *root, char *ptr)
337
memory::internal::UsedMemory *next;
338
for (next=root->used; next ; next=next->next)
340
if ((char*) next <= ptr && (char*) next + next->size > ptr)
342
root->pre_alloc=next;
346
for (next=root->free ; next ; next=next->next)
348
if ((char*) next <= ptr && (char*) next + next->size > ptr)
350
root->pre_alloc=next;
357
char *memory::strdup_root(memory::Root *root, const char *str)
359
return strmake_root(root, str, strlen(str));
363
char *memory::strmake_root(memory::Root *root, const char *str, size_t len)
327
if (old != this->pre_alloc)
330
this->used=this->free=0;
333
this->free=this->pre_alloc;
334
this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
335
TRASH_MEM(this->pre_alloc);
339
this->first_block_usage= 0;
344
* Duplicate a null-terminated string into memory allocated from within the
347
char *memory::Root::strdup_root(const char *str)
349
return strmake_root(str, strlen(str));
354
* Copy the (not necessarily null-terminated) string into memory allocated
355
* from within the specified Root
358
* Note that the string is copied according to the length specified, so
359
* null-termination is ignored. The duplicated string will be null-terminated,
360
* even if the original string wasn't (one additional byte is allocated for
363
char *memory::Root::strmake_root(const char *str, size_t len)
366
if ((pos=(char *)memory::alloc_root(root,len+1)))
366
if ((pos= (char *)alloc_root(len+1)))
368
368
memcpy(pos,str,len);