51
51
* should be no less than memory::ROOT_MIN_BLOCK_SIZE)
54
void memory::init_alloc_root(memory::Root *mem_root, size_t block_size)
54
void memory::Root::init_alloc_root(size_t block_size_arg)
56
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
57
mem_root->min_malloc= 32;
58
mem_root->block_size= block_size - memory::ROOT_MIN_BLOCK_SIZE;
59
mem_root->error_handler= 0;
60
mem_root->block_num= 4; /* We shift this with >>2 */
61
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 */
79
77
* must be equal to or greater than block size,
80
78
* otherwise means 'no prealloc'.
82
void memory::reset_root_defaults(memory::Root *mem_root, size_t block_size,
83
size_t pre_alloc_size)
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.
101
96
if (mem->size == size)
103
98
/* We found a suitable block, no need to do anything else */
104
mem_root->pre_alloc= mem;
107
102
if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
109
104
/* remove block from the list and free it */
110
105
*prev= mem->next;
114
109
prev= &mem->next;
147
142
* @todo Would this be more suitable as a member function on the
150
void *memory::alloc_root(memory::Root *mem_root, size_t length)
145
void *memory::Root::alloc_root(size_t length)
152
size_t get_size, block_size;
153
147
unsigned char* point;
154
148
memory::internal::UsedMemory *next= NULL;
155
149
memory::internal::UsedMemory **prev;
156
assert(alloc_root_inited(mem_root));
150
assert(alloc_root_inited());
158
152
length= ALIGN_SIZE(length);
159
if ((*(prev= &mem_root->free)) != NULL)
153
if ((*(prev= &this->free)) != NULL)
161
155
if ((*prev)->left < length &&
162
mem_root->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
156
this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
163
157
(*prev)->left < MAX_BLOCK_TO_DROP)
166
160
*prev= next->next; /* Remove block from list */
167
next->next= mem_root->used;
168
mem_root->used= next;
169
mem_root->first_block_usage= 0;
161
next->next= this->used;
163
this->first_block_usage= 0;
171
165
for (next= *prev ; next && next->left < length ; next= next->next)
172
166
prev= &next->next;
175
169
{ /* Time to alloc new block */
176
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);
177
173
get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
178
get_size= max(get_size, block_size);
174
get_size= max(get_size, tmp_block_size);
180
176
if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
182
if (mem_root->error_handler)
183
(*mem_root->error_handler)();
178
if (this->error_handler)
179
(*this->error_handler)();
186
mem_root->block_num++;
187
183
next->next= *prev;
188
184
next->size= get_size;
189
185
next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
193
189
point= (unsigned char*) ((char*) next+ (next->size-next->left));
194
/** @todo next part may be unneeded due to mem_root->first_block_usage counter*/
195
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)
196
192
{ /* Full block */
197
193
*prev= next->next; /* Remove block from list */
198
next->next= mem_root->used;
199
mem_root->used= next;
200
mem_root->first_block_usage= 0;
194
next->next= this->used;
196
this->first_block_usage= 0;
263
259
* Mark all data in blocks free for reusage
265
static inline void mark_blocks_free(memory::Root* root)
261
void memory::Root::mark_blocks_free()
267
263
memory::internal::UsedMemory *next;
268
264
memory::internal::UsedMemory **last;
270
266
/* iterate through (partially) free blocks, mark them free */
272
for (next= root->free; next; next= *(last= &next->next))
268
for (next= free; next; next= *(last= &next->next))
274
270
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
278
274
/* Combine the free and the used list */
279
*last= next=root->used;
281
277
/* now go through the used blocks and mark them free */
282
278
for (; next; next= next->next)
306
302
* @li KEEP_PREALLOC If this is not set, then free also the
307
303
* preallocated block
309
void memory::free_root(memory::Root *root, myf MyFlags)
305
void memory::Root::free_root(myf MyFlags)
311
307
memory::internal::UsedMemory *next,*old;
313
309
if (MyFlags & memory::MARK_BLOCKS_FREE)
315
mark_blocks_free(root);
311
this->mark_blocks_free();
318
314
if (!(MyFlags & memory::KEEP_PREALLOC))
321
for (next=root->used; next ;)
317
for (next=this->used; next ;)
323
319
old=next; next= next->next ;
324
if (old != root->pre_alloc)
320
if (old != this->pre_alloc)
327
for (next=root->free ; next ;)
323
for (next=this->free ; next ;)
329
325
old=next; next= next->next;
330
if (old != root->pre_alloc)
333
root->used=root->free=0;
336
root->free=root->pre_alloc;
337
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
338
TRASH_MEM(root->pre_alloc);
342
root->first_block_usage= 0;
348
* Find block that contains an object and set the pre_alloc to it
350
void memory::set_prealloc_root(memory::Root *root, char *ptr)
352
memory::internal::UsedMemory *next;
353
for (next=root->used; next ; next=next->next)
355
if ((char*) next <= ptr && (char*) next + next->size > ptr)
357
root->pre_alloc=next;
361
for (next=root->free ; next ; next=next->next)
363
if ((char*) next <= ptr && (char*) next + next->size > ptr)
365
root->pre_alloc=next;
326
if (old != this->pre_alloc)
329
this->used=this->free=0;
332
this->free=this->pre_alloc;
333
this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
334
TRASH_MEM(this->pre_alloc);
338
this->first_block_usage= 0;
373
343
* Duplicate a null-terminated string into memory allocated from within the
376
char *memory::strdup_root(memory::Root *root, const char *str)
346
char *memory::Root::strdup_root(const char *str)
378
return strmake_root(root, str, strlen(str));
348
return strmake_root(str, strlen(str));
389
359
* even if the original string wasn't (one additional byte is allocated for
392
char *memory::strmake_root(memory::Root *root, const char *str, size_t len)
362
char *memory::Root::strmake_root(const char *str, size_t len)
395
if ((pos=(char *)memory::alloc_root(root,len+1)))
365
if ((pos= (char *)alloc_root(len+1)))
397
367
memcpy(pos,str,len);
409
379
* non-NULL pointer to a copy of the data if memory could be allocated, otherwise
412
void *memory::memdup_root(memory::Root *root, const void *str, size_t len)
382
void *memory::Root::memdup_root(const void *str, size_t len)
415
if ((pos=memory::alloc_root(root,len)))
386
if ((pos= this->alloc_root(len)))
416
387
memcpy(pos,str,len);